Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
teamplay.qh File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  { TEAM_CHANGE_AUTO = 2 , TEAM_CHANGE_MANUAL = 3 , TEAM_CHANGE_SPECTATOR = 4 }
enum  { TEAMS_COMPARE_INVALID , TEAMS_COMPARE_LESS , TEAMS_COMPARE_EQUAL , TEAMS_COMPARE_GREATER }
 Describes the result of comparing teams. More...
enum  { TEAM_FORCE_SPECTATOR = -1 , TEAM_FORCE_DEFAULT = 0 }

Functions

entity Entity_GetTeam (entity this)
 Returns the team entity of the given entity.
int Entity_GetTeamIndex (entity this)
 Returns the team index of the given entity.
bool Entity_HasValidTeam (entity this)
 Returns whether the given entity belongs to a valid team.
void KillPlayerForTeamChange (entity player)
 Kills player as a result of team change.
void LogTeamChange (float player_id, float team_number, int type)
bool MoveToTeam (entity client, int team_index, int type)
 Moves player to the specified team.
void Player_DetermineForcedTeam (entity player)
 Determines the forced team of the player using current global config.
int Player_GetForcedTeamIndex (entity player)
 Returns the index of the forced team of the given player.
bool Player_HasRealForcedTeam (entity player)
 Returns whether player has real forced team.
void Player_SetForcedTeamIndex (entity player, int team_index)
 Sets the index of the forced team of the given player.
bool Player_SetTeamIndex (entity player, int index)
 Sets the team of the player using its index.
bool QueuedPlayersReady (entity this, bool checkspecificteam)
 Returns true when enough players are queued that the next will join directly to the only available team (also triggering the joins of the queued players).
bool QueueNeeded (entity ignore)
void setcolor (entity this, int clr)
void SetPlayerColors (entity player, float _color)
bool SetPlayerTeam (entity player, int team_index, int type)
 Sets the team of the player.
void SV_ChangeTeam (entity player, int new_color)
 Called when the player changes color with the "color" command.
int Team_GetNumberOfAlivePlayers (entity team_ent)
 Returns the number of alive players in a team.
int Team_GetNumberOfAliveTeams ()
 Returns the number of alive teams.
int Team_GetNumberOfOwnedItems (entity team_ent)
 Returns the number of items owned by a team.
int Team_GetNumberOfTeamsWithOwnedItems ()
 Returns the number of teams that own items.
entity Team_GetTeam (int team_num)
 Returns the global team entity that corresponds to the given TEAM_NUM value.
entity Team_GetTeamFromIndex (int index)
 Returns the global team entity at the given index.
float Team_GetTeamScore (entity team_ent)
 Returns the score of the team.
int Team_GetWinnerAliveTeam ()
 Returns the winner team.
int Team_GetWinnerTeam_WithOwnedItems (int min_owned_items)
 Returns the winner team.
void Team_InitTeams ()
void Team_SetNumberOfAlivePlayers (entity team_ent, int number)
 Sets the number of alive players in a team.
void Team_SetNumberOfOwnedItems (entity team_ent, int number)
 Sets the number of items owned by a team.
void Team_SetTeamScore (entity team_ent, float score)
 Sets the score of the team.
bool TeamBalance_AreEqual (entity ignore, bool would_leave)
void TeamBalance_AutoBalanceBots ()
 Switches a bot from one team to another if teams are not balanced.
void TeamBalance_BanTeamsExcept (entity balance, int index)
 Bans team change to all teams except the given one.
entity TeamBalance_CheckAllowedTeams (entity for_whom)
 Checks whether the player can join teams according to global configuration and mutator settings.
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.
int TeamBalance_CompareTeamsInternal (entity team_a, entity team_index_b, entity player, bool use_score)
 Compares two teams for the purposes of game balance.
void TeamBalance_Destroy (entity balance)
 Destroy the team balance entity.
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_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 them.
int TeamBalance_GetAllowedTeams (entity balance)
 Returns the bitmask of allowed teams.
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.
int TeamBalance_GetNumberOfPlayers (entity balance, int index)
 Returns the number of players (both humans and bots) in a 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.
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.
void TeamBalance_GetTeamCounts (entity balance, entity ignore)
 Counts the number of players and various other information about each team.
entity TeamBalance_GetTeamFromIndex (entity balance, int index)
 Returns the team entity of the team balance entity at the given index.
bool TeamBalance_IsTeamAllowed (entity balance, int index)
 Returns whether the team change to the specified team is allowed.
bool TeamBalance_IsTeamAllowedInternal (entity balance, int index)
 Returns whether the team change to the specified team is allowed.
void TeamBalance_JoinBestTeam (entity player)
 Assigns the given player to a team that will make the game most balanced.
bool TeamBalance_QueuedPlayersTagIn (entity ignore)
 Joins queued player(s) to team(s) with a shortage, this should be more robust than only replacing the player that left.
void TeamBalance_RemoveExcessPlayers (entity ignore)
int TeamBalance_SizeDifference (entity ignore)
 Returns the size difference between the largest and smallest team (bots included).
int TeamBalanceTeam_GetNumberOfBots (entity team_ent)
 Returns the number of bots in a team.
int TeamBalanceTeam_GetNumberOfPlayers (entity team_ent)
 Returns the number of players (both humans and bots) in a team.
bool TeamBalanceTeam_IsAllowed (entity team_ent)
 Returns whether the team is allowed.

Variables

bool autocvar_g_balance_teams
bool autocvar_g_balance_teams_prevent_imbalance
bool autocvar_g_balance_teams_queue
bool autocvar_g_balance_teams_remove
int autocvar_g_balance_teams_remove_wait
string autocvar_g_forced_team_otherwise
bool autocvar_teamplay_lockonrestart
int autocvar_teamplay_mode
bool lockteams
int team_forced

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
TEAM_CHANGE_AUTO 

The team was selected by autobalance.

TEAM_CHANGE_MANUAL 

Player has manually selected their team.

TEAM_CHANGE_SPECTATOR 

Player is joining spectators. //TODO: Remove?

Definition at line 112 of file teamplay.qh.

113{
114 TEAM_CHANGE_AUTO = 2,
117};
@ TEAM_CHANGE_AUTO
The team was selected by autobalance.
Definition teamplay.qh:114
@ TEAM_CHANGE_MANUAL
Player has manually selected their team.
Definition teamplay.qh:115
@ TEAM_CHANGE_SPECTATOR
Player is joining spectators. //TODO: Remove?
Definition teamplay.qh:116

◆ anonymous enum

anonymous enum

Describes the result of comparing teams.

Enumerator
TEAMS_COMPARE_INVALID 

One or both teams are invalid.

TEAMS_COMPARE_LESS 

First team is less than the second one.

TEAMS_COMPARE_EQUAL 

Both teams are equal.

TEAMS_COMPARE_GREATER 

First team the greater than the second one.

Definition at line 245 of file teamplay.qh.

246{
251};
@ TEAMS_COMPARE_INVALID
One or both teams are invalid.
Definition teamplay.qh:247
@ TEAMS_COMPARE_GREATER
First team the greater than the second one.
Definition teamplay.qh:250
@ TEAMS_COMPARE_LESS
First team is less than the second one.
Definition teamplay.qh:248
@ TEAMS_COMPARE_EQUAL
Both teams are equal.
Definition teamplay.qh:249

◆ anonymous enum

anonymous enum
Enumerator
TEAM_FORCE_SPECTATOR 

Force the player to spectator team.

TEAM_FORCE_DEFAULT 

Don't force any team.

Definition at line 135 of file teamplay.qh.

136{
139};
@ TEAM_FORCE_DEFAULT
Don't force any team.
Definition teamplay.qh:138
@ TEAM_FORCE_SPECTATOR
Force the player to spectator team.
Definition teamplay.qh:137

Function Documentation

◆ Entity_GetTeam()

entity Entity_GetTeam ( entity this)

Returns the team entity of the given entity.

Parameters
[in]thisEntity to check.
Returns
Team entity of the given entity or NULL if the entity doesn't belong to any team.

Definition at line 186 of file teamplay.qc.

187{
188 int index = Entity_GetTeamIndex(this);
189 if (!Team_IsValidIndex(index))
190 {
191 return NULL;
192 }
193 return Team_GetTeamFromIndex(index);
194}
#define NULL
Definition post.qh:14
int Entity_GetTeamIndex(entity this)
Returns the team index of the given entity.
Definition teamplay.qc:181
entity Team_GetTeamFromIndex(int index)
Returns the global team entity at the given index.
Definition teamplay.qc:57
bool Team_IsValidIndex(int index)
Returns whether the team index is valid.
Definition teams.qh:151

References entity(), Entity_GetTeamIndex(), NULL, Team_GetTeamFromIndex(), and Team_IsValidIndex().

Referenced by CA_count_alive_players(), Domination_count_controlpoints(), freezetag_count_alive_players(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), and Onslaught_count_generators().

◆ Entity_GetTeamIndex()

int Entity_GetTeamIndex ( entity this)

Returns the team index of the given entity.

Parameters
[in]thisEntity to check.
Returns
Team index of the entity.

Definition at line 181 of file teamplay.qc.

182{
183 return Team_TeamToIndex(this.team);
184}
int team
Definition main.qh:188
int Team_TeamToIndex(int team_num)
Converts team value into team index.
Definition teams.qh:184

References entity(), team, and Team_TeamToIndex().

Referenced by Entity_GetTeam(), SetPlayerTeam(), shuffleteams(), and TeamBalance_GetPlayerForTeamSwitch().

◆ Entity_HasValidTeam()

bool Entity_HasValidTeam ( entity this)

Returns whether the given entity belongs to a valid team.

Parameters
[in]thisEntity to check.
Returns
True if entity belongs to a valid team, false otherwise.

Definition at line 176 of file teamplay.qc.

177{
178 return Team_IsValidTeam(this.team);
179}
bool Team_IsValidTeam(int team_num)
Returns whether team value is valid.
Definition teams.qh:133

References entity(), team, and Team_IsValidTeam().

Referenced by CA_count_alive_players(), CA_PreventStalemate(), Domination_count_controlpoints(), and freezetag_count_alive_players().

◆ KillPlayerForTeamChange()

void KillPlayerForTeamChange ( entity player)

