diff --git a/PugSharp.Config/TeamMode.cs b/PugSharp.Config/TeamMode.cs index df933a46..a8da99f4 100644 --- a/PugSharp.Config/TeamMode.cs +++ b/PugSharp.Config/TeamMode.cs @@ -7,4 +7,7 @@ public enum TeamMode // Scramble Teams after all players are joined Scramble, + + // Player Selects which Team to join + PlayerSelect } diff --git a/PugSharp.Match/Match.cs b/PugSharp.Match/Match.cs index 4ae82a42..3095c8f6 100644 --- a/PugSharp.Match/Match.cs +++ b/PugSharp.Match/Match.cs @@ -124,6 +124,7 @@ private void InitializeStateMachine() _MatchStateMachine.Configure(MatchState.DefineTeams) .Permit(MatchCommand.TeamsDefined, MatchState.MapVote) .OnEntry(ContinueIfDefault) + .OnEntry(ContinueIfPlayerSelect) .OnEntry(ScrambleTeams); _MatchStateMachine.Configure(MatchState.MapVote) @@ -215,6 +216,14 @@ private void ContinueIfDefault() } } + private void ContinueIfPlayerSelect() + { + if (MatchInfo.Config.TeamMode == Config.TeamMode.PlayerSelect) + { + TryFireState(MatchCommand.TeamsDefined); + } + } + private void StartWarmup() { _CsServer.LoadAndExecuteConfig("warmup.cfg"); @@ -649,7 +658,7 @@ private void VoteTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) private void ReadyReminderTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) { - if (!_ReadyReminderTimer.Enabled) + if (MatchInfo.Config.TeamMode != Config.TeamMode.PlayerSelect && !_ReadyReminderTimer.Enabled) { return; } @@ -658,6 +667,25 @@ private void ReadyReminderTimer_Elapsed(object? sender, System.Timers.ElapsedEve { try { + if (MatchInfo.Config.TeamMode == Config.TeamMode.PlayerSelect) + { + _Logger.LogInformation("TeamReminder Elapsed"); + foreach (var player in AllMatchPlayers) + { + var matchTeam = GetMatchTeam(player.Player.Team); + if (player.Player.Team == Team.Terrorist || player.Player.Team == Team.CounterTerrorist) + { + var teamMessage = _TextHelper.GetText(nameof(Resources.PugSharp_Match_TeamReminder), matchTeam?.TeamConfig.Name); + player.Player.PrintToChat(teamMessage); + } + } + } + + if (!_ReadyReminderTimer.Enabled) + { + return; + } + _Logger.LogInformation("ReadyReminder Elapsed"); var readyPlayerIds = AllMatchPlayers.Where(p => p.IsReady).Select(x => x.Player.SteamID).ToList(); var notReadyPlayers = _CsServer.LoadAllPlayers().Where(p => !readyPlayerIds.Contains(p.SteamID)); @@ -937,8 +965,61 @@ private MatchPlayer GetMatchPlayer(ulong steamID) return AllMatchPlayers.First(x => x.Player.SteamID == steamID); } + public bool PlayerIsReady(ulong steamID) + { + var matchPlayer = AllMatchPlayers.FirstOrDefault(x => x.Player.SteamID == steamID); + return matchPlayer != null && matchPlayer.IsReady; + } + #region Match Functions + private bool TryAddPlayerToCurrentTeam(IPlayer player) + { + var matchPlayer = MatchInfo.MatchTeam1.Players.Any(x => x.Player.SteamID == player.SteamID) || MatchInfo.MatchTeam2.Players.Any(x => x.Player.SteamID == player.SteamID) ? GetMatchPlayer(player.SteamID) : null; + if (matchPlayer == null) { + matchPlayer = new MatchPlayer(player); + } + else { + // Remove the player from the match + MatchInfo.MatchTeam1.Players.Remove(matchPlayer); + MatchInfo.MatchTeam2.Players.Remove(matchPlayer); + } + + // Add them back to the match + bool? isTeam1 = null; + if (MatchInfo.MatchTeam1.CurrentTeamSite == Team.None && MatchInfo.MatchTeam2.CurrentTeamSite == Team.None) + { + isTeam1 = player.Team == Team.Terrorist; + } + else if (MatchInfo.MatchTeam1.CurrentTeamSite != Team.None) + { + isTeam1 = MatchInfo.MatchTeam1.CurrentTeamSite == player.Team; + } + else if (MatchInfo.MatchTeam2.CurrentTeamSite != Team.None) + { + isTeam1 = MatchInfo.MatchTeam2.CurrentTeamSite != player.Team; + } + + if (isTeam1 == null) + { + _Logger.LogInformation("Could not add player to match", player.SteamID); + return false; + } + else if (isTeam1.HasValue && isTeam1.Value) + { + MatchInfo.MatchTeam1.Players.Add(matchPlayer); + } + else + { + MatchInfo.MatchTeam2.Players.Add(matchPlayer); + } + + // Console.WriteLine("Team 1: " + string.Join(',', MatchInfo.MatchTeam1.Players.Select(p => $"{p.Player.PlayerName}").ToList())); + // Console.WriteLine("Team 2: " + string.Join(',', MatchInfo.MatchTeam2.Players.Select(p => $"{p.Player.PlayerName}").ToList())); + + return true; + } + public bool TryAddPlayer(IPlayer player) { if (!PlayerBelongsToMatch(player.SteamID)) @@ -947,6 +1028,12 @@ public bool TryAddPlayer(IPlayer player) return false; } + if (MatchInfo.Config.TeamMode == Config.TeamMode.PlayerSelect) + { + // Quicker to just remove them and add them back, rather than check whether they are already in the match + return TryAddPlayerToCurrentTeam(player); + } + if (MatchInfo.MatchTeam1.Players.Any(x => x.Player.SteamID == player.SteamID) || MatchInfo.MatchTeam2.Players.Any(x => x.Player.SteamID == player.SteamID)) { @@ -1036,6 +1123,12 @@ public void TogglePlayerIsReady(IPlayer player) } var matchPlayer = GetMatchPlayer(player.SteamID); + if (matchPlayer.Player.Team != Team.Terrorist && matchPlayer.Player.Team != Team.CounterTerrorist) + { + player.PrintToChat(_TextHelper.GetText(nameof(Resources.PugSharp_Match_Error_NoReadyExpected))); + return; + } + matchPlayer.IsReady = !matchPlayer.IsReady; var readyPlayers = MatchInfo.MatchTeam1.Players.Count(x => x.IsReady) + MatchInfo.MatchTeam2.Players.Count(x => x.IsReady); diff --git a/PugSharp.Translation/Properties/Resources.Designer.cs b/PugSharp.Translation/Properties/Resources.Designer.cs index f71516ed..9a5977e4 100644 --- a/PugSharp.Translation/Properties/Resources.Designer.cs +++ b/PugSharp.Translation/Properties/Resources.Designer.cs @@ -600,6 +600,15 @@ public static string PugSharp_Match_Info_WaitingForAllPlayers { } } + /// + /// Looks up a localized string similar to You are currently on the Team {0:teamName}. + /// + public static string PugSharp_Match_TeamReminder { + get { + return ResourceManager.GetString("PugSharp.Match.TeamReminder", resourceCulture); + } + } + /// /// Looks up a localized string similar to You are !!not!! ready! Type `!ready` if you are ready.. /// @@ -608,7 +617,7 @@ public static string PugSharp_Match_RemindReady { return ResourceManager.GetString("PugSharp.Match.RemindReady", resourceCulture); } } - + /// /// Looks up a localized string similar to {0:teamName} selected {1:side} as startside!. /// @@ -653,6 +662,15 @@ public static string PugSharp_Match_VoteTeamMenuHeader { return ResourceManager.GetString("PugSharp.Match.VoteTeamMenuHeader", resourceCulture); } } + + /// + /// Looks up a localized string similar Confirming Team + /// + public static string PugSharp_Match_VoteConfirmTeamHeader { + get { + return ResourceManager.GetString("PugSharp.Match.VoteConfirmTeamHeader", resourceCulture); + } + } /// /// Looks up a localized string similar to Waiting for other Team to vote!. diff --git a/PugSharp.Translation/Properties/Resources.br.resx b/PugSharp.Translation/Properties/Resources.br.resx index d978eabd..fdfe3c9e 100644 --- a/PugSharp.Translation/Properties/Resources.br.resx +++ b/PugSharp.Translation/Properties/Resources.br.resx @@ -238,6 +238,9 @@ Aguardando todos os jogadores estarem prontos. + + Você está atualmente na equipe: **{0:teamName}**. + Você !!não!! está pronto!! Digite `!ready` se você está pronto. @@ -256,6 +259,9 @@ Escolha o lado inicial com (`!stay` ou `!switch`) + + Escolha a equipe correta: + Aguardando o voto da outra equipe! diff --git a/PugSharp.Translation/Properties/Resources.da.resx b/PugSharp.Translation/Properties/Resources.da.resx index 98fa84bc..369e8e9f 100644 --- a/PugSharp.Translation/Properties/Resources.da.resx +++ b/PugSharp.Translation/Properties/Resources.da.resx @@ -70,6 +70,9 @@ Kampconfig loadet! + + Je zit momenteel in Team: **{0:teamName}**. + `!spillereperteam <players>` for at sætte antal spillere per hold! diff --git a/PugSharp.Translation/Properties/Resources.de.resx b/PugSharp.Translation/Properties/Resources.de.resx index b2c3c2d4..6ca14557 100644 --- a/PugSharp.Translation/Properties/Resources.de.resx +++ b/PugSharp.Translation/Properties/Resources.de.resx @@ -168,6 +168,9 @@ Die Karte mit der Kartennummer **{0:mapNumber}** ist nicht verfügbar! + + Sie sind derzeit im Team: **{0:teamName}**. + Du bist !!nicht!! bereit! Schreibe `!ready` in den chat wenn du bereit bist. @@ -177,6 +180,9 @@ Wähle die Startseite (`!stay` oder`!switch`) + + Wählen Sie das richtige Team: + Stimme ab um eine Karte zu bannen: schreibe `!<Kartennummer>` in den Chat diff --git a/PugSharp.Translation/Properties/Resources.es.resx b/PugSharp.Translation/Properties/Resources.es.resx index e4ca7190..159fbbfa 100644 --- a/PugSharp.Translation/Properties/Resources.es.resx +++ b/PugSharp.Translation/Properties/Resources.es.resx @@ -64,6 +64,9 @@ Elige bando inicial: + + Elige el equipo correcto: + Votación para banear mapa: escribe `!<mapnumber>` @@ -88,6 +91,9 @@ Esperando a que todos los jugadores estén preparados. + + Actualmente estás en el equipo: **{0:teamName}**. + La partida está **EN VIVO** diff --git a/PugSharp.Translation/Properties/Resources.ja.resx b/PugSharp.Translation/Properties/Resources.ja.resx index a417c9b0..1cd4c794 100644 --- a/PugSharp.Translation/Properties/Resources.ja.resx +++ b/PugSharp.Translation/Properties/Resources.ja.resx @@ -67,6 +67,9 @@ 最大ラウンド数を{0:oldMaxRounds}から{1:maxRounds}に変更 + + あなたは現在次のチームに所属しています: **{0:teamName}**. + `!startmatch`で試合を開始できます! diff --git a/PugSharp.Translation/Properties/Resources.ko.resx b/PugSharp.Translation/Properties/Resources.ko.resx index 09d93293..f9f87e13 100644 --- a/PugSharp.Translation/Properties/Resources.ko.resx +++ b/PugSharp.Translation/Properties/Resources.ko.resx @@ -58,6 +58,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 귀하는 현재 다음 팀에 속해 있습니다: **{0:teamName}**. + **{0:playerName}** 안녕하세요, 매치에 오신걸 환영합니다 {1:matchId} diff --git a/PugSharp.Translation/Properties/Resources.resx b/PugSharp.Translation/Properties/Resources.resx index d5e60023..bf76be2b 100644 --- a/PugSharp.Translation/Properties/Resources.resx +++ b/PugSharp.Translation/Properties/Resources.resx @@ -297,6 +297,9 @@ Waiting for all players to be ready. + + You are currently on Team: **{0:teamName}**. + You are !!not!! ready! Type `!ready` if you are ready. @@ -315,6 +318,9 @@ Choose starting side (`!stay` or `!switch`) + + Escolha a equipe correta: + Waiting for other Team to vote! diff --git a/PugSharp/Application.cs b/PugSharp/Application.cs index 878e19b2..85c23731 100644 --- a/PugSharp/Application.cs +++ b/PugSharp/Application.cs @@ -263,6 +263,18 @@ private async void CheckMatchPlayerTeam(CCSPlayerController playerController, in if (_Match.CurrentState == MatchState.WaitingForPlayersConnectedReady || _Match.CurrentState == MatchState.WaitingForPlayersReady) { + // Do not enforce locked teams during warmup for TeamMode: PlayerSelect + if (_Match.MatchInfo.Config.TeamMode == TeamMode.PlayerSelect) + { + // If player is already on team, make sure the match teams are updated + if (_Match.PlayerIsReady(playerController.SteamID) && (team == (int)Match.Contract.Team.Terrorist || team == (int)Match.Contract.Team.CounterTerrorist)) + { + _Match.TryAddPlayer(new Player(playerController.SteamID)); + } + + return; + } + var configTeam = _Match.GetPlayerTeam(playerController.SteamID); var steamId = playerController.SteamID; var userName = playerController.PlayerName; @@ -323,10 +335,15 @@ private void OnMapStartHandler(string mapName) { if (_Match != null) { - _Dispatcher.NextFrame(() => + if (_Match.CurrentState is MatchState.WaitingForPlayersConnectedReady or MatchState.WaitingForPlayersReady) { - SetMatchVariable(); - }); + _CsServer.LoadAndExecuteConfig("warmup.cfg"); + + _Dispatcher.NextFrame(() => + { + SetMatchVariable(); + }); + } } } @@ -1956,6 +1973,18 @@ private void SetMatchVariable() _CsServer.ExecuteCommand($"mp_teamname_2 {tTeam.TeamConfig.Name}"); _CsServer.ExecuteCommand($"mp_teamflag_2 {tTeam.TeamConfig.Flag}"); + // Allow players to select their team + if (_Match.MatchInfo.Config.TeamMode == TeamMode.PlayerSelect) + { + _CsServer.UpdateConvar("sv_disable_teamselect_menu", false); + _CsServer.UpdateConvar("sv_human_autojoin_team", (int)Match.Contract.Team.None); + } + else + { + _CsServer.UpdateConvar("sv_disable_teamselect_menu", true); + _CsServer.UpdateConvar("sv_human_autojoin_team", (int)Match.Contract.Team.Terrorist); + } + _Logger.LogInformation("Set match variables done"); }