Esempio n. 1
0
        public bool Leave(IClient client)
        {
            if (client == null)
                throw new ArgumentNullException("client");

            if (client.Game != this)
            {
                Log.Default.WriteLine(LogLevels.Warning, "Cannot leave, {0} is not in game {1}", client.Name, Name);
                return false;
            }
            //
            bool removed = _clients.Remove(client);
            if (!removed)
                return false;

            // Clear vote kick target and timer
            if (_voteKickTarget == client)
            {
                _voteKickTarget = null;
                _voteKickTimer.Change(Timeout.Infinite, Timeout.Infinite);
            }

            // Save play state
            bool wasPlaying = client.State == ClientStates.Playing;

            // Change role, state and game
            client.Roles &= ~(ClientRoles.Player | ClientRoles.Spectator | ClientRoles.GameMaster); // remove Player+Spectator+GameMaster
            client.State = ClientStates.Connected;
            client.Game = null;
            client.LastVoteKickAnswer = null;

            // Search new game master
            bool gameMasterModified = false;
            IClient newMaster = Players.FirstOrDefault();
            if (newMaster != null && !newMaster.IsGameMaster)
            {
                gameMasterModified = true;
                newMaster.Roles |= ClientRoles.GameMaster;
            }

            // Inform client
            client.OnGameLeft(); // TODO: is this statement really usefull ???

            // Inform other clients in game
            foreach (IClient target in Clients.Where(c => c != client))
                target.OnClientGameLeft(client.Id);
            // Inform other clients about game master modification
            if (gameMasterModified)
            {
                foreach (IClient target in Clients.Where(c => c != client))
                    target.OnGameMasterModified(newMaster.Id);
                Log.Default.WriteLine(LogLevels.Info, "Game {0}: Game master modified: {1}", Name, newMaster.Id);
            }

            // If game was running and player was playing, check if only one player left
            if ((State == GameStates.GameStarted || State == GameStates.GamePaused) && wasPlaying)
            {
                int playingCount = Players.Count(p => p.State == ClientStates.Playing);
                if (playingCount == 0 || playingCount == 1)
                {
                    Log.Default.WriteLine(LogLevels.Info, "Game finished by forfeit no winner");
                    //
                    State = GameStates.GameFinished;
                    // Disable sudden death
                    _isSuddenDeathActive = false;
                    _suddenDeathTimer.Change(Timeout.Infinite, Timeout.Infinite);
                    //
                    GameStatistics statistics = PrepareGameStatistics();
                    // Send game finished (no winner)
                    foreach(IClient target in Clients.Where(c => c != client))
                        target.OnGameFinished(GameFinishedReasons.NotEnoughPlayers, statistics);
                    // Reset last player if any
                    if (playingCount == 1)
                    {
                        IClient last = Players.Single(p => p.State == ClientStates.Playing);
                        last.State = ClientStates.WaitInGame;
                    }
                    //
                    State = GameStates.WaitStartGame;
                }
            }

            Log.Default.WriteLine(LogLevels.Info, "Game {0}: client {1} left", Name, client.Name);
            return true;
        }