Kills player as a result of team change.

Parameters
[in,out]playerPlayer to kill.

Definition at line 1213 of file teamplay.qc.

1214{
1215 if (IS_DEAD(player))
1216 {
1217 return;
1218 }
1219 if (MUTATOR_CALLHOOK(Player_ChangeTeamKill, player) == true)
1220 {
1221 return;
1222 }
1223 Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP,
1224 player.origin, '0 0 0');
1225}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
#define IS_DEAD(s)
Definition player.qh:245
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:503
#define DMG_NOWEP
Definition damage.qh:104

References Damage(), DMG_NOWEP, entity(), IS_DEAD, and MUTATOR_CALLHOOK.

Referenced by SetPlayerTeam().

◆ LogTeamChange()

void LogTeamChange ( float player_id,
float team_number,
int type )

Definition at line 1200 of file teamplay.qc.

1201{
1203 {
1204 return;
1205 }
1206 if (player_id < 1)
1207 {
1208 return;
1209 }
1210 GameLogEcho(sprintf(":team:%d:%d:%d", player_id, team_number, type));
1211}
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3

References autocvar_sv_eventlog, and GameLogEcho().

Referenced by SetPlayerTeam().

◆ MoveToTeam()

bool MoveToTeam ( entity client,
int team_index,
int type )

Moves player to the specified team.

Parameters
[in,out]clientClient to move.
[in]team_indexIndex of the team.
[in]type???
Returns
True on success, false otherwise.

Definition at line 299 of file teamplay.qc.

300{
301 //PrintToChatAll(sprintf("MoveToTeam: %s, %f", client.netname, team_index));
302 int lockteams_backup = lockteams; // backup any team lock
303 lockteams = 0; // disable locked teams
304 if (!SetPlayerTeam(client, team_index, type))
305 {
306 lockteams = lockteams_backup; // restore the team lock
307 return false;
308 }
309 lockteams = lockteams_backup; // restore the team lock
310 return true;
311}
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
Definition teamplay.qc:255
bool lockteams
Definition teamplay.qh:15

References entity(), lockteams, and SetPlayerTeam().

Referenced by GameCommand_moveplayer(), MatchEnd_RestoreSpectatorAndTeamStatus(), and shuffleteams().

◆ Player_DetermineForcedTeam()

void Player_DetermineForcedTeam ( entity player)

Determines the forced team of the player using current global config.

Parameters
[in,out]playerPlayer to adjust.

Definition at line 348 of file teamplay.qc.

349{
351 {
352 if (IS_REAL_CLIENT(player)) // only players, not bots
353 {
355 {
356 player.team_forced = autocvar_g_campaign_forceteam;
357 }
358 else
359 {
360 player.team_forced = TEAM_FORCE_DEFAULT;
361 }
362 }
363 }
365 {
366 player.team_forced = 1;
367 }
369 {
370 player.team_forced = 2;
371 }
373 {
374 player.team_forced = 3;
375 }
377 {
378 player.team_forced = 4;
379 }
380 else
381 {
383 {
384 case "red":
385 {
386 player.team_forced = 1;
387 break;
388 }
389 case "blue":
390 {
391 player.team_forced = 2;
392 break;
393 }
394 case "yellow":
395 {
396 player.team_forced = 3;
397 break;
398 }
399 case "pink":
400 {
401 player.team_forced = 4;
402 break;
403 }
404 case "spectate":
405 case "spectator":
406 {
407 player.team_forced = TEAM_FORCE_SPECTATOR;
408 break;
409 }
410 default:
411 {
412 player.team_forced = TEAM_FORCE_DEFAULT;
413 break;
414 }
415 }
416 }
417 if (!teamplay && Player_HasRealForcedTeam(player))
418 {
419 player.team_forced = TEAM_FORCE_DEFAULT;
420 }
421}
bool autocvar_g_campaign
Definition menu.qc:747
float autocvar_g_campaign_forceteam
Definition campaign.qh:7
bool PlayerInList(entity player, string list)
Definition client.qc:1045
string autocvar_g_forced_team_red
Definition teamplay.qc:40
bool Player_HasRealForcedTeam(entity player)
Returns whether player has real forced team.
Definition teamplay.qc:313
string autocvar_g_forced_team_blue
Definition teamplay.qc:41
string autocvar_g_forced_team_yellow
Definition teamplay.qc:42
string autocvar_g_forced_team_pink
Definition teamplay.qc:43
string autocvar_g_forced_team_otherwise
Definition teamplay.qh:13
bool teamplay
Definition teams.qh:59
#define IS_REAL_CLIENT(v)
Definition utils.qh:17

References autocvar_g_campaign, autocvar_g_campaign_forceteam, autocvar_g_forced_team_blue, autocvar_g_forced_team_otherwise, autocvar_g_forced_team_pink, autocvar_g_forced_team_red, autocvar_g_forced_team_yellow, entity(), IS_REAL_CLIENT, Player_HasRealForcedTeam(), PlayerInList(), TEAM_FORCE_DEFAULT, TEAM_FORCE_SPECTATOR, Team_IsValidIndex(), and teamplay.

Referenced by ClientConnect().

◆ Player_GetForcedTeamIndex()

int Player_GetForcedTeamIndex ( entity player)

Returns the index of the forced team of the given player.

Parameters
[in]playerPlayer to check.
Returns
Index of the forced team.

Definition at line 318 of file teamplay.qc.

319{
320 return player.team_forced;
321}

References entity().

Referenced by ClientCommand_clientversion(), ClientCommand_selectteam(), GameCommand_moveplayer(), joinAllowed(), and PlayerPreThink().

◆ Player_HasRealForcedTeam()

bool Player_HasRealForcedTeam ( entity player)

Returns whether player has real forced team.

Spectator team is ignored.

Parameters
[in]playerPlayer to check.
Returns
True if player has real forced team, false otherwise.

Definition at line 313 of file teamplay.qc.

314{
315 return player.team_forced > TEAM_FORCE_DEFAULT;
316}

References entity(), and TEAM_FORCE_DEFAULT.

Referenced by Player_DetermineForcedTeam(), ShowTeamSelection(), shuffleteams(), TeamBalance_GetTeamCounts(), and TeamBalance_JoinBestTeam().

◆ Player_SetForcedTeamIndex()

void Player_SetForcedTeamIndex ( entity player,
int team_index )

Sets the index of the forced team of the given player.

Parameters
[in,out]playerPlayer to adjust.
[in]team_indexIndex of the team to set.

Definition at line 323 of file teamplay.qc.

324{
325 switch (team_index)
326 {
329 {
330 player.team_forced = team_index;
331 break;
332 }
333 default:
334 {
335 if (!Team_IsValidIndex(team_index))
336 {
337 LOG_FATAL("Invalid team index.");
338 }
339 else
340 {
341 player.team_forced = team_index;
342 break;
343 }
344 }
345 }
346}
#define LOG_FATAL(...)
Definition log.qh:53

References entity(), LOG_FATAL, TEAM_FORCE_DEFAULT, TEAM_FORCE_SPECTATOR, and Team_IsValidIndex().

Referenced by GameCommand_moveplayer(), MatchEnd_RestoreSpectatorAndTeamStatus(), minigame_addplayer(), and player_clear_minigame().

◆ Player_SetTeamIndex()

bool Player_SetTeamIndex ( entity player,
int index )

Sets the team of the player using its index.

Parameters
[in,out]playerPlayer to adjust.
[in]indexIndex of the team to set.
Returns
True if team switch was successful, false otherwise.

Definition at line 210 of file teamplay.qc.

211{
212 int new_team = Team_IndexToTeam(index);
213 if (player.team == new_team)
214 return true;
215
216 int old_index = Team_TeamToIndex(player.team);
217 if (MUTATOR_CALLHOOK(Player_ChangeTeam, player, old_index, index) == true)
218 {
219 // Mutator has blocked team change.
220 return false;
221 }
222 if (new_team == -1)
223 {
224 player.team = -1;
225 }
226 else
227 {
228 SetPlayerColors(player, new_team - 1);
229 }
230 MUTATOR_CALLHOOK(Player_ChangedTeam, player, old_index, index);
231 return true;
232}
void SetPlayerColors(entity player, float _color)
Definition teamplay.qc:196
int Team_IndexToTeam(int index)
Converts team index into team value.
Definition teams.qh:169

References entity(), MUTATOR_CALLHOOK, SetPlayerColors(), Team_IndexToTeam(), and Team_TeamToIndex().

Referenced by SetPlayerTeam().

◆ QueuedPlayersReady()

bool QueuedPlayersReady ( entity this,
bool checkspecificteam )

Returns true when enough players are queued that the next will join directly to the only available team (also triggering the joins of the queued players).

Optionally only counts players who selected a specific team when joining the queue.

Definition at line 238 of file teamplay.qc.

239{
240 int numplayersqueued = 0;
241
242 FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != this
243 && (checkspecificteam ? it.wants_join > 0 : it.wants_join),
244 {
245 LOG_DEBUGF("Player %s is waiting to join team %d", it.netname, it.wants_join);
246 ++numplayersqueued;
247 if (numplayersqueued >= AVAILABLE_TEAMS - 1)
248 return true;
249 });
250
251 LOG_DEBUG("No players waiting to join.");
252 return false;
253}
#define LOG_DEBUG(...)
Definition log.qh:80
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50

References entity(), FOREACH_CLIENT, IS_REAL_CLIENT, and LOG_DEBUG.

Referenced by ShowTeamSelection().

◆ QueueNeeded()

bool QueueNeeded ( entity ignore)

Definition at line 1325 of file teamplay.qc.

1326{
1328 return false;
1329
1330 int human_clients = 0;
1332 {
1333 if (++human_clients > 1)
1334 return TeamBalance_AreEqual(ignore, true);
1335 });
1336 return false;
1337}
bool warmup_stage
Definition main.qh:120
bool TeamBalance_AreEqual(entity ignore, bool would_leave)
Definition teamplay.qc:656
bool autocvar_g_balance_teams_queue
Definition teamplay.qh:9

References autocvar_g_balance_teams_queue, autocvar_g_campaign, entity(), FOREACH_CLIENT, IS_REAL_CLIENT, TeamBalance_AreEqual(), teamplay, and warmup_stage.

Referenced by joinAllowed().

◆ setcolor()

void setcolor ( entity this,
int clr )

Definition at line 161 of file teamplay.qc.

162{
163#if 1
164 this.clientcolors = clr;
165 if(teamplay)
166 this.team = (clr & 15) + 1;
167 else
168 this.team = -1;
169#else
170 // sets clientcolors and team (even in FFA games)
171 // and sends notification to all clients
172 builtin_setcolor(this, clr);
173#endif
174}
clientcolors
Definition ent_cs.qc:147

References clientcolors, entity(), team, and teamplay.

◆ SetPlayerColors()

void SetPlayerColors ( entity player,
float _color )

Definition at line 196 of file teamplay.qc.

197{
198 float pants = _color & 0x0F;
199 float shirt = _color & 0xF0;
200 if (teamplay)
201 {
202 setcolor(player, 16 * pants + pants);
203 }
204 else
205 {
206 setcolor(player, shirt + pants);
207 }
208}
#define setcolor
Definition pre.qh:11

References entity(), setcolor, and teamplay.

Referenced by Player_SetTeamIndex(), and SV_ChangeTeam().

◆ SetPlayerTeam()

bool SetPlayerTeam ( entity player,
int team_index,
int type )

Sets the team of the player.

Parameters
[in,out]playerPlayer to adjust.
[in]team_indexIndex of the team to set.
[in]typeType of the team change. See TEAM_CHANGE constants.
Returns
True if team switch was successful, false otherwise.

Definition at line 255 of file teamplay.qc.

256{
257 int old_team_index = Entity_GetTeamIndex(player);
258
259 if (!Player_SetTeamIndex(player, team_index))
260 return false;
261
262 LogTeamChange(player.playerid, player.team, type);
263
264 if (team_index != old_team_index)
265 {
267 PlayerScore_Clear(player); // works only in gametypes without teams
268
269 if (!IS_BOT_CLIENT(player))
271
272 if (team_index != -1)
273 {
274 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(player.team, INFO_JOIN_PLAY_TEAM), player.netname);
275 player.team_selected = team_index; // no autoselect in Join()
276
277 if (warmup_stage)
278 ReadyCount(); // teams might be balanced now
279 }
280 }
281
282 if (team_index == -1)
283 {
284 if (autocvar_sv_maxidle_playertospectator > 0 && CS(player).idlekick_lasttimeleft)
285 {
286 // this done here so it happens even when manually speccing during the countdown
287 Kill_Notification(NOTIF_ONE_ONLY, player, MSG_CENTER, CPID_IDLING);
288 CS(player).idlekick_lasttimeleft = 0;
289 }
290 else if (!CS(player).just_joined && player.frags != FRAGS_SPECTATOR)
291 {
292 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, player.netname);
293 }
294 }
295
296 return true;
297}
const int FRAGS_SPECTATOR
Definition constants.qh:4
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
Definition all.inc:688
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
Definition all.qc:1537
#define APP_TEAM_NUM(num, prefix)
Definition all.qh:84
bool PlayerScore_Clear(entity player)
Initialize the score of this player if needed.
Definition scores.qc:285
bool just_joined
Definition client.qh:76
float autocvar_sv_maxidle_playertospectator
Definition client.qh:39
void ReadyCount()
Definition vote.qc:553
ClientState CS(Client this)
Definition state.qh:47
void TeamBalance_AutoBalanceBots()
Switches a bot from one team to another if teams are not balanced.
Definition teamplay.qc:1059
void LogTeamChange(float player_id, float team_number, int type)
Definition teamplay.qc:1200
bool Player_SetTeamIndex(entity player, int index)
Sets the team of the player using its index.
Definition teamplay.qc:210
void KillPlayerForTeamChange(entity player)
Kills player as a result of team change.
Definition teamplay.qc:1213
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15

References APP_TEAM_NUM, autocvar_sv_maxidle_playertospectator, CPID_IDLING, CS(), entity(), Entity_GetTeamIndex(), FRAGS_SPECTATOR, IS_BOT_CLIENT, just_joined, Kill_Notification(), KillPlayerForTeamChange(), LogTeamChange(), NULL, Player_SetTeamIndex(), PlayerScore_Clear(), ReadyCount(), Send_Notification(), TeamBalance_AutoBalanceBots(), and warmup_stage.

Referenced by ClientKill_Now_TeamChange(), MoveToTeam(), PutObserverInServer(), PutPlayerInServer(), TeamBalance_AutoBalanceBots(), and TeamBalance_JoinBestTeam().

◆ SV_ChangeTeam()

void SV_ChangeTeam ( entity player,
int new_color )

Called when the player changes color with the "color" command.

Note
the "color" command is always called early on player connection
Parameters
[in,out]playerPlayer that requested a new color.
[in]new_colorRequested color.

Definition at line 1319 of file teamplay.qc.

1320{
1321 if (!teamplay)
1322 SetPlayerColors(player, new_color);
1323}

References entity(), SetPlayerColors(), and teamplay.

◆ Team_GetNumberOfAlivePlayers()

int Team_GetNumberOfAlivePlayers ( entity team_ent)

Returns the number of alive players in a team.

Parameters
[in]team_entTeam entity.
Returns
Number of alive players in a team.

Definition at line 85 of file teamplay.qc.

86{
87 return team_ent.m_num_players_alive;
88}

References entity().

Referenced by CA_CheckTeams(), CA_count_alive_players(), CA_PreventStalemate(), freezetag_CheckTeams(), freezetag_count_alive_players(), MUTATOR_HOOKFUNCTION(), and MUTATOR_HOOKFUNCTION().

◆ Team_GetNumberOfAliveTeams()

int Team_GetNumberOfAliveTeams ( )

Returns the number of alive teams.

Returns
Number of alive teams.

Definition at line 110 of file teamplay.qc.

111{
112 int result = 0;
113 for (int i = 0; i < NUM_TEAMS; ++i)
114 {
116 {
117 ++result;
118 }
119 }
120 return result;
121}
entity result
Definition promise.qc:43
entity g_team_entities[NUM_TEAMS]
Holds global team entities.
Definition teamplay.qc:45
int m_num_players_alive
Number of alive players in a team.
Definition teamplay.qc:37
const int NUM_TEAMS
Number of teams in the game.
Definition teams.qh:3

References g_team_entities, m_num_players_alive, NUM_TEAMS, and result.

Referenced by CA_CheckTeams(), and freezetag_CheckTeams().

◆ Team_GetNumberOfOwnedItems()

int Team_GetNumberOfOwnedItems ( entity team_ent)

Returns the number of items owned by a team.

Parameters
[in]team_entTeam entity.
Returns
Number of items owned by a team.

Definition at line 138 of file teamplay.qc.

139{
140 return team_ent.m_num_owned_items;
141}

References entity().

Referenced by Domination_count_controlpoints(), and Onslaught_count_generators().

◆ Team_GetNumberOfTeamsWithOwnedItems()

int Team_GetNumberOfTeamsWithOwnedItems ( )

Returns the number of teams that own items.

Returns
Number of teams that own items.

Definition at line 148 of file teamplay.qc.

149{
150 int result = 0;
151 for (int i = 0; i < NUM_TEAMS; ++i)
152 {
154 {
155 ++result;
156 }
157 }
158 return result;
159}
int m_num_owned_items
Number of items owned by a team.
Definition teamplay.qc:38

References g_team_entities, m_num_owned_items, NUM_TEAMS, and result.

◆ Team_GetTeam()

entity Team_GetTeam ( int team_num)

Returns the global team entity that corresponds to the given TEAM_NUM value.

Parameters
[in]team_numTeam value. See TEAM_NUM constants.
Returns
Global team entity that corresponds to the given TEAM_NUM value.

Definition at line 66 of file teamplay.qc.

67{
68 if (!Team_IsValidTeam(team_num))
69 {
70 LOG_FATALF("Value is invalid: %f", team_num);
71 }
72 return g_team_entities[Team_TeamToIndex(team_num) - 1];
73}
#define LOG_FATALF(...)
Definition log.qh:54

References entity(), g_team_entities, LOG_FATALF, Team_IsValidTeam(), and Team_TeamToIndex().

Referenced by CA_PreventStalemate(), and WinningCondition_RanOutOfSpawns().

◆ Team_GetTeamFromIndex()

entity Team_GetTeamFromIndex ( int index)

Returns the global team entity at the given index.

Parameters
[in]indexIndex of the team.
Returns
Global team entity at the given index.

Definition at line 57 of file teamplay.qc.

58{
59 if (!Team_IsValidIndex(index))
60 {
61 LOG_FATALF("Index is invalid: %f", index);
62 }
63 return g_team_entities[index - 1];
64}

References entity(), g_team_entities, LOG_FATALF, and Team_IsValidIndex().

Referenced by CA_CheckTeams(), CA_count_alive_players(), CA_PreventStalemate(), Domination_count_controlpoints(), Entity_GetTeam(), freezetag_CheckTeams(), freezetag_count_alive_players(), Onslaught_count_generators(), WinningCondition_RanOutOfSpawns(), and WinningCondition_Scores().

◆ Team_GetTeamScore()

float Team_GetTeamScore ( entity team_ent)

Returns the score of the team.

Parameters
[in]team_entTeam entity.
Returns
Score of the team.

Definition at line 75 of file teamplay.qc.

76{
77 return team_ent.m_team_score;
78}

References entity().

Referenced by WinningCondition_RanOutOfSpawns().

◆ Team_GetWinnerAliveTeam()

int Team_GetWinnerAliveTeam ( )

Returns the winner team.

Returns
Winner team or 0 if 2 or more teams have alive players or -1 if no team has any alive players.

Definition at line 95 of file teamplay.qc.

96{
97 int winner = 0;
98 for (int i = 0; i < NUM_TEAMS; ++i)
99 {
101 {
102 if (winner)
103 return 0;
104 winner = Team_IndexToTeam(i + 1);
105 }
106 }
107 return (winner ? winner : -1);
108}

References g_team_entities, m_num_players_alive, NUM_TEAMS, and Team_IndexToTeam().

Referenced by CA_CheckWinner(), and freezetag_CheckWinner().

◆ Team_GetWinnerTeam_WithOwnedItems()

int Team_GetWinnerTeam_WithOwnedItems ( int min_owned_items)

Returns the winner team.

Parameters
[in]min_owned_itemsMinimum number of items the winner team must have.
Returns
Winner team or 0 if 2 or more teams own items or -1 if no team own any items.

Definition at line 123 of file teamplay.qc.

124{
125 int winner = 0;
126 for (int i = 0; i < NUM_TEAMS; ++i)
127 {
128 if (g_team_entities[i].m_num_owned_items >= min_control_points)
129 {
130 if (winner)
131 return 0;
132 winner = Team_IndexToTeam(i + 1);
133 }
134 }
135 return (winner ? winner : -1);
136}

References g_team_entities, m_num_owned_items, NUM_TEAMS, and Team_IndexToTeam().

Referenced by Domination_CheckWinner(), and Onslaught_CheckWinner().

◆ Team_InitTeams()

void Team_InitTeams ( )

Definition at line 47 of file teamplay.qc.

48{
49 if (g_team_entities[0])
50 return;
51 for (int i = 0; i < NUM_TEAMS; ++i)
52 {
53 g_team_entities[i] = new_pure(team_entity);
54 }
55}
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67

References g_team_entities, new_pure, and NUM_TEAMS.

Referenced by GameRules_teams().

◆ Team_SetNumberOfAlivePlayers()

void Team_SetNumberOfAlivePlayers ( entity team_ent,
int number )

Sets the number of alive players in a team.

Parameters
[in,out]team_entTeam entity.
[in]numberNumber of players to set.

Definition at line 90 of file teamplay.qc.

91{
92 team_ent.m_num_players_alive = number;
93}
int int number
Definition impulse.qc:89

References entity(), and number.

Referenced by CA_count_alive_players(), and freezetag_count_alive_players().

◆ Team_SetNumberOfOwnedItems()

void Team_SetNumberOfOwnedItems ( entity team_ent,
int number )

Sets the number of items owned by a team.

Parameters
[in,out]team_entTeam entity.
[in]numberNumber of items to set.

Definition at line 143 of file teamplay.qc.

144{
145 team_ent.m_num_owned_items = number;
146}

References entity(), and number.

Referenced by Domination_count_controlpoints(), and Onslaught_count_generators().

◆ Team_SetTeamScore()

void Team_SetTeamScore ( entity team_ent,
float score )

Sets the score of the team.

Parameters
[in,out]team_entTeam entity.
[in]scoreScore to set.

Definition at line 80 of file teamplay.qc.

81{
82 team_ent.m_team_score = score;
83}

References entity().

Referenced by WinningCondition_RanOutOfSpawns(), and WinningCondition_Scores().

◆ TeamBalance_AreEqual()

bool TeamBalance_AreEqual ( entity ignore,
bool would_leave )

Definition at line 656 of file teamplay.qc.

657{
658 entity balance = TeamBalance_CheckAllowedTeams(ignore);
659 TeamBalance_GetTeamCounts(balance, ignore);
660
661 bool equality = true;
662 int total;
663 int prev_total = 0;
664 int bots = 0;
665
666 for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
667 {
668 total = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
669 bots += TeamBalance_GetTeamFromIndex(balance, i).m_num_bots;
670 if(i > 1 && total != prev_total)
671 {
672 equality = false;
673 break;
674 }
675 prev_total = total;
676 }
677 TeamBalance_Destroy(balance);
678
679 // Ignore if there are "ghost" bots that would leave if anyone joined
680 if (would_leave && bots_would_leave)
681 return false;
682
683 return equality;
684}
int bots_would_leave
how many bots would leave so humans can replace them
Definition api.qh:101
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define AVAILABLE_TEAMS
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:599
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
Definition teamplay.qc:846
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:459
entity TeamBalance_GetTeamFromIndex(entity balance, int index)
Returns the team entity of the team balance entity at the given index.
Definition teamplay.qc:1244

References AVAILABLE_TEAMS, bots_would_leave, entity(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetTeamCounts(), and TeamBalance_GetTeamFromIndex().

Referenced by Join(), QueueNeeded(), and Remove_Countdown().

◆ TeamBalance_AutoBalanceBots()

void TeamBalance_AutoBalanceBots ( )

Switches a bot from one team to another if teams are not balanced.

Definition at line 1059 of file teamplay.qc.

1060{
1061 // checks disabled because we always want auto-balanced bots
1062 //if (!autocvar_g_balance_teams_prevent_imbalance)
1063 // return;
1064
1065 if (intermission_running) return;
1066
1069 int smallest_team_index = 0;
1070 int smallest_team_player_count = 0;
1071 for (int i = 1; i <= NUM_TEAMS; ++i)
1072 {
1073 entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
1074 if (!TeamBalanceTeam_IsAllowed(team_))
1075 {
1076 continue;
1077 }
1078 int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_);
1079 if (smallest_team_index == 0)
1080 {
1081 smallest_team_index = i;
1082 smallest_team_player_count = playercount;
1083 }
1084 else if (playercount < smallest_team_player_count)
1085 {
1086 smallest_team_index = i;
1087 smallest_team_player_count = playercount;
1088 }
1089 }
1090 //PrintToChatAll(sprintf("Smallest team: %f", smallest_team_index));
1091 //PrintToChatAll(sprintf("Smallest team players: %f", smallest_team_player_count));
1092 entity switchable_bot = NULL;
1093 int teams = BITS(NUM_TEAMS);
1094 while (teams != 0)
1095 {
1096 int largest_team_index = TeamBalance_GetLargestTeamIndex(balance,
1097 teams);
1098 if (smallest_team_index == largest_team_index)
1099 {
1100 TeamBalance_Destroy(balance);
1101 return;
1102 }
1103 entity largest_team = TeamBalance_GetTeamFromIndex(balance,
1104 largest_team_index);
1105 int largest_team_player_count = TeamBalanceTeam_GetNumberOfPlayers(
1106 largest_team);
1107 if (largest_team_player_count - smallest_team_player_count < 2)
1108 {
1109 TeamBalance_Destroy(balance);
1110 return;
1111 }
1112 //PrintToChatAll(sprintf("Largest team: %f", largest_team_index));
1113 //PrintToChatAll(sprintf("Largest team players: %f", largest_team_player_count));
1114 switchable_bot = TeamBalance_GetPlayerForTeamSwitch(largest_team_index,
1115 smallest_team_index, true);
1116 if (switchable_bot != NULL)
1117 {
1118 break;
1119 }
1120 teams &= ~Team_IndexToBit(largest_team_index);
1121 }
1122 TeamBalance_Destroy(balance);
1123 if (switchable_bot == NULL)
1124 {
1125 //PrintToChatAll("No bot found after searching through all the teams");
1126 return;
1127 }
1128 SetPlayerTeam(switchable_bot, smallest_team_index, TEAM_CHANGE_AUTO);
1129}
#define BITS(n)
Definition bits.qh:9
entity teams
Definition main.qh:58
bool intermission_running
bool TeamBalanceTeam_IsAllowed(entity team_ent)
Returns whether the team is allowed.
Definition teamplay.qc:1258
int TeamBalanceTeam_GetNumberOfPlayers(entity team_ent)
Returns the number of players (both humans and bots) in a team.
Definition teamplay.qc:1263
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.
Definition teamplay.qc:1131
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.
Definition teamplay.qc:1161
int Team_IndexToBit(int index)
Converts team index into bit value that is used in team bitmasks.
Definition teams.qh:211

