]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/teamplay.qc
Merge branch 'master' into Lyberta/TeamplayOverhaul2
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / teamplay.qc
index 5b9ab4db5faf240bcc887d156f083359521a19c1..1959fe369791811fd19385308acb52e3795df9be 100644 (file)
@@ -28,6 +28,8 @@ enum
 /// \brief Indicates that the player is not allowed to join a team.
 const int TEAM_NOT_ALLOWED = -1;
 
+.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
+
 .int m_team_balance_state; ///< Holds the state of the team balance entity.
 .entity m_team_balance_team[NUM_TEAMS]; ///< ???
 
@@ -37,6 +39,11 @@ const int TEAM_NOT_ALLOWED = -1;
 .int m_num_players_alive; ///< Number of alive players in a team.
 .int m_num_control_points; ///< Number of control points owned by a team.
 
+string autocvar_g_forced_team_red;
+string autocvar_g_forced_team_blue;
+string autocvar_g_forced_team_yellow;
+string autocvar_g_forced_team_pink;
+
 entity g_team_entities[NUM_TEAMS]; ///< Holds global team entities.
 
 STATIC_INIT(g_team_entities)
@@ -254,6 +261,116 @@ void LogTeamchange(float player_id, float team_number, int type)
        GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
 }
 
+bool Player_HasRealForcedTeam(entity player)
+{
+       return player.team_forced > TEAM_FORCE_DEFAULT;
+}
+
+int Player_GetForcedTeamIndex(entity player)
+{
+       return player.team_forced;
+}
+
+void Player_SetForcedTeamIndex(entity player, int team_index)
+{
+       switch (team_index)
+       {
+               case TEAM_FORCE_SPECTATOR:
+               case TEAM_FORCE_DEFAULT:
+               {
+                       player.team_forced = team_index;
+                       break;
+               }
+               default:
+               {
+                       if (!Team_IsValidIndex(team_index))
+                       {
+                               LOG_FATAL("Player_SetForcedTeamIndex: Invalid team index.");
+                       }
+                       else
+                       {
+                               player.team_forced = team_index;
+                               break;
+                       }
+               }
+       }
+}
+
+void Player_DetermineForcedTeam(entity player)
+{
+       if (autocvar_g_campaign)
+       {
+               if (IS_REAL_CLIENT(player)) // only players, not bots
+               {
+                       if (Team_IsValidIndex(autocvar_g_campaign_forceteam))
+                       {
+                               player.team_forced = autocvar_g_campaign_forceteam;
+                       }
+                       else
+                       {
+                               player.team_forced = TEAM_FORCE_DEFAULT;
+                       }
+               }
+       }
+       else if (PlayerInList(player, autocvar_g_forced_team_red))
+       {
+               player.team_forced = 1;
+       }
+       else if (PlayerInList(player, autocvar_g_forced_team_blue))
+       {
+               player.team_forced = 2;
+       }
+       else if (PlayerInList(player, autocvar_g_forced_team_yellow))
+       {
+               player.team_forced = 3;
+       }
+       else if (PlayerInList(player, autocvar_g_forced_team_pink))
+       {
+               player.team_forced = 4;
+       }
+       else
+       {
+               switch (autocvar_g_forced_team_otherwise)
+               {
+                       case "red":
+                       {
+                               player.team_forced = 1;
+                               break;
+                       }
+                       case "blue":
+                       {
+                               player.team_forced = 2;
+                               break;
+                       }
+                       case "yellow":
+                       {
+                               player.team_forced = 3;
+                               break;
+                       }
+                       case "pink":
+                       {
+                               player.team_forced = 4;
+                               break;
+                       }
+                       case "spectate":
+                       case "spectator":
+                       {
+                               player.team_forced = TEAM_FORCE_SPECTATOR;
+                               break;
+                       }
+                       default:
+                       {
+                               player.team_forced = TEAM_FORCE_DEFAULT;
+                               break;
+                       }
+               }
+       }
+       if (!teamplay && Player_HasRealForcedTeam(player))
+       {
+               player.team_forced = TEAM_FORCE_DEFAULT;
+       }
+}
+
 entity TeamBalance_CheckAllowedTeams(entity for_whom)
 {
        entity balance = spawn();
@@ -264,6 +381,7 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom)
                team_ent.m_num_players = TEAM_NOT_ALLOWED;
                team_ent.m_num_bots = 0;
        }
