X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fteamplay.qc;h=239fb69f0ca8e0e4b20b1da78d8e44897b4e6e5b;hb=5d36c4af90925223244be05529c0152f5011e7ce;hp=ffa1399d4748bf1935f75da9efca1946d7fffd95;hpb=639ff52aeb3d7f0f0bd86e97976c1c00deb74b61;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index ffa1399d4..239fb69f0 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -9,10 +9,10 @@ #include "command/vote.qh" -#include "mutators/_mod.qh" +#include #include "../common/deathtypes/all.qh" -#include "../common/gamemodes/_mod.qh" +#include #include "../common/teams.qh" /// \brief Describes a state of team balance entity. @@ -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]; ///< ??? @@ -36,8 +38,11 @@ const int TEAM_NOT_ALLOWED = -1; .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. @@ -67,24 +72,24 @@ entity Team_GetTeam(int team_num) return g_team_entities[Team_TeamToIndex(team_num) - 1]; } -float Team_GetTeamScore(entity team_) +float Team_GetTeamScore(entity team_ent) { - return team_.m_team_score; + return team_ent.m_team_score; } -void Team_SetTeamScore(entity team_, float score) +void Team_SetTeamScore(entity team_ent, float score) { - team_.m_team_score = score; + team_ent.m_team_score = score; } -int Team_GetNumberOfAlivePlayers(entity team_) +int Team_GetNumberOfAlivePlayers(entity team_ent) { - return team_.m_num_players_alive; + return team_ent.m_num_players_alive; } -void Team_SetNumberOfAlivePlayers(entity team_, int number) +void Team_SetNumberOfAlivePlayers(entity team_ent, int number) { - team_.m_num_players_alive = number; + team_ent.m_num_players_alive = number; } int Team_GetNumberOfAliveTeams() @@ -100,14 +105,14 @@ int Team_GetNumberOfAliveTeams() return result; } -int Team_GetNumberOfControlPoints(entity team_) +int Team_GetNumberOfControlPoints(entity team_ent) { - return team_.m_num_control_points; + return team_ent.m_num_control_points; } -void Team_SetNumberOfControlPoints(entity team_, int number) +void Team_SetNumberOfControlPoints(entity team_ent, int number) { - team_.m_num_control_points = number; + team_ent.m_num_control_points = number; } int Team_GetNumberOfTeamsWithControlPoints() @@ -123,22 +128,6 @@ int Team_GetNumberOfTeamsWithControlPoints() return result; } -void TeamchangeFrags(entity e) -{ - PlayerScore_Clear(e); -} - -void LogTeamchange(float player_id, float team_number, float type) -{ - if(!autocvar_sv_eventlog) - return; - - if(player_id < 1) - return; - - GameLogEcho(strcat(":team:", ftos(player_id), ":", ftos(team_number), ":", ftos(type))); -} - void setcolor(entity this, int clr) { #if 0 @@ -188,9 +177,13 @@ bool Player_SetTeamIndex(entity player, int index) 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); @@ -199,41 +192,264 @@ bool Player_SetTeamIndex(entity player, int index) // 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, 3); // log manual team join - 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 KillPlayerForTeamChange(entity player) +void Player_SetTeamIndexChecked(entity player, int team_index) { - if (IS_DEAD(player)) + if (!teamplay) { return; } - if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true) + 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 + if (!SetPlayerTeam(client, team_index, type)) + { + lockteams = lockteams_backup; // restore the team lock + return false; + } + lockteams = lockteams_backup; // restore the team lock + return true; +} + +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; + } +} + +void TeamBalance_JoinBestTeam(entity player) +{ + //PrintToChatAll(sprintf("TeamBalance_JoinBestTeam: %s", player.netname)); + if (!teamplay) + { + return; + } + if (player.bot_forced_team) + { + return; + } + 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; } - Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP, - player.origin, '0 0 0'); } entity TeamBalance_CheckAllowedTeams(entity for_whom) @@ -241,13 +457,12 @@ entity TeamBalance_CheckAllowedTeams(entity for_whom) entity balance = spawn(); for (int i = 0; i < NUM_TEAMS; ++i) { - entity team_ = balance.m_team_balance_team[i] = spawn(); - team_.m_team_score = g_team_entities[i].m_team_score; - team_.m_num_players = TEAM_NOT_ALLOWED; - team_.m_num_bots = 0; - team_.m_lowest_human = NULL; - team_.m_lowest_bot = NULL; + entity team_ent = balance.m_team_balance_team[i] = spawn(); + 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; } + setthink(balance, TeamBalance_Destroy); int teams_mask = 0; string teament_name = string_null; @@ -366,12 +581,12 @@ 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); + break; } - break; } balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED; return balance; @@ -385,9 +600,9 @@ void TeamBalance_Destroy(entity balance) } for (int i = 0; i < NUM_TEAMS; ++i) { - remove(balance.(m_team_balance_team[i])); + delete(balance.(m_team_balance_team[i])); } - remove(balance); + delete(balance); } int TeamBalance_GetAllowedTeams(entity balance) @@ -447,16 +662,12 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore) // Mutator has overriden the configuration. for (int i = 1; i <= NUM_TEAMS; ++i) { - entity team_ = TeamBalance_GetTeamFromIndex(balance, i); - if (TeamBalanceTeam_IsAllowed(team_)) + entity team_ent = TeamBalance_GetTeamFromIndex(balance, i); + if (TeamBalanceTeam_IsAllowed(team_ent)) { - MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore, - team_.m_num_players, team_.m_num_bots, team_.m_lowest_human, - team_.m_lowest_bot); - team_.m_num_players = M_ARGV(2, float); - team_.m_num_bots = M_ARGV(3, float); - team_.m_lowest_human = M_ARGV(4, entity); - team_.m_lowest_bot = M_ARGV(5, entity); + MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore); + team_ent.m_num_players = M_ARGV(2, float); + team_ent.m_num_bots = M_ARGV(3, float); } } } @@ -470,13 +681,15 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore) 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 { @@ -486,39 +699,15 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore) { continue; } - entity team_ = TeamBalance_GetTeam(balance, team_num); - if (!TeamBalanceTeam_IsAllowed(team_)) + entity team_ent = TeamBalance_GetTeam(balance, team_num); + if (!TeamBalanceTeam_IsAllowed(team_ent)) { continue; } - ++team_.m_num_players; + ++team_ent.m_num_players; if (IS_BOT_CLIENT(it)) { - ++team_.m_num_bots; - } - float temp_score = PlayerScore_Get(it, SP_SCORE); - if (!IS_BOT_CLIENT(it)) - { - if (team_.m_lowest_human == NULL) - { - team_.m_lowest_human = it; - continue; - } - if (temp_score < PlayerScore_Get(team_.m_lowest_human, - SP_SCORE)) - { - team_.m_lowest_human = it; - } - continue; - } - if (team_.m_lowest_bot == NULL) - { - team_.m_lowest_bot = it; - continue; - } - if (temp_score < PlayerScore_Get(team_.m_lowest_bot, SP_SCORE)) - { - team_.m_lowest_bot = it; + ++team_ent.m_num_bots; } }); } @@ -528,11 +717,11 @@ void TeamBalance_GetTeamCounts(entity balance, entity ignore) { if (Team_IsValidIndex(autocvar_g_campaign_forceteam)) { - entity team_ = TeamBalance_GetTeamFromIndex(balance, + entity team_ent = TeamBalance_GetTeamFromIndex(balance, autocvar_g_campaign_forceteam); - if (team_.m_num_players == team_.m_num_bots) + if (team_ent.m_num_players == team_ent.m_num_bots) { - ++team_.m_num_players; + ++team_ent.m_num_players; } } } @@ -642,59 +831,6 @@ int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score) 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, 99); - 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); - TeamchangeFrags(this); - Player_SetTeamIndex(this, best_team_index); - LogTeamchange(this.playerid, this.team, 2); // log auto join - 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) { @@ -726,50 +862,172 @@ int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b, 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; + } + } + //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) + { + 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); } - if (!Team_IsValidIndex(source_team_index)) + TeamBalance_Destroy(balance); + if (switchable_bot == NULL) { - LOG_WARNF("AutoBalanceBots: Source team index is invalid: %f", - source_team_index); + //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) @@ -803,29 +1061,19 @@ entity TeamBalance_GetTeam(entity balance, int team_num) return TeamBalance_GetTeamFromIndex(balance, Team_TeamToIndex(team_num)); } -bool TeamBalanceTeam_IsAllowed(entity team_) -{ - return team_.m_num_players != TEAM_NOT_ALLOWED; -} - -int TeamBalanceTeam_GetNumberOfPlayers(entity team_) +bool TeamBalanceTeam_IsAllowed(entity team_ent) { - return team_.m_num_players; + return team_ent.m_num_players != TEAM_NOT_ALLOWED; } -int TeamBalanceTeam_GetNumberOfBots(entity team_) +int TeamBalanceTeam_GetNumberOfPlayers(entity team_ent) { - return team_.m_num_bots; + return team_ent.m_num_players; } -entity TeamBalanceTeam_GetLowestHuman(entity team_) +int TeamBalanceTeam_GetNumberOfBots(entity team_ent) { - return team_.m_lowest_human; -} - -entity TeamBalanceTeam_GetLowestBot(entity team_) -{ - return team_.m_lowest_bot; + return team_ent.m_num_bots; } int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b, @@ -870,102 +1118,24 @@ int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b, 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 - TeamchangeFrags(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)); }