using System; using System.Collections.Generic; using System.Linq; using System.Threading; using MafiaCommon.Packets; using MafiaCommon; namespace MafiaServer { public class Game { private readonly List _players = new List(); private readonly List _playerRolesAtStart = new List(); private bool _isStarted; private GameState _gameState = GameState.NotStarted; private readonly List _votesRemain = new List(); private readonly List _mafia = new List(); private readonly Dictionary _mafiaVotes = new Dictionary(); private readonly Dictionary _dayVote = new Dictionary(); private Timer _voteStartTimer; public void ConnectPlayer(PlayerSocketWorker player) { if (_players.Count >= Settings.Config().MaxPlayers) { player.SendPacket(new DisconnectPacket("Game Full!")); player.Disconnect(); } else { if (_isStarted) { player.SendPacket(new DisconnectPacket("Game already started!")); player.Disconnect(); } else { foreach (var othPlayer in _players) { othPlayer.SendPacket(new PlayerConnectedPacket(player.PlayerName, _players.Count + 1, Settings.Config().MaxPlayers)); } _players.Add(player); player.Id = _players.LastIndexOf(player); player.OnDisconnectByErrorEvent += OnDisconnectByError; player.OnPlayerSendMessageEvent += PlayerOnOnPlayerSendMessageEvent; player.OnDisconnectEvent += PlayerOnOnDisconnectEvent; player.OnPlayerVoteEvent += PlayerOnOnPlayerVoteEvent; player.SendPacket(new WelcomePacket(Settings.Config().ServerName, _players.Count, Settings.Config().MaxPlayers)); } } } private List GetPlayersRoles() { return (from player in _players where player.Role != Role.Died select new Player(player.Id, player.PlayerName)).ToList(); } private bool WorkDeath(PlayerSocketWorker player) { switch (player.Role) { case Role.Don: _mafia.Remove(player); if (_mafia.Count == 0) { foreach (var p in _players) { p.SendPacket(new EndGamePacket(true, _playerRolesAtStart)); } _isStarted = false; _gameState = GameState.NotStarted; return false; } else { _mafia[0].Role = Role.Don; if (_gameState == GameState.VotingNight) { _mafia[0].SendPacket(new MessageReceivePacket(ChatType.Active, true, "System", "Дон покинул игру, ты новый дон!")); } _mafia.RemoveAt(0); } break; } player.Role = Role.Died; var mafias = _mafia.Count + 1; var aliveLefts = _players.Count(pl => pl.Role != Role.Died && pl.Role != Role.Don && pl.Role != Role.Mafia); if (mafias < aliveLefts) return true; foreach (var p in _players) { p.SendPacket(new EndGamePacket(p.Role == Role.Mafia || p.Role == Role.Don, _playerRolesAtStart)); } _isStarted = false; _gameState = GameState.NotStarted; return false; } private void PlayerOnOnPlayerVoteEvent(PlayerSocketWorker sender, int id) { if (_votesRemain.Contains(sender)) { var voteFor = _players.FindPlayerById(id); switch (_gameState) { case GameState.VotingNight: switch (sender.Role) { case Role.Don: _mafiaVotes.AddEmpty(id, 2); _votesRemain.Remove(sender); foreach (var player in _players.Where(player => player.Role == Role.Mafia || player.Role == Role.Don)) { player.SendPacket(new MessageReceivePacket(ChatType.Active, true, "System", sender.PlayerName + " проголосовал за " + voteFor.PlayerName)); } break; case Role.Mafia: _mafiaVotes.AddEmpty(id, 1); _votesRemain.Remove(sender); foreach (var player in _players.Where(player => player.Role == Role.Mafia || player.Role == Role.Don)) { player.SendPacket(new MessageReceivePacket(ChatType.Active, true, "System", sender.PlayerName + " проголосовал за " + voteFor.PlayerName)); } break; } break; case GameState.VotingDay: _dayVote.AddEmpty(id, 1); _votesRemain.Remove(sender); foreach (var player in _players) { player.SendPacket(new MessageReceivePacket(ChatType.Day, true, "System", sender.PlayerName + " проголосовал за " + voteFor.PlayerName)); } break; } } if (_votesRemain.Count != 0) return; switch (_gameState) { case GameState.VotingNight: var selId = 0; var selVotes = 0; foreach (var (key, value) in _mafiaVotes.Where(votes => votes.Value > selVotes)) { selId = key; selVotes = value; } var killed = _players.FindPlayerById(selId); if (WorkDeath(killed)) { _gameState = GameState.Day; foreach (var player in _players) { player.SendPacket(new GameStageChangedPacket(GameState.Day, player.Role, GetPlayersRoles())); player.SendPacket(new MessageReceivePacket(ChatType.Day, true, "System", killed.PlayerName + " был убит!")); } _voteStartTimer = new Timer(StartDayVote, null, 60000, 60000); } break; case GameState.VotingDay: selId = 0; selVotes = 0; foreach (var (key, value) in _dayVote.Where(votes => votes.Value > selVotes)) { selId = key; selVotes = value; } killed = _players.FindPlayerById(selId); if (WorkDeath(killed)) { _gameState = GameState.VotingNight; FillNightVotes(); foreach (var player in _players) { player.SendPacket(new GameStageChangedPacket(GameState.VotingNight, player.Role, GetPlayersRoles())); player.SendPacket(new MessageReceivePacket(ChatType.Day, true, "System", killed.PlayerName + " был повешен!")); } } break; } } private void StartDayVote(object obj) { _voteStartTimer.Dispose(); _gameState = GameState.VotingDay; _votesRemain.Clear(); foreach (var player in _players.Where(player => player.Role != Role.Died)) { _votesRemain.Add(player); } List players = GetPlayersRoles(); foreach (var player in _players) { player.SendPacket(new GameStageChangedPacket(GameState.VotingDay, player.Role, players)); player.SendPacket(new MessageReceivePacket(ChatType.Day, true, "System", "Начинаем голосование!")); } } private void FillNightVotes() { foreach (var player in _players) { switch (player.Role) { case Role.Don: case Role.Mafia: _votesRemain.Add(player); break; } } } private void PlayerOnOnDisconnectEvent(PlayerSocketWorker sender) { _players.Remove(sender); foreach (var player in _players) { player.SendPacket(new PlayerDisconnectedPacket(true, sender.Id, _players.Count, Settings.Config().MaxPlayers)); } if (_gameState != GameState.NotStarted) { WorkDeath(sender); } } public void Start() { if (_isStarted) { return; } if (_players.Count < 3) { Console.WriteLine("Not Enough Players"); return; } foreach (var player in _players) { player.Role = Role.Citizen; } _playerRolesAtStart.Clear(); _votesRemain.Clear(); _mafiaVotes.Clear(); _dayVote.Clear(); var random = new Random(); var empty = _players.ToArray(); random.Shuffle(empty); var mafiasNeed = empty.Length / 3; Console.WriteLine("Debug: needs counted"); while (mafiasNeed != 0) { for (var i = 0; i < empty.Length; i++) { switch (random.Next(2)) { case 0: //Мирный break; case 1: //Мафия if (mafiasNeed > 0) { empty[i].Role = Role.Mafia; mafiasNeed--; _mafia.Add(empty[i]); empty = empty.RemoveFromArray(i); } break; } } } Console.WriteLine("Debug: randomized"); var don = _mafia[0]; don.Role = Role.Don; _mafia.RemoveAt(0); var players = GetPlayersRoles(); don.SendPacket(new GameStartPacket(Role.Don, players)); _votesRemain.Add(don); foreach (var player in empty) { player.SendPacket(new GameStartPacket(Role.Citizen, players)); } foreach (var player in _mafia) { player.SendPacket(new GameStartPacket(Role.Mafia, players)); _votesRemain.Add(player); } foreach (var player in _players) { _playerRolesAtStart.Add(new PlayerRole(player.PlayerName, player.Role)); } Console.WriteLine("Debug: packets sent"); _isStarted = true; _gameState = GameState.VotingNight; } private void OnDisconnectByError(PlayerSocketWorker sender) { _players.Remove(sender); foreach (var player in _players) { player.SendPacket(new PlayerDisconnectedPacket(true, sender.Id, _players.Count, Settings.Config().MaxPlayers)); } if (_gameState != GameState.NotStarted) { WorkDeath(sender); } } private void PlayerOnOnPlayerSendMessageEvent(PlayerSocketWorker sender, ChatType chatType, string text) { switch (chatType) { case ChatType.Queue: if (!_isStarted) { foreach (var player in _players) { player.SendPacket(new MessageReceivePacket(ChatType.Queue, false, sender.PlayerName, text)); } } break; case ChatType.Active: if (_isStarted) { switch (sender.Role) { case Role.Mafia: case Role.Don: foreach (var player in _players.Where(player => player.Role == Role.Mafia || player.Role == Role.Don)) { player.SendPacket(new MessageReceivePacket(ChatType.Active, false, sender.PlayerName, text)); } break; } } break; case ChatType.Day: if (_isStarted) { if (sender.Role == Role.Died) { sender.SendPacket(new MessageReceivePacket(ChatType.Day, true, "system", "Мёртвое говорить не может")); } else { foreach (var player in _players) { player.SendPacket( new MessageReceivePacket(ChatType.Day, false, sender.PlayerName, text)); } } } break; default: Console.WriteLine("User sending in bad chat"); break; } } } }