+       setthink(balance, TeamBalance_Destroy);
        
        int teams_mask = 0;     
        string teament_name = string_null;
@@ -382,7 +500,7 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom)
        // if player has a forced team, ONLY allow that one
        for (int i = 1; i <= NUM_TEAMS; ++i)
        {
-               if (for_whom.team_forced == Team_IndexToTeam(i) &&
+               if (for_whom.team_forced == i &&
                        TeamBalance_IsTeamAllowedInternal(balance, i))
                {
                        TeamBalance_BanTeamsExcept(balance, i);
@@ -486,9 +604,9 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore)
                        {
                                team_num = it.team;
                        }
-                       else if (it.team_forced > 0)
+                       else if (Player_HasRealForcedTeam(it))
                        {
-                               team_num = it.team_forced; // reserve the spot
+                               team_num = Team_IndexToTeam(it.team_forced); // reserve the spot
                        }
                        else
                        {
@@ -630,48 +748,40 @@ int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score)
        return team_bits;
 }
 
-void TeamBalance_JoinBestTeam(entity this, bool force_best_team)
+void TeamBalance_JoinBestTeam(entity this)
 {
-       //PrintToChatAll(sprintf("JoinBestTeam: %s, %f", this.netname, force_best_team));
-       // don't join a team if we're not playing a team game
+       //PrintToChatAll(sprintf("JoinBestTeam: %s", this.netname));
        if (!teamplay)
        {
                return;
        }
-
-       // find out what teams are available
+       if (this.bot_forced_team)
+       {
+               return;
+       }
+       int old_team_index = Team_TeamToIndex(this.team);
        entity balance = TeamBalance_CheckAllowedTeams(this);
-
-       // if we don't care what team they end up on, put them on whatever team they entered as.
-       // if they're not on a valid team, then let other code put them on the smallest team
-       if (!force_best_team)
+       if (Player_HasRealForcedTeam(this))
        {
-               int selected_team_index = -1;
-               for (int i = 1; i <= NUM_TEAMS; ++i)
+               int forced_team_index = this.team_forced;
+               bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
+                       forced_team_index);
+               TeamBalance_Destroy(balance);
+               if (!is_team_allowed)
                {
-                       if (TeamBalance_IsTeamAllowedInternal(balance, i) &&
-                               (Team_TeamToIndex(this.team) == i))
-                       {
-                               selected_team_index = i;
-                               break;
-                       }
+                       return;
                }
-               
-               if (Team_IsValidIndex(selected_team_index))
+               if (!SetPlayerTeam(this, forced_team_index, TEAM_CHANGE_AUTO))
                {
-                       SetPlayerTeam(this, selected_team_index, TEAM_CHANGE_AUTO_RELAXED);
-                       TeamBalance_Destroy(balance);
                        return;
                }
-       }
-       // otherwise end up on the smallest team (handled below)
-       if (this.bot_forced_team)
-       {
-               TeamBalance_Destroy(balance);
+               if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
+               {
+                       TeamBalance_AutoBalanceBots(forced_team_index, old_team_index);
+               }
                return;
        }
        int best_team_index = TeamBalance_FindBestTeam(balance, this, true);
-       int old_team_index = Team_TeamToIndex(this.team);
        TeamBalance_Destroy(balance);
        PlayerScore_Clear(this);
        if (!SetPlayerTeam(this, best_team_index, TEAM_CHANGE_AUTO))
@@ -965,5 +1075,9 @@ void SV_ChangeTeam(entity this, float _color)
        {
                return;
        }
+       if (source_team_index == -1)
+       {
+               return;
+       }
        TeamBalance_AutoBalanceBots(destination_team_index, source_team_index);
 }