426 lines
15 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |