#include "command/vote.qh"
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
#include "../common/deathtypes/all.qh"
-#include "../common/gamemodes/_mod.qh"
+#include <common/gamemodes/_mod.qh>
#include "../common/teams.qh"
/// \brief Describes a state of team balance entity.
/// \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]; ///< ???
.int m_num_bots; ///< Number of bots in a team.
.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.
-.entity m_lowest_human; ///< Human with the lowest score in a team.
-.entity m_lowest_bot; ///< Bot with the lowest score in 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.
int new_team = Team_IndexToTeam(index);
if (player.team == new_team)
{
- // This is important when players join the game and one of their color
- // matches the team color while other doesn't. For example [BOT]Lion.
- SetPlayerColors(player, new_team - 1);
+ if (new_team != -1)
+ {
+ // This is important when players join the game and one of their
+ // color matches the team color while other doesn't. For example
+ // [BOT]Lion.
+ SetPlayerColors(player, new_team - 1);
+ }
return true;
}
int old_index = Team_TeamToIndex(player.team);
// Mutator has blocked team change.
return false;
}
- SetPlayerColors(player, new_team - 1);
+ if (new_team == -1)
+ {
+ player.team = -1;
+ }
+ else
+ {
+ SetPlayerColors(player, new_team - 1);
+ }
MUTATOR_CALLHOOK(Player_ChangedTeam, player, old_index, index);
return true;
}
-bool SetPlayerTeam(entity player, int destination_team_index,
- int source_team_index, bool no_print)
+bool SetPlayerTeam(entity player, int team_index, int type)
{
- if (!Player_SetTeamIndex(player, destination_team_index))
+ int old_team_index = Entity_GetTeamIndex(player);
+ if (!Player_SetTeamIndex(player, team_index))
{
return false;
}
- LogTeamchange(player.playerid, player.team, TEAM_CHANGE_MANUAL);
- if (no_print)
+ LogTeamChange(player.playerid, player.team, type);
+ if (team_index != old_team_index)
{
- return true;
+ PlayerScore_Clear(player);
+ if (team_index != -1)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(
+ player.team, INFO_JOIN_PLAY_TEAM), player.netname);
+ }
+ else
+ {
+ if (!CS(player).just_joined)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE,
+ player.netname);
+ }
+ else
+ {
+ CS(player).just_joined = false;
+ }
+ }
+ KillPlayerForTeamChange(player);
+ if (!IS_BOT_CLIENT(player))
+ {
+ TeamBalance_AutoBalanceBots();
+ }
}
- bprint(playername(player, false), "^7 has changed from ",
- Team_IndexToColoredFullName(source_team_index), "^7 to ",
- Team_IndexToColoredFullName(destination_team_index), "\n");
return true;
}
+void Player_SetTeamIndexChecked(entity player, int team_index)
+{
+ if (!teamplay)
+ {
+ return;
+ }
+ if (!Team_IsValidIndex(team_index))
+ {
+ return;
+ }
+ if ((autocvar_g_campaign) || (autocvar_g_changeteam_banned &&
+ CS(player).wasplayer))
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_INFO,
+ INFO_TEAMCHANGE_NOTALLOWED);
+ return;
+ }
+ entity balance = TeamBalance_CheckAllowedTeams(player);
+ if (team_index == 1 && !TeamBalance_IsTeamAllowedInternal(balance, 1))
+ {
+ team_index = 4;
+ }
+ if (team_index == 4 && !TeamBalance_IsTeamAllowedInternal(balance, 4))
+ {
+ team_index = 3;
+ }
+ if (team_index == 3 && !TeamBalance_IsTeamAllowedInternal(balance, 3))
+ {
+ team_index = 2;
+ }
+ if (team_index == 2 && !TeamBalance_IsTeamAllowedInternal(balance, 2))
+ {
+ team_index = 1;
+ }
+ // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless
+ if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
+ {
+ TeamBalance_GetTeamCounts(balance, player);
+ if ((Team_IndexToBit(team_index) & TeamBalance_FindBestTeams(balance,
+ player, false)) == 0)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_INFO,
+ INFO_TEAMCHANGE_LARGERTEAM);
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ }
+ TeamBalance_Destroy(balance);
+ SetPlayerTeam(player, team_index, TEAM_CHANGE_MANUAL);
+}
+
bool MoveToTeam(entity client, int team_index, int type)
{
+ //PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index));
int lockteams_backup = lockteams; // backup any team lock
lockteams = 0; // disable locked teams
- PlayerScore_Clear(client);
- if (!Player_SetTeamIndex(client, team_index))
+ if (!SetPlayerTeam(client, team_index, type))
{
lockteams = lockteams_backup; // restore the team lock
return false;
}
- KillPlayerForTeamChange(client);
lockteams = lockteams_backup; // restore the team lock
- LogTeamchange(client.playerid, client.team, type);
return true;
}
-void KillPlayerForTeamChange(entity player)
+bool Player_HasRealForcedTeam(entity player)
{
- if (IS_DEAD(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)
{
- return;
+ 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;
+ }
+ }
}
- if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
+}
+
+void Player_DetermineForcedTeam(entity player)
+{
+ if (autocvar_g_campaign)
{
- return;
+ 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;
}
- Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
- player.origin, '0 0 0');
}
-void LogTeamchange(float player_id, float team_number, int type)
+void TeamBalance_JoinBestTeam(entity player)
{
- if(!autocvar_sv_eventlog)
+ //PrintToChatAll(sprintf("TeamBalance_JoinBestTeam: %s", player.netname));
+ if (!teamplay)
+ {
return;
-
- if(player_id < 1)
+ }
+ if (player.bot_forced_team)
+ {
return;
-
- GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type)));
+ }
+ entity balance = TeamBalance_CheckAllowedTeams(player);
+ if (Player_HasRealForcedTeam(player))
+ {
+ int forced_team_index = player.team_forced;
+ bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
+ forced_team_index);
+ TeamBalance_Destroy(balance);
+ if (!is_team_allowed)
+ {
+ return;
+ }
+ if (!SetPlayerTeam(player, forced_team_index, TEAM_CHANGE_AUTO))
+ {
+ return;
+ }
+ return;
+ }
+ int best_team_index = TeamBalance_FindBestTeam(balance, player, true);
+ TeamBalance_Destroy(balance);
+ if (!SetPlayerTeam(player, best_team_index, TEAM_CHANGE_AUTO))
+ {
+ return;
+ }
}
entity TeamBalance_CheckAllowedTeams(entity for_whom)
team_ent.m_team_score = g_team_entities[i].m_team_score;
team_ent.m_num_players = TEAM_NOT_ALLOWED;
team_ent.m_num_bots = 0;
- team_ent.m_lowest_human = NULL;
- team_ent.m_lowest_bot = NULL;
}
+ setthink(balance, TeamBalance_Destroy);
int teams_mask = 0;
string teament_name = string_null;
// 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);
+ break;
}
- break;
}
balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED;
return balance;
entity team_ent = TeamBalance_GetTeamFromIndex(balance, i);
if (TeamBalanceTeam_IsAllowed(team_ent))
{
- MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore,
- team_ent.m_num_players, team_ent.m_num_bots,
- team_ent.m_lowest_human, team_ent.m_lowest_bot);
+ MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore);
team_ent.m_num_players = M_ARGV(2, float);
team_ent.m_num_bots = M_ARGV(3, float);
- team_ent.m_lowest_human = M_ARGV(4, entity);
- team_ent.m_lowest_bot = M_ARGV(5, entity);
}
}
}
continue;
}
int team_num;
- if (IS_PLAYER(it) || it.caplayer)
+ // TODO: Reconsider when the player is truly on the team.
+ if (IS_CLIENT(it) || (it.caplayer))
{
team_num = it.team;
}
- else if (it.team_forced > 0)
+ else if (Player_HasRealForcedTeam(it))
{
- team_num = it.team_forced; // reserve the spot
+ // Do we really need this? Probably not.
+ team_num = Team_IndexToTeam(it.team_forced); // reserve the spot
}
else
{
{
++team_ent.m_num_bots;
}
- float temp_score = PlayerScore_Get(it, SP_SCORE);
- if (!IS_BOT_CLIENT(it))
- {
- if (team_ent.m_lowest_human == NULL)
- {
- team_ent.m_lowest_human = it;
- continue;
- }
- if (temp_score < PlayerScore_Get(team_ent.m_lowest_human,
- SP_SCORE))
- {
- team_ent.m_lowest_human = it;
- }
- continue;
- }
- if (team_ent.m_lowest_bot == NULL)
- {
- team_ent.m_lowest_bot = it;
- continue;
- }
- if (temp_score < PlayerScore_Get(team_ent.m_lowest_bot, SP_SCORE))
- {
- team_ent.m_lowest_bot = it;
- }
});
}
return team_bits;
}
-void TeamBalance_JoinBestTeam(entity this, bool force_best_team)
-{
- // don't join a team if we're not playing a team game
- if (!teamplay)
- {
- return;
- }
-
- // find out what teams are available
- 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)
- {
- int selected_team_index = -1;
- for (int i = 1; i <= NUM_TEAMS; ++i)
- {
- if (TeamBalance_IsTeamAllowedInternal(balance, i) &&
- (Team_TeamToIndex(this.team) == i))
- {
- selected_team_index = i;
- break;
- }
- }
-
- if (Team_IsValidIndex(selected_team_index))
- {
- Player_SetTeamIndex(this, selected_team_index);
- LogTeamchange(this.playerid, this.team, 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);
- return;
- }
- int best_team_index = TeamBalance_FindBestTeam(balance, this, true);
- int old_team_index = Team_TeamToIndex(this.team);
- PlayerScore_Clear(this);
- Player_SetTeamIndex(this, best_team_index);
- LogTeamchange(this.playerid, this.team, TEAM_CHANGE_AUTO);
- if ((old_team_index != -1) && !IS_BOT_CLIENT(this))
- {
- TeamBalance_AutoBalanceBots(balance, old_team_index, best_team_index);
- }
- KillPlayerForTeamChange(this);
- TeamBalance_Destroy(balance);
-}
-
int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b,
entity player, bool use_score)
{
return TeamBalance_CompareTeamsInternal(team_a, team_b, player, use_score);
}
-void TeamBalance_AutoBalanceBots(entity balance, int source_team_index,
- int destination_team_index)
+void TeamBalance_AutoBalanceBots()
{
- if (balance == NULL)
+ if (!autocvar_g_balance_teams ||
+ !autocvar_g_balance_teams_prevent_imbalance)
{
- LOG_FATAL("TeamBalance_AutoBalanceBots: Team balance entity is NULL.");
+ return;
}
- if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
+ //PrintToChatAll("TeamBalance_AutoBalanceBots");
+ entity balance = TeamBalance_CheckAllowedTeams(NULL);
+ TeamBalance_GetTeamCounts(balance, NULL);
+ int smallest_team_index = 0;
+ int smallest_team_player_count = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
{
- LOG_FATAL("TeamBalance_AutoBalanceBots: "
- "TeamBalance_GetTeamCounts has not been called.");
+ entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
+ if (!TeamBalanceTeam_IsAllowed(team_))
+ {
+ continue;
+ }
+ int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_);
+ if (smallest_team_index == 0)
+ {
+ smallest_team_index = i;
+ smallest_team_player_count = playercount;
+ }
+ else if (playercount < smallest_team_player_count)
+ {
+ smallest_team_index = i;
+ smallest_team_player_count = playercount;
+ }
}
- if (!Team_IsValidIndex(source_team_index))
+ //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index));
+ //PrintToChatAll(sprintf("Smallest team players: %f", smallest_team_player_count));
+ entity switchable_bot = NULL;
+ int teams = BITS(NUM_TEAMS);
+ while (teams != 0)
{
- LOG_WARNF("AutoBalanceBots: Source team index is invalid: %f",
- source_team_index);
+ int largest_team_index = TeamBalance_GetLargestTeamIndex(balance,
+ teams);
+ if (smallest_team_index == largest_team_index)
+ {
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ entity largest_team = TeamBalance_GetTeamFromIndex(balance,
+ largest_team_index);
+ int largest_team_player_count = TeamBalanceTeam_GetNumberOfPlayers(
+ largest_team);
+ if (largest_team_player_count - smallest_team_player_count < 2)
+ {
+ TeamBalance_Destroy(balance);
+ return;
+ }
+ //PrintToChatAll(sprintf("Largest team: %f", largest_team_index));
+ //PrintToChatAll(sprintf("Largest team players: %f", largest_team_player_count));
+ switchable_bot = TeamBalance_GetPlayerForTeamSwitch(largest_team_index,
+ smallest_team_index, true);
+ if (switchable_bot != NULL)
+ {
+ break;
+ }
+ teams &= ~Team_IndexToBit(largest_team_index);
+ }
+ TeamBalance_Destroy(balance);
+ if (switchable_bot == NULL)
+ {
+ //PrintToChatAll("No bot found after searching through all the teams");
return;
}
- if (!Team_IsValidIndex(destination_team_index))
+ SetPlayerTeam(switchable_bot, smallest_team_index, TEAM_CHANGE_AUTO);
+}
+
+int TeamBalance_GetLargestTeamIndex(entity balance, int teams)
+{
+ int largest_team_index = 0;
+ int largest_team_player_count = 0;
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ if (!(Team_IndexToBit(i) & teams))
+ {
+ continue;
+ }
+ entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
+ if (!TeamBalanceTeam_IsAllowed(team_))
+ {
+ continue;
+ }
+ int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_);
+ if (largest_team_index == 0)
+ {
+ largest_team_index = i;
+ largest_team_player_count = playercount;
+ }
+ else if (playercount > largest_team_player_count)
+ {
+ largest_team_index = i;
+ largest_team_player_count = playercount;
+ }
+ }
+ return largest_team_index;
+}
+
+entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index,
+ int destination_team_index, bool is_bot)
+{
+ if (MUTATOR_CALLHOOK(TeamBalance_GetPlayerForTeamSwitch, source_team_index,
+ destination_team_index, is_bot))
+ {
+ return M_ARGV(3, entity);
+ }
+ entity lowest_player = NULL;
+ float lowest_score = FLOAT_MAX;
+ FOREACH_CLIENT(Entity_GetTeamIndex(it) == source_team_index,
+ {
+ if (IS_BOT_CLIENT(it) != is_bot)
+ {
+ continue;
+ }
+ float temp_score = PlayerScore_Get(it, SP_SCORE);
+ if (temp_score >= lowest_score)
+ {
+ continue;
+ }
+ //PrintToChatAll(sprintf(
+ // "Found %s with lowest score, checking allowed teams", it.netname));
+ entity balance = TeamBalance_CheckAllowedTeams(it);
+ if (TeamBalance_IsTeamAllowed(balance, source_team_index))
+ {
+ //PrintToChatAll("Allowed");
+ lowest_player = it;
+ lowest_score = temp_score;
+ }
+ else
+ {
+ //PrintToChatAll("Not allowed");
+ }
+ TeamBalance_Destroy(balance);
+ });
+ return lowest_player;
+}
+
+void LogTeamChange(float player_id, float team_number, int type)
+{
+ if (!autocvar_sv_eventlog)
{
- LOG_WARNF("AutoBalanceBots: Destination team index is invalid: %f",
- destination_team_index);
return;
}
- if (!autocvar_g_balance_teams ||
- !autocvar_g_balance_teams_prevent_imbalance)
+ if (player_id < 1)
{
return;
}
- entity source_team = TeamBalance_GetTeamFromIndex(balance,
- source_team_index);
- if (!TeamBalanceTeam_IsAllowed(source_team))
+ GameLogEcho(sprintf(":team:%f:%f:%f", player_id, team_number, type));
+}
+
+void KillPlayerForTeamChange(entity player)
+{
+ if (IS_DEAD(player))
{
return;
}
- entity destination_team = TeamBalance_GetTeamFromIndex(balance,
- destination_team_index);
- if ((destination_team.m_num_players <= source_team.m_num_players) ||
- (destination_team.m_lowest_bot == NULL))
+ if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
{
return;
}
- Player_SetTeamIndex(destination_team.m_lowest_bot, source_team_index);
- KillPlayerForTeamChange(destination_team.m_lowest_bot);
+ Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
+ player.origin, '0 0 0');
}
bool TeamBalance_IsTeamAllowedInternal(entity balance, int index)
return team_ent.m_num_bots;
}
-entity TeamBalanceTeam_GetLowestHuman(entity team_ent)
-{
- return team_ent.m_lowest_human;
-}
-
-entity TeamBalanceTeam_GetLowestBot(entity team_ent)
-{
- return team_ent.m_lowest_bot;
-}
-
int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b,
entity player, bool use_score)
{
return TEAMS_COMPARE_EQUAL;
}
-void SV_ChangeTeam(entity this, float _color)
+void SV_ChangeTeam(entity player, int new_color)
{
- int source_color, destination_color;
- int source_team_index, destination_team_index;
-
- // in normal deathmatch we can just apply the color and we're done
- if(!teamplay)
- SetPlayerColors(this, _color);
-
- if(!IS_CLIENT(this))
- {
- // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname);
- return;
- }
-
- if(!teamplay)
- return;
-
- source_color = this.clientcolors & 0x0F;
- destination_color = _color & 0x0F;
-
- source_team_index = Team_TeamToIndex(source_color + 1);
- destination_team_index = Team_TeamToIndex(destination_color + 1);
-
- if (destination_team_index == -1)
- {
- return;
- }
-
- entity balance = TeamBalance_CheckAllowedTeams(this);
-
- if (destination_team_index == 1 && !TeamBalance_IsTeamAllowedInternal(
- balance, 1))
- {
- destination_team_index = 4;
- }
- if (destination_team_index == 4 && !TeamBalance_IsTeamAllowedInternal(
- balance, 4))
- {
- destination_team_index = 3;
- }
- if (destination_team_index == 3 && !TeamBalance_IsTeamAllowedInternal(
- balance, 3))
- {
- destination_team_index = 2;
- }
- if (destination_team_index == 2 && !TeamBalance_IsTeamAllowedInternal(
- balance, 2))
- {
- destination_team_index = 1;
- }
-
- // not changing teams
- if (source_color == destination_color)
- {
- SetPlayerTeam(this, destination_team_index, source_team_index, true);
- TeamBalance_Destroy(balance);
- return;
- }
-
- if((autocvar_g_campaign) || (autocvar_g_changeteam_banned && CS(this).wasplayer)) {
- Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_NOTALLOWED);
- return; // changing teams is not allowed
- }
-
- // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless
- if (autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
- {
- TeamBalance_GetTeamCounts(balance, this);
- if ((Team_IndexToBit(destination_team_index) &
- TeamBalance_FindBestTeams(balance, this, false)) == 0)
- {
- Send_Notification(NOTIF_ONE, this, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
- TeamBalance_Destroy(balance);
- return;
- }
- }
- if (IS_PLAYER(this) && source_team_index != destination_team_index)
+ if (!teamplay)
{
- // reduce frags during a team change
- PlayerScore_Clear(this);
+ SetPlayerColors(player, new_color);
}
- if (!SetPlayerTeam(this, destination_team_index, source_team_index,
- !IS_CLIENT(this)))
+ // TODO: Should we really bother with this?
+ if(!IS_CLIENT(player))
{
- TeamBalance_Destroy(balance);
+ // since this is an engine function, and gamecode doesn't have any calls earlier than this, do the connecting message here
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING,
+ player.netname);
return;
}
- TeamBalance_AutoBalanceBots(balance, source_team_index,
- destination_team_index);
- if (!IS_PLAYER(this) || (source_team_index == destination_team_index))
+ if (!teamplay)
{
- TeamBalance_Destroy(balance);
return;
}
- KillPlayerForTeamChange(this);
- TeamBalance_Destroy(balance);
+ Player_SetTeamIndexChecked(player, Team_TeamToIndex((new_color & 0x0F) +
+ 1));
}