2021-04-28 23:50:55 +03:00

426 lines
15 KiB
C#

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<PlayerSocketWorker> _players = new();
private readonly List<PlayerRole> _playerRolesAtStart = new();
private bool _isStarted;
private GameState _gameState = GameState.NotStarted;
private readonly List<PlayerSocketWorker> _votesRemain = new();
private readonly List<PlayerSocketWorker> _mafia = new();
private readonly Dictionary<int, int> _mafiaVotes = new();
private readonly Dictionary<int, int> _dayVote = new();
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<Player> 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);
}
var 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;
}
}
}
}