GameRoom.GameProcess.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MafiaTelegramBot.Controllers;
  7. using MafiaTelegramBot.CustomCollections.Extensions;
  8. using MafiaTelegramBot.DataBase.EntityDao;
  9. using MafiaTelegramBot.Game.GameRoles;
  10. using MafiaTelegramBot.Models;
  11. using MafiaTelegramBot.Resources;
  12. using Microsoft.EntityFrameworkCore;
  13. using Timer = System.Timers.Timer;
  14. namespace MafiaTelegramBot.Game.GameRooms
  15. {
  16. public partial class GameRoom
  17. {
  18. public void Start()
  19. {
  20. new Task(async () =>
  21. {
  22. IsRunning = true;
  23. await FirstNight();
  24. await FirstDay();
  25. await GameCycle();
  26. await EndOfGame();
  27. }).Start();
  28. }
  29. private async Task FirstDay()
  30. {
  31. IsDay = true;
  32. await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
  33. await PlayersCh.Send(strings.first_day_message);
  34. await Task.Run(async() =>
  35. {
  36. var turnsCount = _turnOrder.Count;
  37. Player firstPlayer = null;
  38. for (var i = 0; i < turnsCount; ++i)
  39. {
  40. var player = _turnOrder.Dequeue();
  41. if(!player.IsPlaying) continue;
  42. await PlayersCh.Send($"{strings.now_turn} ({player.TurnOrder}) {player.NickName}");
  43. if (TimerEnabled) await Bot.SendWithMarkdown2(player.ChatId, strings.you_turn_say);
  44. await player.CurrentRole.SpeakAction();
  45. if (firstPlayer != null && player.IsPlaying) _turnOrder.Enqueue(player);
  46. else firstPlayer = player;
  47. }
  48. _turnOrder.Enqueue(firstPlayer);
  49. });
  50. }
  51. private async Task FirstNight()
  52. {
  53. IsDay = false;
  54. await Task.Run(async() =>
  55. {
  56. //Start updating games stats
  57. var statsQuery = "SELECT * FROM mafia.statistics WHERE";
  58. foreach (var player in Players.Values)
  59. {
  60. statsQuery += $" id = {player.Id} AND role = '{player.GetRole().ToString()}' OR role = 'All' OR";
  61. }
  62. statsQuery = statsQuery.Substring(0, statsQuery.Length - 2);
  63. try
  64. {
  65. var statsList = UserDao.DataBase.Statistics.FromSqlRaw(statsQuery).ToArrayAsync().Result;
  66. foreach (var player in Players.Values)
  67. {
  68. var userProfile = UserDao.GetPlayerById(player.Id).Result;
  69. foreach (var row in statsList.Where(s => s.UserId == player.Id))
  70. row.Games++;
  71. if (userProfile.Statistics.Contains(Roles.All))
  72. {
  73. userProfile.Statistics[player.CurrentRole.RoleKey].Games++;
  74. userProfile.Statistics[Roles.All].Games++;
  75. }
  76. }
  77. UserDao.DataBase.Statistics.UpdateRange(statsList);
  78. }
  79. catch (Exception e)
  80. {
  81. await Console.Out.WriteLineAsync(e.Message);
  82. }
  83. //Stop updating games stats
  84. await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
  85. await PlayersCh.Send(strings.city_falls_asleep);
  86. var mafia = Players.Values.Where(player => player.GetRole() is Roles.Mafia).ToArray();
  87. var don = Players.Values.FirstOrDefault(player => player.GetRole() is Roles.Don);
  88. var dame = Players.Values.FirstOrDefault(player => player.GetRole() is Roles.Dame);
  89. var message = strings.your_teammates;
  90. if (don != null) message += $"\n({don.TurnOrder}) {don.NickName} - {roles.Don}";
  91. if (dame != null) message += $"\n({dame.TurnOrder}) {dame.NickName} - {roles.Dame}";
  92. message = mafia.Aggregate(message, (current, player) => current + $"\n({player.TurnOrder}) {player.NickName}");
  93. await _mafiaCh.Send(message);
  94. var resetEvent = new ManualResetEvent(false);
  95. var timer = new Timer
  96. {
  97. AutoReset = false,
  98. Interval = Constants.FIRST_NIGHT_INTERVAL
  99. };
  100. timer.Elapsed += (_, _) => resetEvent.Set();
  101. timer.Start();
  102. try
  103. {
  104. await UserDao.DataBase.SaveChangesAsync();
  105. }
  106. catch (Exception e)
  107. {
  108. await Console.Out.WriteLineAsync(e.Message);
  109. }
  110. foreach (var player in Players.Values)
  111. {
  112. if (player.GetRole() is not (Roles.Don or Roles.Mafia or Roles.Dame))
  113. player.CurrentRole.KnownRoles.Add(player.Id, player.GetRoleName());
  114. else
  115. foreach (var p in Players.Values
  116. .Where(p => p.GetRole() is Roles.Don or Roles.Mafia or Roles.Dame))
  117. player.CurrentRole.KnownRoles.Add(p.Id, p.GetRoleName());
  118. }
  119. resetEvent.WaitOne();
  120. });
  121. }
  122. private async Task GameCycle()
  123. {
  124. await Task.Run(async () =>
  125. {
  126. while (GameNotEnded())
  127. {
  128. await NightPhase();
  129. await SummingUpPhase();
  130. if (!GameNotEnded()) break;
  131. await DayPhase();
  132. await DispatchPhase();
  133. if (!GameNotEnded()) break;
  134. }
  135. });
  136. }
  137. private bool GameNotEnded()
  138. {
  139. var playersCount = Players.Values.Count(p => p.IsAlive);
  140. var mafiaCount = Players.Values.Count(p => p.IsAlive && p.GetRole() is Roles.Don or Roles.Mafia or Roles.Dame);
  141. if (PlayersRole.ContainsKey(Roles.Werewolf)
  142. && PlayersRole[Roles.Werewolf].Count == 1 && PlayersRole[Roles.Werewolf][0].IsAlive
  143. && ((WerewolfRole) PlayersRole[Roles.Werewolf][0].CurrentRole).IsMafia) mafiaCount++;
  144. var villagersCount = playersCount - mafiaCount;
  145. return villagersCount > mafiaCount && mafiaCount > 0;
  146. }
  147. private async Task DayPhase()
  148. {
  149. IsDay = true;
  150. var discussionTimer = new Timer {AutoReset = false, Interval = Constants.DISCUSSION_INTERVAL};
  151. var discussionEnded = new ManualResetEvent(false);
  152. foreach (var player in Players.Values.Where(player => !player.IsBlocked)) player.IsSpeaker = true;
  153. discussionTimer.Elapsed += async (_, _) =>
  154. {
  155. foreach (var player in Players.Values) player.IsSpeaker = false;
  156. await PlayersCh.Send(strings.day_discussion_ended);
  157. discussionEnded.Set();
  158. };
  159. await PlayersCh.Send(strings.disscution_time);
  160. discussionTimer.Start();
  161. discussionEnded.WaitOne();
  162. var turnsCount = _turnOrder.Count;
  163. Player toEndQueue = null;
  164. for (var i = 0; i < turnsCount; ++i)
  165. {
  166. var player = _turnOrder.Dequeue();
  167. if(!Players.ContainsKey(player.Id)) continue;
  168. if (!player.IsBlocked && player.IsAlive)
  169. {
  170. await PlayersCh.Send($"{strings.now_turn} ({player.TurnOrder}) {player.NickName}");
  171. if (TimerEnabled) await Bot.SendWithMarkdown2(player.ChatId, strings.you_turn_say);
  172. await player.CurrentRole.SpeakAction();
  173. if (Players.ContainsKey(player.Id)) await player.CurrentRole.VotingAction(VoteUpList.Count == 0);
  174. }
  175. if (toEndQueue != null) _turnOrder.Enqueue(player);
  176. else toEndQueue = player;
  177. }
  178. _turnOrder.Enqueue(toEndQueue);
  179. }
  180. private async Task NightPhase()
  181. {
  182. IsDay = false;
  183. await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
  184. await PlayersCh.Send(strings.city_falls_asleep);
  185. await Task.Run(async () =>
  186. {
  187. var resetEvent = new ManualResetEvent(false);
  188. var timer = new Timer{ Interval = Constants.NIGHT_ACTION_INTERVAL, AutoReset = false };
  189. foreach (var player in Players.Values)
  190. await player.CurrentRole.NightAction();
  191. timer.Elapsed += (_, _) => resetEvent.Set();
  192. var doctorId = PlayersRole[Roles.Doctor].Count == 1 ? PlayersRole[Roles.Doctor][0].Id : -1;
  193. foreach (var player in Players.Values)
  194. {
  195. if(doctorId != player.Id) player.CanBeHealed = true;
  196. player.CanBeBlockedNight = true;
  197. player.CanBeBlockedDay = true;
  198. player.IsBlocked = false;
  199. }
  200. timer.Start();
  201. resetEvent.WaitOne();
  202. });
  203. }
  204. public async Task SummingUpPhase()
  205. {
  206. await Task.Run(async () =>
  207. {
  208. var beforeKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
  209. var mafiaNotAgree = "";
  210. var votes = Players.Values.Where(p=> p.IsAlive && p.CurrentRole.MafiaTargetId != -1 && p.CurrentRole.MafiaTargetId != -2 && p.CurrentRole.MafiaTargetId != -4)
  211. .GroupBy(p => p.CurrentRole.MafiaTargetId)
  212. .Select(item => new {id = item.Key, count = item.Count()})
  213. .ToList();
  214. if (votes.Count == 0)
  215. {
  216. var allMafiaVotes = Players.Values.Where(p => p.CurrentRole.MafiaTargetId is -1 or -2 or -3).Distinct().ToList();
  217. if (allMafiaVotes.Count == 1)
  218. {
  219. mafiaNotAgree = allMafiaVotes[0].CurrentRole.MafiaTargetId switch
  220. {
  221. -1 => strings.mafia_not_kill_message,
  222. -3 => strings.mafia_decided_not_kill,
  223. _ => "",
  224. };
  225. }
  226. }
  227. else {
  228. var max = votes.Max(item => item.count);
  229. var maxObjects = votes.Where(item => item.count == max).ToList();
  230. if(maxObjects.Count == 1)
  231. {
  232. if (Players.ContainsKey(maxObjects[0].id))
  233. await Players[maxObjects[0].id].CurrentRole.Kill();
  234. }
  235. }
  236. foreach (var (role, players) in PlayersRole)
  237. {
  238. if (role is Roles.Mafia)
  239. foreach (var mafia in players) await mafia.CurrentRole.ApplyNightActionResult();
  240. else if (players.Count == 1) await players[0].CurrentRole.ApplyNightActionResult();
  241. }
  242. var afterKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
  243. var message = strings.city_wakes_up;
  244. if(afterKill.IsEquals(beforeKill)) message += strings.everyone_survived;
  245. else foreach (var (id, alive) in afterKill)
  246. if(beforeKill[id] != alive && Players.ContainsKey(id))
  247. {
  248. message += alive
  249. ? $"\n{Players[id].NickName} {strings.will_be_ressurected}"
  250. : $"\n{Players[id].NickName} {strings.will_be_killed}";
  251. if(!alive && Players[id].GetRole() is Roles.Don or Roles.Dame or Roles.Mafia
  252. && PlayersRole.ContainsKey(Roles.Werewolf) && PlayersRole[Roles.Werewolf].Count == 1)
  253. await ((WerewolfRole) PlayersRole[Roles.Werewolf][0].CurrentRole).TransformToMafia();
  254. await PlayersCh.SendTo(id, alive ? strings.you_will_be_ressurected : strings.you_will_be_killed);
  255. }
  256. message += '\n' + mafiaNotAgree;
  257. await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
  258. await PlayersCh.Send(message);
  259. });
  260. }
  261. private async Task DefencePhase(List<Player> contenders)
  262. {
  263. await Task.Run( async () =>
  264. {
  265. var contendersCopy = contenders.ToList();
  266. foreach (var contender in contendersCopy.Where(p => !p.IsBlocked))
  267. if (Players.ContainsKey(contender.Id)) await contender.CurrentRole.DefenceAction();
  268. var votersPlayers = Players.Values.Where(p => p.IsAlive && !p.IsBlocked).ToArray();
  269. foreach (var voter in votersPlayers)
  270. await voter.CurrentRole.VotingAction(contendersCopy.Where(p => Players.ContainsKey(p.Id)).ToList());
  271. var timer = new Timer {Interval = Constants.VOTE_KILL_INTERVAL, AutoReset = false};
  272. var resetEvent = new ManualResetEvent(false);
  273. timer.Elapsed += async(_, _) =>
  274. {
  275. foreach (var voter in votersPlayers.Where(p => !VoteKillList.ContainsKey(p.Id) && Players.ContainsKey(p.Id)))
  276. await voter.CurrentRole.RandomVoting();
  277. resetEvent.Set();
  278. };
  279. timer.Start();
  280. resetEvent.WaitOne();
  281. });
  282. }
  283. private async Task DispatchPhase()
  284. {
  285. await Task.Run(async () =>
  286. {
  287. switch (VoteUpList.Count)
  288. {
  289. case 0:
  290. await PlayersCh.Send(strings.nothing_up_to_vote);
  291. break;
  292. case 1:
  293. {
  294. await VoteUpList[0].CurrentRole.Dispatch();
  295. break;
  296. }
  297. default:
  298. {
  299. await DefencePhase(VoteUpList);
  300. VoteUpList = await CalculateCandidates();
  301. switch (VoteUpList.Count)
  302. {
  303. case 0:
  304. await PlayersCh.Send(strings.nothing_up_to_dispatch);
  305. break;
  306. case 1:
  307. await VoteUpList[0].CurrentRole.Dispatch();
  308. break;
  309. case > 1:
  310. await DefencePhase(VoteUpList);
  311. VoteUpList = await CalculateCandidates();
  312. switch (VoteUpList.Count)
  313. {
  314. case 0:
  315. await PlayersCh.Send(strings.nothing_up_to_dispatch);
  316. break;
  317. case 1:
  318. await VoteUpList[0].CurrentRole.Dispatch();
  319. break;
  320. default:
  321. await PlayersCh.Send(strings.villagers_could_not_decide);
  322. break;
  323. }
  324. break;
  325. }
  326. break;
  327. }
  328. }
  329. VoteUpList.Clear();
  330. VoteKillList.Clear();
  331. });
  332. }
  333. private async Task<List<Player>> CalculateCandidates()
  334. {
  335. var message = strings.results_of_voting;
  336. foreach (var (playerId, targetId) in VoteKillList)
  337. {
  338. message += Players.ContainsKey(playerId) && Players.ContainsKey(targetId)
  339. ? $"\n({Players[playerId].TurnOrder}) {Players[playerId].NickName} {strings.vote_to} " +
  340. $"({Players[targetId].TurnOrder}) {Players[targetId].NickName}" : "";
  341. }
  342. if (message == strings.results_of_voting) message = strings.no_one_voted;
  343. await PlayersCh.Send(message);
  344. var votes = VoteUpList.Where(p=>Players.ContainsKey(p.Id))
  345. .GroupBy(p => p.Id)
  346. .Select(item => new {id = item.Key, count = item.Count()})
  347. .ToList();
  348. List<Player> result = new();
  349. if (votes.Count == 0) return result;
  350. var max = votes.Max(item => item.count);
  351. var maxObjects = votes.Where(item => item.count == max);
  352. result.AddRange(from obj in maxObjects select Players[obj.id]);
  353. VoteKillList.Clear();
  354. VoteUpList.Clear();
  355. return result;
  356. }
  357. private async Task PutUpVote(long playerId, long targetId, int messageId = -1, bool toKill = false)
  358. {
  359. if (Players.ContainsKey(playerId))
  360. {
  361. if (targetId == 0)
  362. {
  363. if (!toKill) await PlayersCh.SendExcept(playerId, $"{Players[playerId].NickName} {strings.skip_vote}");
  364. await PlayersCh.EditTo(playerId, messageId, strings.you_skip_vote);
  365. }
  366. else
  367. {
  368. if (Players.ContainsKey(targetId))
  369. {
  370. if (!toKill)
  371. {
  372. if (VoteUpList.AddUnique(Players[targetId]))
  373. {
  374. if (playerId != targetId)
  375. {
  376. await PlayersCh.SendExcept(playerId, $"{Players[playerId].NickName} {strings.put_up_vote_to} {Players[targetId].NickName}");
  377. await PlayersCh.EditTo(playerId, messageId, $"{strings.you_vote_player} {Players[targetId].NickName}");
  378. }
  379. else
  380. {
  381. await PlayersCh.SendExcept(playerId, $"{Players[playerId].NickName} {strings.vote_to_self}");
  382. await PlayersCh.EditTo(playerId, messageId, strings.you_vote_to_self);
  383. }
  384. }
  385. }
  386. else if (VoteKillList.AddUniqueByKey(playerId, targetId))
  387. {
  388. VoteUpList.Add(Players[targetId]);
  389. if (messageId != -1)
  390. {
  391. if (playerId != targetId)
  392. await PlayersCh.EditTo(playerId, messageId, $"{strings.you_vote_to_kill} {Players[targetId].NickName}");
  393. else
  394. await PlayersCh.EditTo(playerId, messageId, strings.you_vote_to_kill_self);
  395. }
  396. }
  397. }
  398. }
  399. }
  400. else await PlayersCh.SendTo(playerId, strings.this_player_left_from_game);
  401. }
  402. private async Task EndOfGame()
  403. {
  404. await Task.Run(async () =>
  405. {
  406. var aliveMafia = Players.Values.Count(p => p.GetRole() is Roles.Don or Roles.Dame or Roles.Mafia && p.IsAlive);
  407. if (PlayersRole.ContainsKey(Roles.Werewolf)
  408. && PlayersRole[Roles.Werewolf].Count == 1 && PlayersRole[Roles.Werewolf][0].IsAlive
  409. && ((WerewolfRole) PlayersRole[Roles.Werewolf][0].CurrentRole).IsMafia) aliveMafia++;
  410. var additionalResult = "";
  411. foreach (var (_, value) in PlayersRole)
  412. {
  413. if (value.Count != 1) continue;
  414. var yellowResult = await value[0].CurrentRole.IsWon();
  415. if (yellowResult != "") additionalResult += "\n" + yellowResult;
  416. }
  417. if (aliveMafia == 0)
  418. {
  419. await PlayersCh.Send(strings.villagers_won + additionalResult, exceptDied: false);
  420. await PlayersCh.SendSticker(Stickers.Sticker["VillagerWins"]);
  421. }
  422. else
  423. {
  424. if (aliveMafia == 1)
  425. {
  426. var player = Players.Values.FirstOrDefault(p => p.IsAlive && p.GetRole() is Roles.Don or Roles.Dame or Roles.Mafia) ??
  427. PlayersRole[Roles.Werewolf][0];
  428. player.LawyerRoleAchievementEvent();
  429. }
  430. await PlayersCh.Send(strings.mafia_won + additionalResult, exceptDied: false);
  431. await PlayersCh.SendSticker(Stickers.Sticker["MafiaWins"]);
  432. }
  433. if (PlayersRole.ContainsKey(Roles.Fool) && PlayersRole[Roles.Fool].Count == 1)
  434. await PlayersRole[Roles.Fool][0].CurrentRole.IsWon();
  435. var rolesMessage = strings.in_this_game_roles;
  436. var players = Players.Values.ToList();
  437. var statsQueryStats = "SELECT * FROM mafia.statistics WHERE";
  438. var statsQueryOpenRoles = "SELECT * FROM mafia.opened_roles WHERE";
  439. foreach (var player in players)
  440. {
  441. rolesMessage += $"\n({player.TurnOrder}) {player.NickName} - {player.GetRoleName()}";
  442. statsQueryStats += $" id = {player.Id} AND role = '{player.GetRole().ToString()}' OR role = 'All' OR";
  443. statsQueryOpenRoles += $" id = {player.Id} OR";
  444. }
  445. await PlayersCh.Send(rolesMessage);
  446. //var updatingNotifications = await PlayersCh.SendWithReturn("Update data! Wait until it disappears");
  447. statsQueryStats = statsQueryStats.Substring(0, statsQueryStats.Length - 2);
  448. statsQueryOpenRoles = statsQueryOpenRoles.Substring(0, statsQueryOpenRoles.Length - 2);
  449. try
  450. {
  451. var statsList = UserDao.DataBase.Statistics.FromSqlRaw(statsQueryStats).ToArrayAsync().Result;
  452. var openRolesList = UserDao.DataBase.OpenedRoles.FromSqlRaw(statsQueryOpenRoles).ToArrayAsync().Result;
  453. void UpdateWins(Player player)
  454. {
  455. var userProfile = UserDao.GetPlayerById(player.Id).Result;
  456. foreach (var row in statsList.Where(s => s.UserId == player.Id))
  457. {
  458. row.Wins++;
  459. }
  460. var roles = openRolesList.Where(o => o.Id == player.Id).First();
  461. if (roles.Hooker == false)
  462. roles.Hooker = true;
  463. if (userProfile.Statistics.Contains(Roles.All))
  464. {
  465. userProfile.Statistics[player.CurrentRole.RoleKey].Wins++;
  466. userProfile.Statistics[Roles.All].Wins++;
  467. }
  468. }
  469. foreach (var player in players)
  470. {
  471. if (aliveMafia == 0)
  472. {
  473. if ((player.CurrentRole.ColorRole == 1 || !(player.CurrentRole.RoleKey == Roles.Lawyer)) && player.IsAlive)
  474. UpdateWins(player);
  475. }
  476. else
  477. {
  478. if ((player.CurrentRole.ColorRole == 2 || player.CurrentRole.RoleKey == Roles.Lawyer) && player.IsAlive)
  479. UpdateWins(player);
  480. }
  481. if (player.CurrentRole.ColorRole == 3)
  482. {
  483. if (player.CurrentRole.IsWon().Result != "")
  484. UpdateWins(player);
  485. }
  486. player.ResetState();
  487. if (player.CurrentRole.RoleKey == Roles.Cop)
  488. {
  489. if (((CopRole) PlayersRole[Roles.Cop][0].CurrentRole).CountRed ==
  490. ((CopRole) PlayersRole[Roles.Cop][0].CurrentRole).CountBlack) player.JournalistAchievementEvent();
  491. }
  492. }
  493. UserDao.DataBase.Statistics.UpdateRange(statsList);
  494. UserDao.DataBase.OpenedRoles.UpdateRange(openRolesList);
  495. await UserDao.DataBase.SaveChangesAsync();
  496. }
  497. catch (Exception e)
  498. {
  499. await Console.Out.WriteLineAsync(e.Message);
  500. }
  501. /*
  502. foreach (var message in updatingNotifications)
  503. {
  504. await Bot.Get().DeleteMessageAsync(message.Chat.Id,message.MessageId);
  505. }
  506. */
  507. IsRunning = false;
  508. IsDay = false;
  509. _turnOrder.Clear();
  510. Settings.Clear();
  511. foreach (var (_, list) in PlayersRole) list.Clear();
  512. if (!Players.ContainsKey(Owner.Id) || Players.Count == 0) new Task(async() =>
  513. await RoomController.DissolveRoom(RoomEncrypter.GetCode(RoomName))).Start();
  514. else
  515. {
  516. await Bot.SendWithMarkdown2(Owner.ChatId, strings.thanks_for_game, Keyboard.OwnerGameMenu);
  517. await PlayersCh.SendExcept(Owner.Id, strings.thanks_for_game, Keyboard.PlayerGameMenu);
  518. }
  519. if (Players.Count <= Constants.PLAYER_DISABLE_TIMER) StartTimer();
  520. });
  521. }
  522. }
  523. }