77 return team_ent.m_team_score;
82 team_ent.m_team_score = score;
87 return team_ent.m_num_players_alive;
92 team_ent.m_num_players_alive =
number;
107 return (winner ? winner : -1);
135 return (winner ? winner : -1);
140 return team_ent.m_num_owned_items;
145 team_ent.m_num_owned_items =
number;
166 this.
team = (clr & 15) + 1;
172 builtin_setcolor(
this, clr);
198 float pants = _color & 0x0F;
199 float shirt = _color & 0xF0;
202 setcolor(player, 16 * pants + pants);
213 if (player.team == new_team)
240 int numplayersqueued = 0;
243 && (checkspecificteam ? it.wants_join > 0 : it.wants_join),
245 LOG_DEBUGF(
"Player %s is waiting to join team %d", it.netname, it.wants_join);
247 if (numplayersqueued >= AVAILABLE_TEAMS - 1)
251 LOG_DEBUG(
"No players waiting to join.");
264 if (team_index != old_team_index)
272 if (team_index != -1)
275 player.team_selected = team_index;
282 if (team_index == -1)
288 CS(player).idlekick_lasttimeleft = 0;
320 return player.team_forced;
330 player.team_forced = team_index;
341 player.team_forced = team_index;
366 player.team_forced = 1;
370 player.team_forced = 2;
374 player.team_forced = 3;
378 player.team_forced = 4;
386 player.team_forced = 1;
391 player.team_forced = 2;
396 player.team_forced = 3;
401 player.team_forced = 4;
430 if (player.bot_forced_team)
437 int forced_team_index = player.team_forced;
441 if (!is_team_allowed)
464 entity team_ent = balance.m_team_balance_team[i] =
spawn();
467 team_ent.m_num_bots = 0;
470 balance.nextthink =
time;
475 teams_mask, teament_name, for_whom);
476 teams_mask =
M_ARGV(0,
float);
477 teament_name =
M_ARGV(1,
string);
478 if (mutator_returnvalue)
482 if (teams_mask &
BIT(i))
484 balance.m_team_balance_team[i].m_num_players = 0;
588 if (for_whom.team_forced == i &&
607 delete(balance.(m_team_balance_team[i]));
616 LOG_FATAL(
"Team balance entity is NULL.");
620 LOG_FATAL(
"Team balance entity is not initialized.");
661 bool equality =
true;
670 if(i > 1 && total != prev_total)
724 if(i == 1 || cur <
min)
731 if(cur > 0 && cur >
min)
740 latest_join =
CS(it).startplaytime;
780 int j, teamplayers_deficit = 0, teamplayers_max = 0;
788 if (bots_would_leave_remaining)
791 it.m_num_players -= to_remove;
792 bots_would_leave_remaining -= to_remove;
795 if (it.m_num_players > teamplayers_max)
796 teamplayers_max = it.m_num_players;
803 for (j = 1; teamplayers_deficit > 0 && j <=
maxclients; ++j)
806 if (it.wants_join <= 0 || it == ignore)
continue;
810 --teamplayers_deficit;
814 for (j = 1; teamplayers_deficit > 0 && j <=
maxclients; ++j)
817 if (it.wants_join >= 0 || it == ignore)
continue;
819 --teamplayers_deficit;
823 return teamplayers_deficit <= 0;
830 LOG_FATAL(
"Team balance entity is NULL.");
834 LOG_FATAL(
"Team balance entity is not initialized.");
850 LOG_FATAL(
"Team balance entity is NULL.");
854 LOG_FATAL(
"Team balance entity is not initialized.");
865 team_ent.m_num_players =
M_ARGV(2,
float);
866 team_ent.m_num_bots =
M_ARGV(3,
float);
883 team_num = it.killindicator_teamchange > 0 ? it.killindicator_teamchange : it.team;
903 ++team_ent.m_num_players;
906 ++team_ent.m_num_bots;
918 if (team_ent.m_num_players == team_ent.m_num_bots)
920 ++team_ent.m_num_players;
931 LOG_FATAL(
"Team balance entity is NULL.");
935 LOG_FATAL(
"TeamBalance_GetTeamCounts has not been called.");
939 LOG_FATALF(
"Team index is invalid: %f", index);
941 return balance.m_team_balance_team[index - 1].m_num_players;
948 LOG_FATAL(
"Team balance entity is NULL.");
952 LOG_FATAL(
"Team balance entity is not initialized.");
988 LOG_FATAL(
"Team balance entity is NULL.");
992 LOG_FATAL(
"TeamBalance_GetTeamCounts has not been called.");
999 int previous_team = 0;
1006 if (previous_team == 0)
1030 entity player,
bool use_score)
1032 if (balance ==
NULL)
1034 LOG_FATAL(
"Team balance entity is NULL.");
1038 LOG_FATAL(
"TeamBalance_GetTeamCounts has not been called.");
1050 if (team_index_a == team_index_b)
1069 int smallest_team_index = 0;
1070 int smallest_team_player_count = 0;
1079 if (smallest_team_index == 0)
1081 smallest_team_index = i;
1082 smallest_team_player_count = playercount;
1084 else if (playercount < smallest_team_player_count)
1086 smallest_team_index = i;
1087 smallest_team_player_count = playercount;
1098 if (smallest_team_index == largest_team_index)
1104 largest_team_index);
1107 if (largest_team_player_count - smallest_team_player_count < 2)
1115 smallest_team_index,
true);
1116 if (switchable_bot !=
NULL)
1123 if (switchable_bot ==
NULL)
1133 int largest_team_index = 0;
1134 int largest_team_player_count = 0;
1147 if (largest_team_index == 0)
1149 largest_team_index = i;
1150 largest_team_player_count = playercount;
1152 else if (playercount > largest_team_player_count)
1154 largest_team_index = i;
1155 largest_team_player_count = playercount;
1158 return largest_team_index;
1162 int destination_team_index,
bool is_bot)
1165 destination_team_index, is_bot))
1178 if (temp_score >= lowest_score)
1189 lowest_score = temp_score;
1197 return lowest_player;
1210 GameLogEcho(sprintf(
":team:%d:%d:%d", player_id, team_number, type));
1223 Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id,
DMG_NOWEP,
1224 player.origin,
'0 0 0');
1229 return balance.m_team_balance_team[index - 1].m_num_players !=
1250 return balance.m_team_balance_team[index - 1];
1265 return team_ent.m_num_players;
1270 return team_ent.m_num_bots;
1274 entity player,
bool use_score)
1276 if (team_a == team_b)
1286 int num_players_team_a = team_a.m_num_players;
1287 int num_players_team_b = team_b.m_num_players;
1291 int to_remove =
min(team_a.m_num_bots,
ceil(bots_would_leave_remaining * 0.5));
1292 num_players_team_a -= to_remove;
1293 bots_would_leave_remaining -= to_remove;
1294 num_players_team_b -=
min(team_b.m_num_bots, bots_would_leave_remaining);
1296 if (num_players_team_a < num_players_team_b)
1300 if (num_players_team_a > num_players_team_b)
1308 if (team_a.m_team_score < team_b.m_team_score)
1312 if (team_a.m_team_score > team_b.m_team_score)
1330 int human_clients = 0;
1333 if (++human_clients > 1)
int bots_would_leave
how many bots would leave so humans can replace them
#define MUTATOR_CALLHOOK(id,...)
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
int killindicator_teamchange
string playername(string thename, int teamid, bool team_colorize)
const int FRAGS_SPECTATOR
int autocvar_bot_vs_human
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
void GameLogEcho(string s)
bool autocvar_sv_eventlog
bool intermission_running
s1 s2 s1 s2 FLAG s1 s2 FLAG spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 CPID_REMOVE
s1 s2 s1 s2 FLAG s1 s2 FLAG spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 CPID_IDLING
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
#define APP_TEAM_NUM(num, prefix)
#define new_pure(class)
purely logical entities (not linked to the area grid)
ERASEABLE void RandomSelection_Init()
float RandomSelection_chosen_float
#define RandomSelection_AddFloat(f, weight, priority)
bool PlayerScore_Clear(entity player)
Initialize the score of this player if needed.
float autocvar_g_campaign_forceteam
void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
putting a client as observer in the server
bool PlayerInList(entity player, string list)
void Join(entity this, bool queued_join)
it's assumed this isn't called for bots (campaign_bots_may_start, centreprints)
float autocvar_sv_maxidle_playertospectator
#define PlayerScore_Get(player, scorefield)
Returns the player's score.
ClientState CS(Client this)
int Team_GetWinnerTeam_WithOwnedItems(int min_control_points)
Returns the winner team.
bool QueuedPlayersReady(entity this, bool checkspecificteam)
Returns true when enough players are queued that the next will join directly to the only available te...
bool TeamBalanceTeam_IsAllowed(entity team_ent)
Returns whether the team is allowed.
string autocvar_g_forced_team_red
int Entity_GetTeamIndex(entity this)
Returns the team index of the given entity.
bool TeamBalance_QueuedPlayersTagIn(entity ignore)
Joins queued player(s) to team(s) with a shortage, this should be more robust than only replacing the...
int Team_GetNumberOfAlivePlayers(entity team_ent)
Returns the number of alive players in a team.
entity Team_GetTeam(int team_num)
Returns the global team entity that corresponds to the given TEAM_NUM value.
void TeamBalance_AutoBalanceBots()
Switches a bot from one team to another if teams are not balanced.
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b, entity player, bool use_score)
Compares two teams for the purposes of game balance.
void TeamBalance_BanTeamsExcept(entity balance, int index)
Bans team change to all teams except the given one.
void TeamBalance_RemoveExcessPlayers(entity ignore)
entity Entity_GetTeam(entity this)
Returns the team entity of the given entity.
const int TEAM_NOT_ALLOWED
Indicates that the player is not allowed to join a team.
void Player_DetermineForcedTeam(entity player)
Determines the forced team of the player using current global config.
void TeamBalance_JoinBestTeam(entity player)
Assigns the given player to a team that will make the game most balanced.
bool Player_HasRealForcedTeam(entity player)
Returns whether player has real forced team.
void LogTeamChange(float player_id, float team_number, int type)
int TeamBalanceTeam_GetNumberOfPlayers(entity team_ent)
Returns the number of players (both humans and bots) in a team.
void Team_SetTeamScore(entity team_ent, float score)
Sets the score of the team.
int m_num_owned_items
Number of items owned by a team.
bool QueueNeeded(entity ignore)
int TeamBalance_GetNumberOfPlayers(entity balance, int index)
Returns the number of players (both humans and bots) in a team.
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
entity g_team_entities[NUM_TEAMS]
Holds global team entities.
int TeamBalance_GetLargestTeamIndex(entity balance, int teams)
Returns the index of the team with most players that is contained in the given bitmask of teams.
bool Player_SetTeamIndex(entity player, int index)
Sets the team of the player using its index.
@ TEAM_BALANCE_TEAM_COUNTS_FILLED
TeamBalance_GetTeamCounts has been called.
@ TEAM_BALANCE_TEAMS_CHECKED
TeamBalance_CheckAllowedTeams has been called.
@ TEAM_BALANCE_UNINITIALIZED
The team balance has not been initialized.
int TeamBalanceTeam_GetNumberOfBots(entity team_ent)
Returns the number of bots in a team.
int Team_GetNumberOfTeamsWithOwnedItems()
Returns the number of teams that own items.
void Remove_Countdown(entity this)
int m_num_bots
Number of bots in a team.
int Team_GetWinnerAliveTeam()
Returns the winner team.
void Team_SetNumberOfOwnedItems(entity team_ent, int number)
Sets the number of items owned by a team.
void SetPlayerColors(entity player, float _color)
int m_team_balance_state
Holds the state of the team balance entity.
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
string autocvar_g_forced_team_blue
int Team_GetNumberOfOwnedItems(entity team_ent)
Returns the number of items owned by a team.
int Player_GetForcedTeamIndex(entity player)
Returns the index of the forced team of the given player.
bool TeamBalance_IsTeamAllowedInternal(entity balance, int index)
Returns whether the team change to the specified team is allowed.
string autocvar_g_forced_team_yellow
string autocvar_g_forced_team_pink
int m_num_players
Number of players (both humans and bots) in a team.
float Team_GetTeamScore(entity team_ent)
Returns the score of the team.
bool Entity_HasValidTeam(entity this)
Returns whether the given entity belongs to a valid team.
int TeamBalance_GetAllowedTeams(entity balance)
Returns the bitmask of allowed teams.
int m_num_players_alive
Number of alive players in a team.
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
entity m_team_balance_team[NUM_TEAMS]
???
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
int TeamBalance_FindBestTeams(entity balance, entity player, bool use_score)
Returns the bitmask of the teams that will make the game most balanced if the player joins any of the...
bool TeamBalance_AreEqual(entity ignore, bool would_leave)
int Team_GetNumberOfAliveTeams()
Returns the number of alive teams.
void KillPlayerForTeamChange(entity player)
Kills player as a result of team change.
void Team_SetNumberOfAlivePlayers(entity team_ent, int number)
Sets the number of alive players in a team.
entity Team_GetTeamFromIndex(int index)
Returns the global team entity at the given index.
int TeamBalance_SizeDifference(entity ignore)
Returns the size difference between the largest and smallest team (bots included).
float m_team_score
The score of the team.
entity TeamBalance_GetPlayerForTeamSwitch(int source_team_index, int destination_team_index, bool is_bot)
Returns the player who is the most suitable for switching between the given teams.
void Player_SetForcedTeamIndex(entity player, int team_index)
Sets the index of the forced team of the given player.
int TeamBalance_FindBestTeam(entity balance, entity player, bool ignore_player)
Finds the team that will make the game most balanced if the player joins it.
int TeamBalance_CompareTeams(entity balance, int team_index_a, int team_index_b, entity player, bool use_score)
Compares two teams for the purposes of game balance.
entity TeamBalance_GetTeam(entity balance, int team_num)
Returns the team entity of the team balance entity that corresponds to the given TEAM_NUM value.
entity TeamBalance_GetTeamFromIndex(entity balance, int index)
Returns the team entity of the team balance entity at the given index.
bool MoveToTeam(entity client, int team_index, int type)
Moves player to the specified team.
int autocvar_g_balance_teams_remove_wait
string autocvar_g_forced_team_otherwise
bool autocvar_g_balance_teams_queue
@ TEAM_FORCE_DEFAULT
Don't force any team.
@ TEAM_FORCE_SPECTATOR
Force the player to spectator team.
@ TEAM_CHANGE_AUTO
The team was selected by autobalance.
@ TEAMS_COMPARE_INVALID
One or both teams are invalid.
@ TEAMS_COMPARE_GREATER
First team the greater than the second one.
@ TEAMS_COMPARE_LESS
First team is less than the second one.
@ TEAMS_COMPARE_EQUAL
Both teams are equal.
bool Team_IsValidTeam(int team_num)
Returns whether team value is valid.
int Team_TeamToBit(int team_num)
Converts team value into bit value that is used in team bitmasks.
bool Team_IsValidIndex(int index)
Returns whether the team index is valid.
int Team_TeamToIndex(int team_num)
Converts team value into team index.
int Team_IndexToTeam(int index)
Converts team index into team value.
const int NUM_TEAMS
Number of teams in the game.
int Team_IndexToBit(int index)
Converts team index into bit value that is used in team bitmasks.
#define IS_REAL_CLIENT(v)
#define FOREACH_CLIENT(cond, body)
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))