References BITS, entity(), intermission_running, NULL, NUM_TEAMS, SetPlayerTeam(), TEAM_CHANGE_AUTO, Team_IndexToBit(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetLargestTeamIndex(), TeamBalance_GetPlayerForTeamSwitch(), TeamBalance_GetTeamCounts(), TeamBalance_GetTeamFromIndex(), TeamBalanceTeam_GetNumberOfPlayers(), TeamBalanceTeam_IsAllowed(), and teams.

Referenced by SetPlayerTeam().

◆ TeamBalance_BanTeamsExcept()

void TeamBalance_BanTeamsExcept ( entity balance,
int index )

Bans team change to all teams except the given one.

Parameters
[in,out]balanceTeam balance entity.
[in]indexIndex of the team.

Definition at line 1233 of file teamplay.qc.

1234{
1235 for (int i = 1; i <= NUM_TEAMS; ++i)
1236 {
1237 if (i != index)
1238 {
1239 balance.m_team_balance_team[i - 1].m_num_players = TEAM_NOT_ALLOWED;
1240 }
1241 }
1242}
const int TEAM_NOT_ALLOWED
Indicates that the player is not allowed to join a team.
Definition teamplay.qc:29

References entity(), NUM_TEAMS, and TEAM_NOT_ALLOWED.

Referenced by TeamBalance_CheckAllowedTeams().

◆ TeamBalance_CheckAllowedTeams()

entity TeamBalance_CheckAllowedTeams ( entity for_whom)

Checks whether the player can join teams according to global configuration and mutator settings.

Parameters
[in]for_whomPlayer to check for. Pass NULL for global rules.
Returns
Team balance entity that holds information about teams. This entity will be automatically destroyed on the next frame but you are encouraged to manually destroy it by calling TeamBalance_Destroy for performance reasons.

Definition at line 459 of file teamplay.qc.

460{
461 entity balance = spawn();
462 for (int i = 0; i < NUM_TEAMS; ++i)
463 {
464 entity team_ent = balance.m_team_balance_team[i] = spawn();
465 team_ent.m_team_score = g_team_entities[i].m_team_score;
466 team_ent.m_num_players = TEAM_NOT_ALLOWED;
467 team_ent.m_num_bots = 0;
468 }
470 balance.nextthink = time;
471
472 int teams_mask = 0;
473 string teament_name = string_null;
474 bool mutator_returnvalue = MUTATOR_CALLHOOK(TeamBalance_CheckAllowedTeams,
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)
479 {
480 for (int i = 0; i < NUM_TEAMS; ++i)
481 {
482 if (teams_mask & BIT(i))
483 {
484 balance.m_team_balance_team[i].m_num_players = 0;
485 }
486 }
487 }
488
489 if (teament_name)
490 {
491 entity head = find(NULL, classname, teament_name);
492 while (head)
493 {
494 if (Team_IsValidTeam(head.team))
495 {
496 TeamBalance_GetTeam(balance, head.team).m_num_players = 0;
497 }
498 head = find(head, classname, teament_name);
499 }
500 }
501
502 // TODO: Balance quantity of bots across > 2 teams when bot_vs_human is set (and remove next line)
503 if (autocvar_bot_vs_human && AVAILABLE_TEAMS == 2 && for_whom)
504 {
505 if (autocvar_bot_vs_human > 0)
506 {
507 // find last team available
508 if (IS_BOT_CLIENT(for_whom))
509 {
510 if (TeamBalance_IsTeamAllowedInternal(balance, 4))
511 {
512 TeamBalance_BanTeamsExcept(balance, 4);
513 }
514 else if (TeamBalance_IsTeamAllowedInternal(balance, 3))
515 {
516 TeamBalance_BanTeamsExcept(balance, 3);
517 }
518 else
519 {
520 TeamBalance_BanTeamsExcept(balance, 2);
521 }
522 // no further cases, we know at least 2 teams exist
523 }
524 else
525 {
526 if (TeamBalance_IsTeamAllowedInternal(balance, 1))
527 {
528 TeamBalance_BanTeamsExcept(balance, 1);
529 }
530 else if (TeamBalance_IsTeamAllowedInternal(balance, 2))
531 {
532 TeamBalance_BanTeamsExcept(balance, 2);
533 }
534 else
535 {
536 TeamBalance_BanTeamsExcept(balance, 3);
537 }
538 // no further cases, bots have one of the teams
539 }
540 }
541 else
542 {
543 // find first team available
544 if (IS_BOT_CLIENT(for_whom))
545 {
546 if (TeamBalance_IsTeamAllowedInternal(balance, 1))
547 {
548 TeamBalance_BanTeamsExcept(balance, 1);
549 }
550 else if (TeamBalance_IsTeamAllowedInternal(balance, 2))
551 {
552 TeamBalance_BanTeamsExcept(balance, 2);
553 }
554 else
555 {
556 TeamBalance_BanTeamsExcept(balance, 3);
557 }
558 // no further cases, we know at least 2 teams exist
559 }
560 else
561 {
562 if (TeamBalance_IsTeamAllowedInternal(balance, 4))
563 {
564 TeamBalance_BanTeamsExcept(balance, 4);
565 }
566 else if (TeamBalance_IsTeamAllowedInternal(balance, 3))
567 {
568 TeamBalance_BanTeamsExcept(balance, 3);
569 }
570 else
571 {
572 TeamBalance_BanTeamsExcept(balance, 2);
573 }
574 // no further cases, bots have one of the teams
575 }
576 }
577 }
578
579 if (!for_whom)
580 {
581 balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED;
582 return balance;
583 }
584
585 // if player has a forced team, ONLY allow that one
586 for (int i = 1; i <= NUM_TEAMS; ++i)
587 {
588 if (for_whom.team_forced == i &&
590 {
591 TeamBalance_BanTeamsExcept(balance, i);
592 break;
593 }
594 }
595 balance.m_team_balance_state = TEAM_BALANCE_TEAMS_CHECKED;
596 return balance;
597}
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
#define M_ARGV(x, type)
Definition events.qh:17
string classname
float time
#define spawn
int autocvar_bot_vs_human
Definition cvars.qh:67
entity find(entity start,.string field, string match)
string string_null
Definition nil.qh:9
#define setthink(e, f)
void TeamBalance_BanTeamsExcept(entity balance, int index)
Bans team change to all teams except the given one.
Definition teamplay.qc:1233
@ TEAM_BALANCE_TEAMS_CHECKED
TeamBalance_CheckAllowedTeams has been called.
Definition teamplay.qc:23
bool TeamBalance_IsTeamAllowedInternal(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition teamplay.qc:1227
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.
Definition teamplay.qc:1253

References autocvar_bot_vs_human, AVAILABLE_TEAMS, BIT, classname, entity(), find(), g_team_entities, IS_BOT_CLIENT, M_ARGV, MUTATOR_CALLHOOK, NULL, NUM_TEAMS, setthink, spawn, string_null, TEAM_BALANCE_TEAMS_CHECKED, Team_IsValidTeam(), TEAM_NOT_ALLOWED, TeamBalance_BanTeamsExcept(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetTeam(), TeamBalance_IsTeamAllowedInternal(), and time.

Referenced by adjust_respawntime(), bot_removefromlargestteam(), bot_setnameandstuff(), ClientCommand_selectteam(), ClientConnect(), ClientKill_TeamChange(), dom_DelayedInit(), GameCommand_moveplayer(), MUTATOR_HOOKABLE(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), MUTATOR_HOOKFUNCTION(), ons_ScoreRules(), ScoreRules_generic(), shuffleteams(), TeamBalance_AreEqual(), TeamBalance_AutoBalanceBots(), TeamBalance_CheckAllowedTeams(), TeamBalance_GetPlayerForTeamSwitch(), TeamBalance_JoinBestTeam(), TeamBalance_QueuedPlayersTagIn(), TeamBalance_RemoveExcessPlayers(), TeamBalance_SizeDifference(), and WinningCondition_RanOutOfSpawns().

◆ TeamBalance_CompareTeams()

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.

Parameters
[in]balanceTeam balance entity.
[in]team_index_aIndex of the first team.
[in]team_index_bIndex of the second team.
[in]playerPlayer to check.
[in]use_scoreWhether to take into account team scores.
Returns
TEAMS_COMPARE value. See above.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 1029 of file teamplay.qc.

1031{
1032 if (balance == NULL)
1033 {
1034 LOG_FATAL("Team balance entity is NULL.");
1035 }
1036 if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
1037 {
1038 LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
1039 }
1040 if (!Team_IsValidIndex(team_index_a))
1041 {
1042 LOG_FATALF("team_index_a is invalid: %f",
1043 team_index_a);
1044 }
1045 if (!Team_IsValidIndex(team_index_b))
1046 {
1047 LOG_FATALF("team_index_b is invalid: %f",
1048 team_index_b);
1049 }
1050 if (team_index_a == team_index_b)
1051 {
1052 return TEAMS_COMPARE_EQUAL;
1053 }
1054 entity team_a = TeamBalance_GetTeamFromIndex(balance, team_index_a);
1055 entity team_b = TeamBalance_GetTeamFromIndex(balance, team_index_b);
1056 return TeamBalance_CompareTeamsInternal(team_a, team_b, player, use_score);
1057}
int TeamBalance_CompareTeamsInternal(entity team_a, entity team_b, entity player, bool use_score)
Compares two teams for the purposes of game balance.
Definition teamplay.qc:1273
@ TEAM_BALANCE_TEAM_COUNTS_FILLED
TeamBalance_GetTeamCounts has been called.
Definition teamplay.qc:25

References entity(), LOG_FATAL, LOG_FATALF, NULL, TEAM_BALANCE_TEAM_COUNTS_FILLED, Team_IsValidIndex(), TeamBalance_CompareTeamsInternal(), TeamBalance_GetTeamFromIndex(), and TEAMS_COMPARE_EQUAL.

Referenced by TeamBalance_FindBestTeams().

◆ TeamBalance_CompareTeamsInternal()

int TeamBalance_CompareTeamsInternal ( entity team_a,
entity team_index_b,
entity player,
bool use_score )

Compares two teams for the purposes of game balance.

Parameters
[in]team_aFirst team.
[in]team_bSecond team.
[in]playerPlayer to check.
[in]use_scoreWhether to take into account team scores.
Returns
TEAMS_COMPARE value. See above.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 1273 of file teamplay.qc.

1275{
1276 if (team_a == team_b)
1277 {
1278 return TEAMS_COMPARE_EQUAL;
1279 }
1280 if (!TeamBalanceTeam_IsAllowed(team_a) ||
1282 {
1283 return TEAMS_COMPARE_INVALID;
1284 }
1285 // deduct bots that would leave if a player joined their team, distributing the deductions between teams
1286 int num_players_team_a = team_a.m_num_players;
1287 int num_players_team_b = team_b.m_num_players;
1288 if (IS_REAL_CLIENT(player) && bots_would_leave)
1289 {
1290 int bots_would_leave_remaining = bots_would_leave;
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);
1295 }
1296 if (num_players_team_a < num_players_team_b)
1297 {
1298 return TEAMS_COMPARE_LESS;
1299 }
1300 if (num_players_team_a > num_players_team_b)
1301 {
1302 return TEAMS_COMPARE_GREATER;
1303 }
1304 if (!use_score)
1305 {
1306 return TEAMS_COMPARE_EQUAL;
1307 }
1308 if (team_a.m_team_score < team_b.m_team_score)
1309 {
1310 return TEAMS_COMPARE_LESS;
1311 }
1312 if (team_a.m_team_score > team_b.m_team_score)
1313 {
1314 return TEAMS_COMPARE_GREATER;
1315 }
1316 return TEAMS_COMPARE_EQUAL;
1317}
float ceil(float f)
float min(float f,...)

References bots_would_leave, ceil(), entity(), IS_REAL_CLIENT, min(), TeamBalanceTeam_IsAllowed(), TEAMS_COMPARE_EQUAL, TEAMS_COMPARE_GREATER, TEAMS_COMPARE_INVALID, and TEAMS_COMPARE_LESS.

Referenced by TeamBalance_CompareTeams().

◆ TeamBalance_Destroy()

void TeamBalance_Destroy ( entity balance)

Destroy the team balance entity.

Parameters
[in,out]balanceTeam balance entity to destroy.
Note
Team balance entity is allowed to be NULL.

Definition at line 599 of file teamplay.qc.

600{
601 if (balance == NULL)
602 {
603 return;
604 }
605 for (int i = 0; i < NUM_TEAMS; ++i)
606 {
607 delete(balance.(m_team_balance_team[i]));
608 }
609 delete(balance);
610}

References entity(), NULL, and NUM_TEAMS.

Referenced by adjust_respawntime(), bot_setnameandstuff(), ClientCommand_selectteam(), ClientConnect(), ClientKill_TeamChange(), dom_DelayedInit(), GameCommand_moveplayer(), ons_ScoreRules(), ScoreRules_generic(), shuffleteams(), TeamBalance_AreEqual(), TeamBalance_AutoBalanceBots(), TeamBalance_CheckAllowedTeams(), TeamBalance_GetPlayerForTeamSwitch(), TeamBalance_JoinBestTeam(), TeamBalance_QueuedPlayersTagIn(), TeamBalance_RemoveExcessPlayers(), and TeamBalance_SizeDifference().

◆ TeamBalance_FindBestTeam()

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.

Parameters
[in]balanceTeam balance entity.
[in]playerPlayer to check.
[in]ignore_player???
Returns
Index of the team that will make the game most balanced if the player joins it. If there are several equally good teams available the function will pick a random one, unless the player is already on one of them in which case that one is returned.

Definition at line 944 of file teamplay.qc.

945{
946 if (balance == NULL)
947 {
948 LOG_FATAL("Team balance entity is NULL.");
949 }
950 if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
951 {
952 LOG_FATAL("Team balance entity is not initialized.");
953 }
954 // count how many players are in each team
955 if (ignore_player)
956 {
957 TeamBalance_GetTeamCounts(balance, player);
958 }
959 else
960 {
962 }
963 int team_bits = TeamBalance_FindBestTeams(balance, player, true);
964 if (team_bits == 0)
965 {
966 LOG_FATALF("No teams available for %s\n", GetGametype());
967 }
968
969 // don't punish players for UI mistakes by changing teams randomly when already on a best team
970 if (player.team > 0 && (team_bits & Team_TeamToBit(player.team)))
971 return Team_TeamToIndex(player.team);
972
974 for (int i = 1; i <= NUM_TEAMS; ++i)
975 {
976 if (team_bits & Team_IndexToBit(i))
977 {
979 }
980 }
982}
string GetGametype()
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
float RandomSelection_chosen_float
Definition random.qh:6
#define RandomSelection_AddFloat(f, weight, priority)
Definition random.qh:15
@ TEAM_BALANCE_UNINITIALIZED
The team balance has not been initialized.
Definition teamplay.qc:21
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...
Definition teamplay.qc:984
int Team_TeamToBit(int team_num)
Converts team value into bit value that is used in team bitmasks.
Definition teams.qh:199

References entity(), GetGametype(), LOG_FATAL, LOG_FATALF, NULL, NUM_TEAMS, RandomSelection_AddFloat, RandomSelection_chosen_float, RandomSelection_Init(), TEAM_BALANCE_UNINITIALIZED, Team_IndexToBit(), Team_TeamToBit(), Team_TeamToIndex(), TeamBalance_FindBestTeams(), and TeamBalance_GetTeamCounts().

Referenced by ClientKill_TeamChange(), GameCommand_moveplayer(), and TeamBalance_JoinBestTeam().

◆ TeamBalance_FindBestTeams()

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 them.

Parameters
[in]balanceTeam balance entity.
[in]playerPlayer to check.
[in]use_scoreWhether to take into account team scores.
Returns
Bitmask of the teams that will make the game most balanced if the player joins any of them.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 984 of file teamplay.qc.

985{
986 if (balance == NULL)
987 {
988 LOG_FATAL("Team balance entity is NULL.");
989 }
990 if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
991 {
992 LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
993 }
994 if (MUTATOR_CALLHOOK(TeamBalance_FindBestTeams, player) == true)
995 {
996 return M_ARGV(1, float);
997 }
998 int team_bits = 0;
999 int previous_team = 0;
1000 for (int i = 1; i <= NUM_TEAMS; ++i)
1001 {
1002 if (!TeamBalance_IsTeamAllowedInternal(balance, i))
1003 {
1004 continue;
1005 }
1006 if (previous_team == 0)
1007 {
1008 team_bits = Team_IndexToBit(i);
1009 previous_team = i;
1010 continue;
1011 }
1012 int compare = TeamBalance_CompareTeams(balance, i, previous_team,
1013 player, use_score);
1014 if (compare == TEAMS_COMPARE_LESS)
1015 {
1016 team_bits = Team_IndexToBit(i);
1017 previous_team = i;
1018 continue;
1019 }
1020 if (compare == TEAMS_COMPARE_EQUAL)
1021 {
1022 team_bits |= Team_IndexToBit(i);
1023 previous_team = i;
1024 }
1025 }
1026 return team_bits;
1027}
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.
Definition teamplay.qc:1029

References entity(), LOG_FATAL, M_ARGV, MUTATOR_CALLHOOK, NULL, NUM_TEAMS, TEAM_BALANCE_TEAM_COUNTS_FILLED, Team_IndexToBit(), TeamBalance_CompareTeams(), TeamBalance_FindBestTeams(), TeamBalance_IsTeamAllowedInternal(), TEAMS_COMPARE_EQUAL, and TEAMS_COMPARE_LESS.

Referenced by ClientCommand_selectteam(), MUTATOR_HOOKABLE(), TeamBalance_FindBestTeam(), and TeamBalance_FindBestTeams().

◆ TeamBalance_GetAllowedTeams()

int TeamBalance_GetAllowedTeams ( entity balance)

Returns the bitmask of allowed teams.

Parameters
[in]balanceTeam balance entity.
Returns
Bitmask of allowed teams.

Definition at line 612 of file teamplay.qc.

613{
614 if (balance == NULL)
615 {
616 LOG_FATAL("Team balance entity is NULL.");
617 }
618 if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
619 {
620 LOG_FATAL("Team balance entity is not initialized.");
621 }
622 int result = 0;
623 for (int i = 1; i <= NUM_TEAMS; ++i)
624 {
625 if (TeamBalance_IsTeamAllowedInternal(balance, i))
626 {
628 }
629 }
630 return result;
631}

References entity(), LOG_FATAL, NULL, NUM_TEAMS, result, TEAM_BALANCE_UNINITIALIZED, Team_IndexToBit(), and TeamBalance_IsTeamAllowedInternal().

Referenced by ClientConnect(), dom_DelayedInit(), ons_ScoreRules(), and ScoreRules_generic().

◆ TeamBalance_GetLargestTeamIndex()

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.

Parameters
[in]balanceTeam balance entity.
[in]teamsBitmask of teams to search in.
Returns
Index of the team with most players.

Definition at line 1131 of file teamplay.qc.

1132{
1133 int largest_team_index = 0;
1134 int largest_team_player_count = 0;
1135 for (int i = 1; i <= NUM_TEAMS; ++i)
1136 {
1137 if (!(Team_IndexToBit(i) & teams))
1138 {
1139 continue;
1140 }
1141 entity team_ = TeamBalance_GetTeamFromIndex(balance, i);
1142 if (!TeamBalanceTeam_IsAllowed(team_))
1143 {
1144 continue;
1145 }
1146 int playercount = TeamBalanceTeam_GetNumberOfPlayers(team_);
1147 if (largest_team_index == 0)
1148 {
1149 largest_team_index = i;
1150 largest_team_player_count = playercount;
1151 }
1152 else if (playercount > largest_team_player_count)
1153 {
1154 largest_team_index = i;
1155 largest_team_player_count = playercount;
1156 }
1157 }
1158 return largest_team_index;
1159}

References entity(), NUM_TEAMS, Team_IndexToBit(), TeamBalance_GetTeamFromIndex(), TeamBalanceTeam_GetNumberOfPlayers(), TeamBalanceTeam_IsAllowed(), and teams.

Referenced by TeamBalance_AutoBalanceBots().

◆ TeamBalance_GetNumberOfPlayers()

int TeamBalance_GetNumberOfPlayers ( entity balance,
int index )

Returns the number of players (both humans and bots) in a team.

Parameters
[in]balanceTeam balance entity.
[in]indexIndex of the team.
Returns
Number of player (both humans and bots) in a team.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 927 of file teamplay.qc.

928{
929 if (balance == NULL)
930 {
931 LOG_FATAL("Team balance entity is NULL.");
932 }
933 if (balance.m_team_balance_state != TEAM_BALANCE_TEAM_COUNTS_FILLED)
934 {
935 LOG_FATAL("TeamBalance_GetTeamCounts has not been called.");
936 }
937 if (!Team_IsValidIndex(index))
938 {
939 LOG_FATALF("Team index is invalid: %f", index);
940 }
941 return balance.m_team_balance_team[index - 1].m_num_players;
942}

References entity(), LOG_FATAL, LOG_FATALF, NULL, TEAM_BALANCE_TEAM_COUNTS_FILLED, and Team_IsValidIndex().

Referenced by adjust_respawntime(), and bot_setnameandstuff().

◆ TeamBalance_GetPlayerForTeamSwitch()

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.

Parameters
[in]source_team_indexIndex of the team to search in.
[in]destination_team_indexIndex of the team to switch to.
[in]is_botTrue to search for bot, false for human.
Returns
Player who is the most suitable for switching between the given teams or NULL if not found.

Definition at line 1161 of file teamplay.qc.

1163{
1165 destination_team_index, is_bot))
1166 {
1167 return M_ARGV(3, entity);
1168 }
1169 entity lowest_player = NULL;
1170 float lowest_score = FLOAT_MAX;
1171 FOREACH_CLIENT(Entity_GetTeamIndex(it) == source_team_index,
1172 {
1173 if (IS_BOT_CLIENT(it) != is_bot)
1174 {
1175 continue;
1176 }
1177 float temp_score = PlayerScore_Get(it, SP_SCORE);
1178 if (temp_score >= lowest_score)
1179 {
1180 continue;
1181 }
1182 //PrintToChatAll(sprintf(
1183 // "Found %s with lowest score, checking allowed teams", it.netname));
1185 if (TeamBalance_IsTeamAllowed(balance, source_team_index))
1186 {
1187 //PrintToChatAll("Allowed");
1188 lowest_player = it;
1189 lowest_score = temp_score;
1190 }
1191 else
1192 {
1193 //PrintToChatAll("Not allowed");
1194 }
1195 TeamBalance_Destroy(balance);
1196 });
1197 return lowest_player;
1198}
const float FLOAT_MAX
Definition float.qh:3
#define PlayerScore_Get(player, scorefield)
Returns the player's score.
Definition scores.qh:42
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition teamplay.qc:826

References entity(), Entity_GetTeamIndex(), FLOAT_MAX, FOREACH_CLIENT, IS_BOT_CLIENT, M_ARGV, MUTATOR_CALLHOOK, NULL, PlayerScore_Get, TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetPlayerForTeamSwitch(), and TeamBalance_IsTeamAllowed().

Referenced by MUTATOR_HOOKABLE(), TeamBalance_AutoBalanceBots(), and TeamBalance_GetPlayerForTeamSwitch().

◆ TeamBalance_GetTeam()

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.

Parameters
[in]balanceTeam balance entity.
[in]team_numTeam value. See TEAM_NUM constants.
Returns
Team entity of the team balance entity that corresponds to the given TEAM_NUM value.
Note
The team entities are temporary so you may write to their fields.

Definition at line 1253 of file teamplay.qc.

1254{
1255 return TeamBalance_GetTeamFromIndex(balance, Team_TeamToIndex(team_num));
1256}

References entity(), Team_TeamToIndex(), and TeamBalance_GetTeamFromIndex().

Referenced by TeamBalance_CheckAllowedTeams(), TeamBalance_GetTeamCounts(), and TeamBalance_QueuedPlayersTagIn().

◆ TeamBalance_GetTeamCounts()

void TeamBalance_GetTeamCounts ( entity balance,
entity ignore )

Counts the number of players and various other information about each team.

Parameters
[in,out]balanceTeam balance entity.
[in]ignorePlayer to ignore. This is useful if you plan to switch the player's team. Pass NULL for global information.
Note
This function updates the internal state of the team balance entity.

Definition at line 846 of file teamplay.qc.

847{
848 if (balance == NULL)
849 {
850 LOG_FATAL("Team balance entity is NULL.");
851 }
852 if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
853 {
854 LOG_FATAL("Team balance entity is not initialized.");
855 }
857 {
858 // Mutator has overriden the configuration.
859 for (int i = 1; i <= NUM_TEAMS; ++i)
860 {
861 entity team_ent = TeamBalance_GetTeamFromIndex(balance, i);
862 if (TeamBalanceTeam_IsAllowed(team_ent))
863 {
864 MUTATOR_CALLHOOK(TeamBalance_GetTeamCount, i, ignore);
865 team_ent.m_num_players = M_ARGV(2, float);
866 team_ent.m_num_bots = M_ARGV(3, float);
867 }
868 }
869 }
870 else
871 {
872 // Manually count all players.
873 FOREACH_CLIENT(true,
874 {
875 if (it == ignore)
876 {
877 continue;
878 }
879 int team_num;
880 // TODO: Reconsider when the player is truly on the team.
881 if (IS_CLIENT(it) || INGAME(it))
882 {
883 team_num = it.killindicator_teamchange > 0 ? it.killindicator_teamchange : it.team;
884 }
885 else if (Player_HasRealForcedTeam(it))
886 {
887 // Do we really need this? Probably not.
888 team_num = Team_IndexToTeam(it.team_forced); // reserve the spot
889 }
890 else
891 {
892 continue;
893 }
894 if (!Team_IsValidTeam(team_num))
895 {
896 continue;
897 }
898 entity team_ent = TeamBalance_GetTeam(balance, team_num);
899 if (!TeamBalanceTeam_IsAllowed(team_ent))
900 {
901 continue;
902 }
903 ++team_ent.m_num_players;
904 if (IS_BOT_CLIENT(it))
905 {
906 ++team_ent.m_num_bots;
907 }
908 });
909 }
910
911 // if the player who has a forced team has not joined yet, reserve the spot
913 {
915 {
916 entity team_ent = TeamBalance_GetTeamFromIndex(balance,
918 if (team_ent.m_num_players == team_ent.m_num_bots)
919 {
920 ++team_ent.m_num_players;
921 }
922 }
923 }
924 balance.m_team_balance_state = TEAM_BALANCE_TEAM_COUNTS_FILLED;
925}
#define IS_CLIENT(s)
Definition player.qh:242
#define INGAME(it)
Definition sv_rules.qh:24

References autocvar_g_campaign, autocvar_g_campaign_forceteam, entity(), FOREACH_CLIENT, INGAME, IS_BOT_CLIENT, IS_CLIENT, LOG_FATAL, M_ARGV, MUTATOR_CALLHOOK, NULL, NUM_TEAMS, Player_HasRealForcedTeam(), TEAM_BALANCE_TEAM_COUNTS_FILLED, TEAM_BALANCE_UNINITIALIZED, Team_IndexToTeam(), Team_IsValidIndex(), Team_IsValidTeam(), TeamBalance_GetTeam(), TeamBalance_GetTeamCounts(), TeamBalance_GetTeamFromIndex(), and TeamBalanceTeam_IsAllowed().

Referenced by adjust_respawntime(), bot_removefromlargestteam(), bot_setnameandstuff(), ClientCommand_selectteam(), MUTATOR_HOOKABLE(), TeamBalance_AreEqual(), TeamBalance_AutoBalanceBots(), TeamBalance_FindBestTeam(), TeamBalance_GetTeamCounts(), TeamBalance_QueuedPlayersTagIn(), TeamBalance_RemoveExcessPlayers(), and TeamBalance_SizeDifference().

◆ TeamBalance_GetTeamFromIndex()

entity TeamBalance_GetTeamFromIndex ( entity balance,
int index )

Returns the team entity of the team balance entity at the given index.

Parameters
[in]balanceTeam balance entity.
[in]indexIndex of the team.
Returns
Team entity of the team balance entity at the given index.
Note
The team entities are temporary so you may write to their fields.

Definition at line 1244 of file teamplay.qc.

1245{
1246 if (!Team_IsValidIndex(index))
1247 {
1248 LOG_FATALF("Index is invalid: %f", index);
1249 }
1250 return balance.m_team_balance_team[index - 1];
1251}

References entity(), LOG_FATALF, and Team_IsValidIndex().

Referenced by TeamBalance_AreEqual(), TeamBalance_AutoBalanceBots(), TeamBalance_CompareTeams(), TeamBalance_GetLargestTeamIndex(), TeamBalance_GetTeam(), TeamBalance_GetTeamCounts(), TeamBalance_QueuedPlayersTagIn(), TeamBalance_RemoveExcessPlayers(), and TeamBalance_SizeDifference().

◆ TeamBalance_IsTeamAllowed()

bool TeamBalance_IsTeamAllowed ( entity balance,
int index )

Returns whether the team change to the specified team is allowed.

Parameters
[in]balanceTeam balance entity.
[in]indexIndex of the team.
Returns
True if team change to the specified team is allowed, false otherwise.

Definition at line 826 of file teamplay.qc.

827{
828 if (balance == NULL)
829 {
830 LOG_FATAL("Team balance entity is NULL.");
831 }
832 if (balance.m_team_balance_state == TEAM_BALANCE_UNINITIALIZED)
833 {
834 LOG_FATAL("Team balance entity is not initialized.");
835 }
836 if (!Team_IsValidIndex(index))
837 {
838 LOG_FATALF("Team index is invalid: %f",
839 index);
840 }
841 return TeamBalance_IsTeamAllowedInternal(balance, index);
842}

References entity(), LOG_FATAL, LOG_FATALF, NULL, TEAM_BALANCE_UNINITIALIZED, Team_IsValidIndex(), and TeamBalance_IsTeamAllowedInternal().

Referenced by adjust_respawntime(), ClientCommand_selectteam(), GameCommand_moveplayer(), shuffleteams(), TeamBalance_GetPlayerForTeamSwitch(), and WinningCondition_RanOutOfSpawns().

◆ TeamBalance_IsTeamAllowedInternal()

bool TeamBalance_IsTeamAllowedInternal ( entity balance,
int index )

Returns whether the team change to the specified team is allowed.

Parameters
[in]balanceTeam balance entity.
[in]indexIndex of the team.
Returns
True if team change to the specified team is allowed, false otherwise.
Note
This function bypasses all the sanity checks.

Definition at line 1227 of file teamplay.qc.

1228{
1229 return balance.m_team_balance_team[index - 1].m_num_players !=
1231}

References entity(), and TEAM_NOT_ALLOWED.

Referenced by TeamBalance_CheckAllowedTeams(), TeamBalance_FindBestTeams(), TeamBalance_GetAllowedTeams(), TeamBalance_IsTeamAllowed(), and TeamBalance_JoinBestTeam().

◆ TeamBalance_JoinBestTeam()

void TeamBalance_JoinBestTeam ( entity player)

Assigns the given player to a team that will make the game most balanced.

Parameters
[in,out]playerPlayer to assign.

Definition at line 423 of file teamplay.qc.

424{
425 //PrintToChatAll(sprintf("TeamBalance_JoinBestTeam: %s", player.netname));
426 if (!teamplay)
427 {
428 return;
429 }
430 if (player.bot_forced_team)
431 {
432 return;
433 }
434 entity balance = TeamBalance_CheckAllowedTeams(player);
435 if (Player_HasRealForcedTeam(player))
436 {
437 int forced_team_index = player.team_forced;
438 bool is_team_allowed = TeamBalance_IsTeamAllowedInternal(balance,
439 forced_team_index);
440 TeamBalance_Destroy(balance);
441 if (!is_team_allowed)
442 {
443 return;
444 }
445 if (!SetPlayerTeam(player, forced_team_index, TEAM_CHANGE_AUTO))
446 {
447 return;
448 }
449 return;
450 }
451 int best_team_index = TeamBalance_FindBestTeam(balance, player, true);
452 TeamBalance_Destroy(balance);
453 if (!SetPlayerTeam(player, best_team_index, TEAM_CHANGE_AUTO))
454 {
455 return;
456 }
457}
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.
Definition teamplay.qc:944

References entity(), Player_HasRealForcedTeam(), SetPlayerTeam(), TEAM_CHANGE_AUTO, TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_FindBestTeam(), TeamBalance_IsTeamAllowedInternal(), and teamplay.

Referenced by PutPlayerInServer().

◆ TeamBalance_QueuedPlayersTagIn()

bool TeamBalance_QueuedPlayersTagIn ( entity ignore)

Joins queued player(s) to team(s) with a shortage, this should be more robust than only replacing the player that left.

Chooses players with a specific team preference first to increase chances of everyone getting what they want. Returns true if the teams are now balanced.

Definition at line 775 of file teamplay.qc.

776{
777 if (!teamplay)
778 return true;
779
780 int j, teamplayers_deficit = 0, teamplayers_max = 0;
781 entity it, balance = TeamBalance_CheckAllowedTeams(ignore);
782 TeamBalance_GetTeamCounts(balance, ignore);
783
784 for (int bots_would_leave_remaining = bots_would_leave, j = 1; j <= AVAILABLE_TEAMS; ++j)
785 {
786 it = TeamBalance_GetTeamFromIndex(balance, j);
787 // deduct bots that would leave if a player joined their team, distributing the deductions between teams
788 if (bots_would_leave_remaining)
789 {
790 int to_remove = min(it.m_num_bots, ceil(bots_would_leave_remaining / AVAILABLE_TEAMS));
791 it.m_num_players -= to_remove;
792 bots_would_leave_remaining -= to_remove;
793 }
794 // find the largest team size
795 if (it.m_num_players > teamplayers_max)
796 teamplayers_max = it.m_num_players;
797 }
798 // find how many players we'd need to join to achieve balanced numbers that way
799 for (j = 1; j <= AVAILABLE_TEAMS; ++j)
800 teamplayers_deficit += teamplayers_max - TeamBalance_GetTeamFromIndex(balance, j).m_num_players;
801
802 // first pass: find clients(s) who want to play on a specific team
803 for (j = 1; teamplayers_deficit > 0 && j <= maxclients; ++j)
804 {
805 it = ftoe(j);
806 if (it.wants_join <= 0 || it == ignore) continue;
807 if (TeamBalance_GetTeamFromIndex(balance, it.wants_join).m_num_players >= teamplayers_max) continue;
808 Join(it, false);
809 ++TeamBalance_GetTeam(balance, it.team).m_num_players;
810 --teamplayers_deficit;
811 }
812
813 // second pass: find clients(s) who want to play on any team
814 for (j = 1; teamplayers_deficit > 0 && j <= maxclients; ++j)
815 {
816 it = ftoe(j);
817 if (it.wants_join >= 0 || it == ignore) continue;
818 Join(it, false);
819 --teamplayers_deficit; // don't need to update .m_num_players as we won't read it again
820 }
821
822 TeamBalance_Destroy(balance);
823 return teamplayers_deficit <= 0; // return true if teams are now balanced
824}
float maxclients
#define ftoe(i)
Definition misc.qh:26
void Join(entity this, bool queued_join)
it's assumed this isn't called for bots (campaign_bots_may_start, centreprints)
Definition client.qc:2068

References AVAILABLE_TEAMS, bots_would_leave, ceil(), entity(), ftoe, Join(), maxclients, min(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetTeam(), TeamBalance_GetTeamCounts(), TeamBalance_GetTeamFromIndex(), and teamplay.

Referenced by ClientDisconnect(), and ClientKill_Now_TeamChange().

◆ TeamBalance_RemoveExcessPlayers()

void TeamBalance_RemoveExcessPlayers ( entity ignore)

Definition at line 712 of file teamplay.qc.

713{
714 if(AVAILABLE_TEAMS != 2 || autocvar_g_campaign) return;
715
716 entity balance = TeamBalance_CheckAllowedTeams(ignore);
717 TeamBalance_GetTeamCounts(balance, ignore);
718
719 int min = 0;
720
721 for(int i = 1; i <= AVAILABLE_TEAMS; ++i)
722 {
723 int cur = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
724 if(i == 1 || cur < min)
725 min = cur;
726 }
727
728 for(int tmi = 1; tmi <= AVAILABLE_TEAMS; ++tmi)
729 {
730 int cur = TeamBalance_GetTeamFromIndex(balance, tmi).m_num_players;
731 if(cur > 0 && cur > min) // If this team has excess players
732 {
733 // Get newest player
734 int latest_join = 0;
735 entity latest_join_pl = NULL;
736
738 if(it.team == Team_IndexToTeam(tmi) && CS(it).startplaytime > latest_join)
739 {
740 latest_join = CS(it).startplaytime;
741 latest_join_pl = it;
742 }
743 });
744
745 // Force player to spectate
746 if(latest_join_pl)
747 {
748 // Send player to spectate
750 {
751 // Give a warning before moving to spect
752 if (!remove_countdown)
753 {
756 remove_countdown.nextthink = time;
757 Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MOVETOSPEC_REMOVE, playername(latest_join_pl.netname, latest_join_pl.team, true), autocvar_g_balance_teams_remove_wait);
758 }
759 remove_countdown.enemy = latest_join_pl;
761 }
762 else
763 {
764 // Move to spects immediately
765 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_REMOVE, latest_join_pl.netname);
766 PutObserverInServer(latest_join_pl, true, true);
767 }
768 }
769 }
770 }
771
772 TeamBalance_Destroy(balance);
773}
string playername(string thename, int teamid, bool team_colorize)
Definition util.qc:2082
void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
putting a client as observer in the server
Definition client.qc:261
float startplaytime
Definition client.qh:67
entity remove_countdown
Definition teamplay.qc:686
void Remove_Countdown(entity this)
Definition teamplay.qc:687
int autocvar_g_balance_teams_remove_wait
Definition teamplay.qh:11

