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