GameRoom.GameProcess.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using MafiaTelegramBot.Controllers;
  6. using MafiaTelegramBot.CustomCollections.Extensions;
  7. using MafiaTelegramBot.Models;
  8. using MafiaTelegramBot.Resources;
  9. using Telegram.Bot.Types;
  10. using Timer = System.Timers.Timer;
  11. namespace MafiaTelegramBot.Game.GameRooms
  12. {
  13. public partial class GameRoom
  14. {
  15. public void Start()
  16. {
  17. new Task(async () =>
  18. {
  19. IsRunning = true;
  20. await FirstNight();
  21. await FirstDay();
  22. await GameCycle();
  23. await EndOfGame();
  24. }).Start();
  25. }
  26. private async Task FirstDay()
  27. {
  28. IsDay = true;
  29. await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
  30. await PlayersCh.Send(strings.first_day_message);
  31. await Task.Run(async() =>
  32. {
  33. var turnsCount = _turnOrder.Count;
  34. Player firstPlayer = null;
  35. for (var i = 0; i < turnsCount; ++i)
  36. {
  37. var player = _turnOrder.Dequeue();
  38. if(!player.IsPlaying) continue;
  39. await PlayersCh.Send($"{strings.now_turn} \\({player.TurnOrder}\\) {player.NickName}");
  40. await player.CurrentRole.SpeakAction();
  41. if (firstPlayer != null && player.IsPlaying) _turnOrder.Enqueue(player);
  42. else firstPlayer = player;
  43. }
  44. _turnOrder.Enqueue(firstPlayer);
  45. });
  46. }
  47. private async Task FirstNight()
  48. {
  49. IsDay = false;
  50. await Task.Run(async() =>
  51. {
  52. await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
  53. await PlayersCh.Send(strings.city_falls_asleep);
  54. var mafia = Players.Values.Where(player => player.GetRole() is Roles.Mafia).ToArray();
  55. var don = Players.Values.FirstOrDefault(player => player.GetRole() is Roles.Don);
  56. var message = strings.your_teammates;
  57. if (don != null) message += $"\n\\({don.TurnOrder}\\) {don.NickName} - {roles.Don}";
  58. message = mafia.Aggregate(message, (current, player) => current + $"\n\\({player.TurnOrder}\\) {player.NickName}");
  59. await _mafiaCh.Send(message);
  60. var resetEvent = new ManualResetEvent(false);
  61. var timer = new Timer
  62. {
  63. AutoReset = false,
  64. Interval = 10 * 1000
  65. };
  66. timer.Elapsed += (_, _) => resetEvent.Set();
  67. timer.Start();
  68. foreach (var player in Players.Values)
  69. {
  70. player.CurrentRole.KnownRoles.Add(player);
  71. if(player.GetRole() is Roles.Don or Roles.Mafia) player.CurrentRole.KnownRoles.AddRange(
  72. Players.Values.Where(p=> player.Id != p.Id && p.GetRole() is Roles.Mafia or Roles.Don)
  73. );
  74. }
  75. resetEvent.WaitOne();
  76. });
  77. }
  78. private async Task GameCycle()
  79. {
  80. await Task.Run(async () =>
  81. {
  82. var alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
  83. var aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
  84. var gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
  85. while (gameNotEnded)
  86. {
  87. await NightPhase();
  88. await SummingUpPhase();
  89. alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
  90. aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
  91. gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
  92. if (!gameNotEnded) break;
  93. await DayPhase();
  94. await DispatchPhase();
  95. alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
  96. aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
  97. gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
  98. if (!gameNotEnded) break;
  99. }
  100. });
  101. }
  102. private async Task DayPhase()
  103. {
  104. IsDay = true;
  105. var turnsCount = _turnOrder.Count;
  106. Player firstPlayer = null;
  107. for (var i = 0; i < turnsCount; ++i)
  108. {
  109. var player = _turnOrder.Dequeue();
  110. if(!player.IsPlaying || !player.IsAlive) continue;
  111. if (firstPlayer == null) player.IsFirst = true;
  112. await PlayersCh.Send($"{strings.now_turn} \\({player.TurnOrder}\\) {player.NickName}");
  113. await player.CurrentRole.SpeakAction();
  114. await player.CurrentRole.VotingAction();
  115. if (player.IsFirst) firstPlayer = player;
  116. else _turnOrder.Enqueue(player);
  117. }
  118. firstPlayer!.IsFirst = false;
  119. _turnOrder.Enqueue(firstPlayer);
  120. }
  121. private async Task NightPhase()
  122. {
  123. IsDay = false;
  124. await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
  125. await PlayersCh.Send(strings.city_falls_asleep);
  126. await Task.Run(async () =>
  127. {
  128. var resetEvent = new ManualResetEvent(false);
  129. var timer = new Timer{ Interval = 60*1000, AutoReset = false };
  130. foreach (var player in Players.Values.Where(p=>p.IsAlive))
  131. {
  132. await player.CurrentRole.NightAction();
  133. }
  134. timer.Elapsed += (_, _) => resetEvent.Set();
  135. timer.Start();
  136. resetEvent.WaitOne();
  137. });
  138. }
  139. public async Task SummingUpPhase()
  140. {
  141. await Task.Run(async () =>
  142. {
  143. var beforeKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
  144. var mafiaNotAgree = "";
  145. foreach (var (role, players) in PlayersRole)
  146. {
  147. if (role is Roles.Mafia)
  148. {
  149. var votes = players.Where(p=> p.IsAlive)
  150. .GroupBy(p => p.CurrentRole.GetNightTarget())
  151. .Select(item => new {id = item.Key, count = item.Count()})
  152. .ToList();
  153. var max = votes.Max(item => item.count);
  154. var maxCount = votes.Count(item => item.count == max);
  155. if (maxCount != 1)
  156. {
  157. mafiaNotAgree = $"\n{strings.mafia_not_agree}";
  158. continue;
  159. }
  160. var selected = votes.First(item => item.count == max);
  161. if (selected.id == -1) continue;
  162. await Players[selected.id].CurrentRole.Kill();
  163. foreach (var mafia in players) await mafia.CurrentRole.ApplyNightActionResult();
  164. }
  165. else if (players.Count == 1)
  166. {
  167. var player = players[0];
  168. if (role != Roles.Doctor) player.CanBeHealed = true;
  169. await player.CurrentRole.ApplyNightActionResult();
  170. }
  171. }
  172. var afterKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
  173. var message = strings.city_wakes_up;
  174. if(afterKill.IsEquals(beforeKill)) message += strings.everyone_survived;
  175. else foreach (var (id, alive) in afterKill)
  176. if(beforeKill[id] != alive) message += alive
  177. ? $"{Players[id].NickName} {strings.will_be_ressurected}"
  178. : $"{Players[id].NickName} {strings.will_be_killed}";
  179. message += mafiaNotAgree;
  180. await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
  181. await PlayersCh.Send(message);
  182. });
  183. }
  184. private async Task<List<Player>> DefencePhase()
  185. {
  186. return await Task.Run( async () =>
  187. {
  188. var contendersForDispatch = _voteUpList.Where(p => p.VotedCount == _largeVote).ToList();
  189. foreach (var defender in _voteUpList) defender.VotedCount = 0;
  190. _voteUpList.Clear();
  191. _largeVote = 0;
  192. if (contendersForDispatch.Count == 1) return contendersForDispatch;
  193. foreach (var defender in contendersForDispatch) await defender.CurrentRole.DefenceAction();
  194. var votersPlayers = Players.Values
  195. .Where(p => p.IsAlive)
  196. .Except(contendersForDispatch)
  197. .ToList();
  198. Timer votingTimer = new() {Interval = 10 * 1000, AutoReset = false};
  199. var resetEvent = new ManualResetEvent(false);
  200. votingTimer.Elapsed += (_, _) => resetEvent.Set();
  201. List<Message> messagesToDelete = new();
  202. foreach (var player in votersPlayers)
  203. messagesToDelete.Add(await player.CurrentRole.SendVotingList(contendersForDispatch));
  204. votingTimer.Start();
  205. resetEvent.WaitOne();
  206. votingTimer.Stop();
  207. foreach (var message in messagesToDelete)
  208. await Bot.EditMessageAsync(message.Chat.Id, message.MessageId, strings.time_out);
  209. return _voteUpList.Where(p => p.VotedCount == _largeVote).ToList();
  210. });
  211. }
  212. private async Task DispatchPhase()
  213. {
  214. await Task.Run(async () =>
  215. {
  216. var contenders = await DefencePhase();
  217. if (contenders.Count > 1) contenders = await DefencePhase();
  218. if (contenders.Count > 1) await PlayersCh.Send(strings.villagers_could_not_decide);
  219. if (contenders.Count == 0) await PlayersCh.Send(strings.villagers_could_not_decide);
  220. else await contenders[0].CurrentRole.Dispatch();
  221. });
  222. }
  223. private async Task<Message> PutUpVote(long playerId, long targetId)
  224. {
  225. var player = Players[playerId];
  226. var target = Players[targetId];
  227. _voteUpList.AddUnique(target);
  228. if (playerId != targetId)
  229. {
  230. target.VotedCount++;
  231. if (target.VotedCount > _largeVote) _largeVote = target.VotedCount;
  232. await PlayersCh.SendExcept(player.ChatId, $"{player.NickName} {strings.vote_to} {target.NickName}");
  233. return await Bot.SendWithMarkdown2(player.ChatId, $"{strings.you_vote_player} {target.NickName}");
  234. }
  235. await PlayersCh.SendExcept(player.ChatId, $"{player.NickName} {strings.vote_to_self}");
  236. return await Bot.SendWithMarkdown2(player.ChatId, strings.you_vote_to_self);
  237. }
  238. private async Task EndOfGame()
  239. {
  240. await Task.Run(async () =>
  241. {
  242. var aliveMafia = Players.Values.Where(p => p.GetRole() is Roles.Don or Roles.Mafia && p.IsAlive).ToList();
  243. if (aliveMafia.Count == 0)
  244. {
  245. await PlayersCh.Send(strings.villagers_won, exceptDied: false);
  246. await PlayersCh.SendSticker(Stickers.Sticker["VillagerWins"]);
  247. }
  248. else
  249. {
  250. await PlayersCh.Send(strings.mafia_won, exceptDied: false);
  251. await PlayersCh.SendSticker(Stickers.Sticker["MafiaWins"]);
  252. }
  253. var rolesMessage = strings.in_this_game_roles;
  254. var sortedPLayers = Players.Values.ToList();
  255. sortedPLayers.Sort((x, y) => x.TurnOrder - y.TurnOrder);
  256. foreach (var player in sortedPLayers)
  257. {
  258. rolesMessage += $"\n\\({player.TurnOrder}\\) {player.NickName} - {player.GetRoleName()}";
  259. player.ResetState();
  260. }
  261. await PlayersCh.Send(rolesMessage);
  262. IsRunning = false;
  263. IsDay = false;
  264. _turnOrder.Clear();
  265. Settings.Clear();
  266. foreach (var (_, list) in PlayersRole) list.Clear();
  267. if (!Players.ContainsKey(Owner.Id) || Players.Count == 0) new Task(async() =>
  268. await RoomController.DissolveRoom(RoomEncrypter.GetCode(RoomName))).Start();
  269. else
  270. {
  271. await Bot.SendWithMarkdown2(Owner.ChatId, strings.thanks_for_game, Keyboard.OwnerGameMenu);
  272. await PlayersCh.SendExcept(Owner.Id, strings.thanks_for_game, Keyboard.PlayerGameMenu);
  273. }
  274. });
  275. }
  276. }
  277. }