123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using MafiaTelegramBot.Controllers;
- using MafiaTelegramBot.CustomCollections.Extensions;
- using MafiaTelegramBot.Models;
- using MafiaTelegramBot.Resources;
- using Telegram.Bot.Types;
- using Timer = System.Timers.Timer;
- namespace MafiaTelegramBot.Game.GameRooms
- {
- public partial class GameRoom
- {
- public void Start()
- {
- new Task(async () =>
- {
- IsRunning = true;
- await FirstNight();
- await FirstDay();
- await GameCycle();
- await EndOfGame();
- }).Start();
- }
- private async Task FirstDay()
- {
- IsDay = true;
- await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
- await PlayersCh.Send(strings.first_day_message);
- await Task.Run(async() =>
- {
- var turnsCount = _turnOrder.Count;
- Player firstPlayer = null;
- for (var i = 0; i < turnsCount; ++i)
- {
- var player = _turnOrder.Dequeue();
- if(!player.IsPlaying) continue;
- await PlayersCh.Send($"{strings.now_turn} \\({player.TurnOrder}\\) {player.NickName}");
- await player.CurrentRole.SpeakAction();
- if (firstPlayer != null && player.IsPlaying) _turnOrder.Enqueue(player);
- else firstPlayer = player;
- }
- _turnOrder.Enqueue(firstPlayer);
- });
- }
- private async Task FirstNight()
- {
- IsDay = false;
- await Task.Run(async() =>
- {
- await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
- await PlayersCh.Send(strings.city_falls_asleep);
- var mafia = Players.Values.Where(player => player.GetRole() is Roles.Mafia).ToArray();
- var don = Players.Values.FirstOrDefault(player => player.GetRole() is Roles.Don);
- var message = strings.your_teammates;
- if (don != null) message += $"\n\\({don.TurnOrder}\\) {don.NickName} - {roles.Don}";
- message = mafia.Aggregate(message, (current, player) => current + $"\n\\({player.TurnOrder}\\) {player.NickName}");
- await _mafiaCh.Send(message);
- var resetEvent = new ManualResetEvent(false);
- var timer = new Timer
- {
- AutoReset = false,
- Interval = 10 * 1000
- };
- timer.Elapsed += (_, _) => resetEvent.Set();
- timer.Start();
- foreach (var player in Players.Values)
- {
- player.CurrentRole.KnownRoles.Add(player);
- if(player.GetRole() is Roles.Don or Roles.Mafia) player.CurrentRole.KnownRoles.AddRange(
- Players.Values.Where(p=> player.Id != p.Id && p.GetRole() is Roles.Mafia or Roles.Don)
- );
- }
- resetEvent.WaitOne();
- });
- }
- private async Task GameCycle()
- {
- await Task.Run(async () =>
- {
- var alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
- var aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
- var gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
- while (gameNotEnded)
- {
- await NightPhase();
- await SummingUpPhase();
- alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
- aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
- gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
- if (!gameNotEnded) break;
- await DayPhase();
- await DispatchPhase();
- alivePlayers = Players.Values.Where(p => p.IsAlive).ToList();
- aliveMafia = alivePlayers.Where(p => p.GetRole() is Roles.Don or Roles.Mafia).ToList();
- gameNotEnded = alivePlayers.Count > 2 * aliveMafia.Count && aliveMafia.Count > 0;
- if (!gameNotEnded) break;
- }
- });
- }
- private async Task DayPhase()
- {
- IsDay = true;
- var turnsCount = _turnOrder.Count;
- Player firstPlayer = null;
- for (var i = 0; i < turnsCount; ++i)
- {
- var player = _turnOrder.Dequeue();
- if(!player.IsPlaying || !player.IsAlive) continue;
- if (firstPlayer == null) player.IsFirst = true;
- await PlayersCh.Send($"{strings.now_turn} \\({player.TurnOrder}\\) {player.NickName}");
- await player.CurrentRole.SpeakAction();
- await player.CurrentRole.VotingAction();
- if (player.IsFirst) firstPlayer = player;
- else _turnOrder.Enqueue(player);
- }
- firstPlayer!.IsFirst = false;
- _turnOrder.Enqueue(firstPlayer);
- }
- private async Task NightPhase()
- {
- IsDay = false;
- await PlayersCh.SendSticker(Stickers.Sticker["Night"]);
- await PlayersCh.Send(strings.city_falls_asleep);
- await Task.Run(async () =>
- {
- var resetEvent = new ManualResetEvent(false);
- var timer = new Timer{ Interval = 60*1000, AutoReset = false };
- foreach (var player in Players.Values.Where(p=>p.IsAlive))
- {
- await player.CurrentRole.NightAction();
- }
- timer.Elapsed += (_, _) => resetEvent.Set();
- timer.Start();
- resetEvent.WaitOne();
- });
- }
- public async Task SummingUpPhase()
- {
- await Task.Run(async () =>
- {
- var beforeKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
- var mafiaNotAgree = "";
- foreach (var (role, players) in PlayersRole)
- {
- if (role is Roles.Mafia)
- {
- var votes = players.Where(p=> p.IsAlive)
- .GroupBy(p => p.CurrentRole.GetNightTarget())
- .Select(item => new {id = item.Key, count = item.Count()})
- .ToList();
- var max = votes.Max(item => item.count);
- var maxCount = votes.Count(item => item.count == max);
- if (maxCount != 1)
- {
- mafiaNotAgree = $"\n{strings.mafia_not_agree}";
- continue;
- }
- var selected = votes.First(item => item.count == max);
- if (selected.id == -1) continue;
- await Players[selected.id].CurrentRole.Kill();
- foreach (var mafia in players) await mafia.CurrentRole.ApplyNightActionResult();
- }
- else if (players.Count == 1)
- {
- var player = players[0];
- if (role != Roles.Doctor) player.CanBeHealed = true;
- await player.CurrentRole.ApplyNightActionResult();
- }
- }
- var afterKill = Players.Values.ToDictionary(p=>p.Id,p=>p.IsAlive);
- var message = strings.city_wakes_up;
- if(afterKill.IsEquals(beforeKill)) message += strings.everyone_survived;
- else foreach (var (id, alive) in afterKill)
- if(beforeKill[id] != alive) message += alive
- ? $"{Players[id].NickName} {strings.will_be_ressurected}"
- : $"{Players[id].NickName} {strings.will_be_killed}";
- message += mafiaNotAgree;
- await PlayersCh.SendSticker(Stickers.Sticker["Day"]);
- await PlayersCh.Send(message);
- });
- }
- private async Task<List<Player>> DefencePhase()
- {
- return await Task.Run( async () =>
- {
- var contendersForDispatch = _voteUpList.Where(p => p.VotedCount == _largeVote).ToList();
- foreach (var defender in _voteUpList) defender.VotedCount = 0;
- _voteUpList.Clear();
- _largeVote = 0;
- if (contendersForDispatch.Count == 1) return contendersForDispatch;
- foreach (var defender in contendersForDispatch) await defender.CurrentRole.DefenceAction();
- var votersPlayers = Players.Values
- .Where(p => p.IsAlive)
- .Except(contendersForDispatch)
- .ToList();
- Timer votingTimer = new() {Interval = 10 * 1000, AutoReset = false};
- var resetEvent = new ManualResetEvent(false);
- votingTimer.Elapsed += (_, _) => resetEvent.Set();
- List<Message> messagesToDelete = new();
- foreach (var player in votersPlayers)
- messagesToDelete.Add(await player.CurrentRole.SendVotingList(contendersForDispatch));
- votingTimer.Start();
- resetEvent.WaitOne();
- votingTimer.Stop();
- foreach (var message in messagesToDelete)
- await Bot.EditMessageAsync(message.Chat.Id, message.MessageId, strings.time_out);
- return _voteUpList.Where(p => p.VotedCount == _largeVote).ToList();
- });
- }
- private async Task DispatchPhase()
- {
- await Task.Run(async () =>
- {
- var contenders = await DefencePhase();
- if (contenders.Count > 1) contenders = await DefencePhase();
- if (contenders.Count > 1) await PlayersCh.Send(strings.villagers_could_not_decide);
- if (contenders.Count == 0) await PlayersCh.Send(strings.villagers_could_not_decide);
- else await contenders[0].CurrentRole.Dispatch();
- });
- }
- private async Task<Message> PutUpVote(long playerId, long targetId)
- {
- var player = Players[playerId];
- var target = Players[targetId];
- _voteUpList.AddUnique(target);
- if (playerId != targetId)
- {
- target.VotedCount++;
- if (target.VotedCount > _largeVote) _largeVote = target.VotedCount;
- await PlayersCh.SendExcept(player.ChatId, $"{player.NickName} {strings.vote_to} {target.NickName}");
- return await Bot.SendWithMarkdown2(player.ChatId, $"{strings.you_vote_player} {target.NickName}");
- }
- await PlayersCh.SendExcept(player.ChatId, $"{player.NickName} {strings.vote_to_self}");
- return await Bot.SendWithMarkdown2(player.ChatId, strings.you_vote_to_self);
- }
- private async Task EndOfGame()
- {
- await Task.Run(async () =>
- {
- var aliveMafia = Players.Values.Where(p => p.GetRole() is Roles.Don or Roles.Mafia && p.IsAlive).ToList();
- if (aliveMafia.Count == 0)
- {
- await PlayersCh.Send(strings.villagers_won, exceptDied: false);
- await PlayersCh.SendSticker(Stickers.Sticker["VillagerWins"]);
- }
- else
- {
- await PlayersCh.Send(strings.mafia_won, exceptDied: false);
- await PlayersCh.SendSticker(Stickers.Sticker["MafiaWins"]);
- }
- var rolesMessage = strings.in_this_game_roles;
- var sortedPLayers = Players.Values.ToList();
- sortedPLayers.Sort((x, y) => x.TurnOrder - y.TurnOrder);
- foreach (var player in sortedPLayers)
- {
- rolesMessage += $"\n\\({player.TurnOrder}\\) {player.NickName} - {player.GetRoleName()}";
- player.ResetState();
- }
- await PlayersCh.Send(rolesMessage);
- IsRunning = false;
- IsDay = false;
- _turnOrder.Clear();
- Settings.Clear();
- foreach (var (_, list) in PlayersRole) list.Clear();
- if (!Players.ContainsKey(Owner.Id) || Players.Count == 0) new Task(async() =>
- await RoomController.DissolveRoom(RoomEncrypter.GetCode(RoomName))).Start();
- else
- {
- await Bot.SendWithMarkdown2(Owner.ChatId, strings.thanks_for_game, Keyboard.OwnerGameMenu);
- await PlayersCh.SendExcept(Owner.Id, strings.thanks_for_game, Keyboard.PlayerGameMenu);
- }
- });
- }
- }
- }
|