References autocvar_g_balance_teams_remove_wait, autocvar_g_campaign, AVAILABLE_TEAMS, CS(), entity(), FOREACH_CLIENT, INGAME, IS_REAL_CLIENT, min(), new_pure, NULL, playername(), PutObserverInServer(), Remove_Countdown(), remove_countdown, Send_Notification(), setthink, startplaytime, Team_IndexToTeam(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetTeamCounts(), TeamBalance_GetTeamFromIndex(), and time.

Referenced by ClientDisconnect(), ClientKill_Now_TeamChange(), and Remove_Countdown().

◆ TeamBalance_SizeDifference()

int TeamBalance_SizeDifference ( entity ignore)

Returns the size difference between the largest and smallest team (bots included).

Definition at line 633 of file teamplay.qc.

634{
635 if (!teamplay)
636 return 0;
637
638 entity balance = TeamBalance_CheckAllowedTeams(ignore);
639 TeamBalance_GetTeamCounts(balance, ignore);
640
641 int ts_min = 255, ts_max = 0;
642 for (int i = 1; i <= AVAILABLE_TEAMS; ++i)
643 {
644 int ts = TeamBalance_GetTeamFromIndex(balance, i).m_num_players;
645 if (ts_min > ts)
646 ts_min = ts;
647 if (ts_max < ts)
648 ts_max = ts;
649 }
650
651 TeamBalance_Destroy(balance);
652
653 return ts_max - ts_min;
654}
int ts_min
Definition scoreboard.qh:27
int ts_max
team size
Definition scoreboard.qh:27

References AVAILABLE_TEAMS, entity(), TeamBalance_CheckAllowedTeams(), TeamBalance_Destroy(), TeamBalance_GetTeamCounts(), TeamBalance_GetTeamFromIndex(), teamplay, ts_max, and ts_min.

Referenced by ReadyCount().

◆ TeamBalanceTeam_GetNumberOfBots()

int TeamBalanceTeam_GetNumberOfBots ( entity team_ent)

Returns the number of bots in a team.

Parameters
[in]team_entTeam entity.
Returns
Number of bots in a team.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 1268 of file teamplay.qc.

1269{
1270 return team_ent.m_num_bots;
1271}

References entity().

◆ TeamBalanceTeam_GetNumberOfPlayers()

int TeamBalanceTeam_GetNumberOfPlayers ( entity team_ent)

Returns the number of players (both humans and bots) in a team.

Parameters
[in]team_entTeam entity.
Returns
Number of player (both humans and bots) in a team.
Note
You need to call TeamBalance_GetTeamCounts before calling this function.

Definition at line 1263 of file teamplay.qc.

1264{
1265 return team_ent.m_num_players;
1266}

References entity().

Referenced by TeamBalance_AutoBalanceBots(), and TeamBalance_GetLargestTeamIndex().

◆ TeamBalanceTeam_IsAllowed()

bool TeamBalanceTeam_IsAllowed ( entity team_ent)

Returns whether the team is allowed.

Parameters
[in]team_entTeam entity.
Returns
True if team is allowed, false otherwise.

Definition at line 1258 of file teamplay.qc.

1259{
1260 return team_ent.m_num_players != TEAM_NOT_ALLOWED;
1261}

References entity(), and TEAM_NOT_ALLOWED.

Referenced by TeamBalance_AutoBalanceBots(), TeamBalance_CompareTeamsInternal(), TeamBalance_GetLargestTeamIndex(), and TeamBalance_GetTeamCounts().

Variable Documentation

◆ autocvar_g_balance_teams

bool autocvar_g_balance_teams

Definition at line 7 of file teamplay.qh.

Referenced by ClientCommand_clientversion(), PlayerPreThink(), and ShowTeamSelection().

◆ autocvar_g_balance_teams_prevent_imbalance

bool autocvar_g_balance_teams_prevent_imbalance

Definition at line 8 of file teamplay.qh.

Referenced by ClientCommand_selectteam().

◆ autocvar_g_balance_teams_queue

bool autocvar_g_balance_teams_queue

Definition at line 9 of file teamplay.qh.

Referenced by QueueNeeded().

◆ autocvar_g_balance_teams_remove

bool autocvar_g_balance_teams_remove

Definition at line 10 of file teamplay.qh.

Referenced by ClientDisconnect(), and ClientKill_Now_TeamChange().

◆ autocvar_g_balance_teams_remove_wait

int autocvar_g_balance_teams_remove_wait

Definition at line 11 of file teamplay.qh.

Referenced by TeamBalance_RemoveExcessPlayers().

◆ autocvar_g_forced_team_otherwise

string autocvar_g_forced_team_otherwise

Definition at line 13 of file teamplay.qh.

Referenced by nJoinAllowed(), and Player_DetermineForcedTeam().

◆ autocvar_teamplay_lockonrestart

bool autocvar_teamplay_lockonrestart

Definition at line 5 of file teamplay.qh.

Referenced by ReadyRestart_force().

◆ autocvar_teamplay_mode

int autocvar_teamplay_mode

Definition at line 3 of file teamplay.qh.

Referenced by Damage().

◆ lockteams

◆ team_forced

int team_forced

Definition at line 17 of file teamplay.qh.