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; }