// # of bots on those teams
float cb1, cb2, cb3, cb4;
-float audit_teams_time;
-
-float IsTeamBalanceForced()
-{
- if(intermission_running)
- return 0; // no rebalancing whatsoever please
- if(!teamplay)
- return 0;
- if(autocvar_g_campaign)
- return 0;
- if(autocvar_bot_vs_human && (c3==-1 && c4==-1))
- return 0;
- if(!autocvar_g_balance_teams_force)
- return -1;
- return 1;
-}
+//float audit_teams_time;
void TeamchangeFrags(entity e)
{
PlayerScore_Clear(e);
}
-vector TeamColor(float teem)
-{
- switch(teem)
- {
- case COLOR_TEAM1:
- return '1 0.0625 0.0625';
- case COLOR_TEAM2:
- return '0.0625 0.0625 1';
- case COLOR_TEAM3:
- return '1 1 0.0625';
- case COLOR_TEAM4:
- return '1 0.0625 1';
- default:
- return '1 1 1';
- }
-}
-
-string TeamName(float t)
-{
- return strcat(Team_ColorName(t), " Team");
-}
-string ColoredTeamName(float t)
-{
- return strcat(Team_ColorCode(t), Team_ColorName(t), " Team^7");
-}
-string TeamNoName(float t)
-{
- // fixme: Search for team entities and get their .netname's!
- if(t == 1)
- return "Red Team";
- if(t == 2)
- return "Blue Team";
- if(t == 3)
- return "Yellow Team";
- if(t == 4)
- return "Pink Team";
- return "Neutral Team";
-}
-
-void dom_init();
-void ctf_init();
void runematch_init();
void tdm_init();
void entcs_init();
ActivateTeamplay();
fraglimit_override = autocvar_g_domination_point_limit;
leadlimit_override = autocvar_g_domination_point_leadlimit;
- dom_init();
+ MUTATOR_ADD(gamemode_domination);
have_team_spawns = -1; // request team spawns
}
if(g_ctf)
{
ActivateTeamplay();
- g_ctf_ignore_frags = autocvar_g_ctf_ignore_frags;
fraglimit_override = autocvar_capturelimit_override;
leadlimit_override = autocvar_captureleadlimit_override;
- ctf_init();
+ MUTATOR_ADD(gamemode_ctf);
have_team_spawns = -1; // request team spawns
}
{
ActivateTeamplay();
have_team_spawns = -1; // request team spawns
+ MUTATOR_ADD(gamemode_onslaught);
}
if(g_race)
float _color;
if(t == 4)
- _color = COLOR_TEAM4 - 1;
+ _color = FL_TEAM_4 - 1;
else if(t == 3)
- _color = COLOR_TEAM3 - 1;
+ _color = FL_TEAM_3 - 1;
else if(t == 2)
- _color = COLOR_TEAM2 - 1;
+ _color = FL_TEAM_2 - 1;
else
- _color = COLOR_TEAM1 - 1;
+ _color = FL_TEAM_1 - 1;
SetPlayerColors(pl,_color);
LogTeamchange(pl.playerid, pl.team, 3); // log manual team join
if(!noprint)
- bprint(pl.netname, "^7 has changed from ", TeamNoName(s), " to ", TeamNoName(t), "\n");
+ bprint(pl.netname, "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n");
}
}
head = findchain(classname, "onslaught_generator");
while (head)
{
- if (head.team == COLOR_TEAM1) c1 = 0;
- if (head.team == COLOR_TEAM2) c2 = 0;
- if (head.team == COLOR_TEAM3) c3 = 0;
- if (head.team == COLOR_TEAM4) c4 = 0;
+ if (head.team == FL_TEAM_1) c1 = 0;
+ if (head.team == FL_TEAM_2) c2 = 0;
+ if (head.team == FL_TEAM_3) c3 = 0;
+ if (head.team == FL_TEAM_4) c4 = 0;
head = head.chain;
}
}
{
if(!(g_domination && head.netname == ""))
{
- if(head.team == COLOR_TEAM1)
+ if(head.team == FL_TEAM_1)
c1 = 0;
- else if(head.team == COLOR_TEAM2)
+ else if(head.team == FL_TEAM_2)
c2 = 0;
- else if(head.team == COLOR_TEAM3)
+ else if(head.team == FL_TEAM_3)
c3 = 0;
- else if(head.team == COLOR_TEAM4)
+ else if(head.team == FL_TEAM_4)
c4 = 0;
}
head = find(head, classname, teament_name);
}
// if player has a forced team, ONLY allow that one
- if(self.team_forced == COLOR_TEAM1 && c1 >= 0)
+ if(self.team_forced == FL_TEAM_1 && c1 >= 0)
c2 = c3 = c4 = -1;
- else if(self.team_forced == COLOR_TEAM2 && c2 >= 0)
+ else if(self.team_forced == FL_TEAM_2 && c2 >= 0)
c1 = c3 = c4 = -1;
- else if(self.team_forced == COLOR_TEAM3 && c3 >= 0)
+ else if(self.team_forced == FL_TEAM_3 && c3 >= 0)
c1 = c2 = c4 = -1;
- else if(self.team_forced == COLOR_TEAM4 && c4 >= 0)
+ else if(self.team_forced == FL_TEAM_4 && c4 >= 0)
c1 = c2 = c3 = -1;
}
float PlayerValue(entity p)
{
- if(IsTeamBalanceForced() == 1)
- return 1;
return 1;
// FIXME: it always returns 1...
}
bvalue = value;
else
bvalue = 0;
- if(t == COLOR_TEAM1)
+ if(t == FL_TEAM_1)
{
if(c1 >= 0)
{
cb1 = cb1 + bvalue;
}
}
- if(t == COLOR_TEAM2)
+ if(t == FL_TEAM_2)
{
if(c2 >= 0)
{
cb2 = cb2 + bvalue;
}
}
- if(t == COLOR_TEAM3)
+ if(t == FL_TEAM_3)
{
if(c3 >= 0)
{
cb3 = cb3 + bvalue;
}
}
- if(t == COLOR_TEAM4)
+ if(t == FL_TEAM_4)
{
if(c4 >= 0)
{
}
}
+float TeamSmallerEqThanTeam(float ta, float tb, entity e)
+{
+ // we assume that CheckAllowedTeams and GetTeamCounts have already been called
+ float f;
+ float ca = -1, cb = -1, cba = 0, cbb = 0, sa = 0, sb = 0;
+
+ switch(ta)
+ {
+ case 1: ca = c1; cba = cb1; sa = team1_score; break;
+ case 2: ca = c2; cba = cb2; sa = team2_score; break;
+ case 3: ca = c3; cba = cb3; sa = team3_score; break;
+ case 4: ca = c4; cba = cb4; sa = team4_score; break;
+ }
+ switch(tb)
+ {
+ case 1: cb = c1; cbb = cb1; sb = team1_score; break;
+ case 2: cb = c2; cbb = cb2; sb = team2_score; break;
+ case 3: cb = c3; cbb = cb3; sb = team3_score; break;
+ case 4: cb = c4; cbb = cb4; sb = team4_score; break;
+ }
+
+ // invalid
+ if(ca < 0 || cb < 0)
+ return FALSE;
+
+ // equal
+ if(ta == tb)
+ return TRUE;
+
+ if(clienttype(e) == CLIENTTYPE_REAL)
+ {
+ if(bots_would_leave)
+ {
+ ca -= cba * 0.999;
+ cb -= cbb * 0.999;
+ }
+ }
+
+ // keep teams alive (teams of size 0 always count as smaller, ignoring score)
+ if(ca < 1)
+ if(cb >= 1)
+ return TRUE;
+ if(ca >= 1)
+ if(cb < 1)
+ return FALSE;
+
+ // first, normalize
+ f = max(ca, cb, 1);
+ ca /= f;
+ cb /= f;
+ f = max(sa, sb, 1);
+ sa /= f;
+ sb /= f;
+
+ // the more we're at the end of the match, the more take scores into account
+ f = bound(0, game_completion_ratio * autocvar_g_balance_teams_scorefactor, 1);
+ ca += (sa - ca) * f;
+ cb += (sb - cb) * f;
+
+ return ca <= cb;
+}
+
// returns # of smallest team (1, 2, 3, 4)
// NOTE: Assumes CheckAllowedTeams has already been called!
float FindSmallestTeam(entity pl, float ignore_pl)
{
- float totalteams, balance_type, maxc;
+ float totalteams, t;
totalteams = 0;
// find out what teams are available
else
GetTeamCounts(world);
- // c1...c4 now have counts of each team
- // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker
-
- // 2 gives priority to what team you're already on, 1 goes in order
- // 2 doesn't seem to work though...
- balance_type = 1;
-
- if(bots_would_leave)
- //if(pl.classname != "player")
- if(clienttype(pl) != CLIENTTYPE_BOT)
- {
- c1 -= cb1 * 255.0/256.0;
- c2 -= cb2 * 255.0/256.0;
- c3 -= cb3 * 255.0/256.0;
- c4 -= cb4 * 255.0/256.0;
- }
- maxc = max4(c1, c2, c3, c4);
-
RandomSelection_Init();
- if(balance_type == 1)
- {
- // 1: use team count, then score (note: can only use 8 significant bits of score)
- if(c1 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + float2range01(-team1_score) / 256.0);
- if(c2 >= 0) RandomSelection_Add(world, 2, string_null, 1, (maxc - c2) + float2range01(-team2_score) / 256.0);
- if(c3 >= 0) RandomSelection_Add(world, 3, string_null, 1, (maxc - c3) + float2range01(-team3_score) / 256.0);
- if(c4 >= 0) RandomSelection_Add(world, 4, string_null, 1, (maxc - c4) + float2range01(-team4_score) / 256.0);
- }
- else if(balance_type == 2)
- {
- // 1: use team count, if equal prefer own team
- if(c1 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM1) / 512.0);
- if(c2 >= 0) RandomSelection_Add(world, 2, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM2) / 512.0);
- if(c3 >= 0) RandomSelection_Add(world, 3, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM3) / 512.0);
- if(c4 >= 0) RandomSelection_Add(world, 4, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM4) / 512.0);
- }
- else if(balance_type == 3)
- {
- // 1: use team count, then score, if equal prefer own team (probably fails due to float accuracy problems)
- if(c1 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + float2range01(-team1_score + 0.5 * (self.team == COLOR_TEAM1)) / 256.0);
- if(c2 >= 0) RandomSelection_Add(world, 2, string_null, 1, (maxc - c2) + float2range01(-team2_score + 0.5 * (self.team == COLOR_TEAM2)) / 256.0);
- if(c3 >= 0) RandomSelection_Add(world, 3, string_null, 1, (maxc - c3) + float2range01(-team3_score + 0.5 * (self.team == COLOR_TEAM3)) / 256.0);
- if(c4 >= 0) RandomSelection_Add(world, 4, string_null, 1, (maxc - c4) + float2range01(-team4_score + 0.5 * (self.team == COLOR_TEAM4)) / 256.0);
- }
+
+ t = 1;
+ if(TeamSmallerEqThanTeam(2, t, pl))
+ t = 2;
+ if(TeamSmallerEqThanTeam(3, t, pl))
+ t = 3;
+ if(TeamSmallerEqThanTeam(4, t, pl))
+ t = 4;
+
+ // now t is the minimum, or A minimum!
+ if(t == 1 || TeamSmallerEqThanTeam(1, t, pl))
+ RandomSelection_Add(world, 1, string_null, 1, 1);
+ if(t == 2 || TeamSmallerEqThanTeam(2, t, pl))
+ RandomSelection_Add(world, 2, string_null, 1, 1);
+ if(t == 3 || TeamSmallerEqThanTeam(3, t, pl))
+ RandomSelection_Add(world, 3, string_null, 1, 1);
+ if(t == 4 || TeamSmallerEqThanTeam(4, t, pl))
+ RandomSelection_Add(world, 4, string_null, 1, 1);
+
return RandomSelection_chosen_float;
}
// if he's not on a valid team, then let other code put him on the smallest team
if(!forcebestteam)
{
- if( c1 >= 0 && pl.team == COLOR_TEAM1)
+ if( c1 >= 0 && pl.team == FL_TEAM_1)
selectedteam = pl.team;
- else if(c2 >= 0 && pl.team == COLOR_TEAM2)
+ else if(c2 >= 0 && pl.team == FL_TEAM_2)
selectedteam = pl.team;
- else if(c3 >= 0 && pl.team == COLOR_TEAM3)
+ else if(c3 >= 0 && pl.team == FL_TEAM_3)
selectedteam = pl.team;
- else if(c4 >= 0 && pl.team == COLOR_TEAM4)
+ else if(c4 >= 0 && pl.team == FL_TEAM_4)
selectedteam = pl.team;
else
selectedteam = -1;
TeamchangeFrags(self);
if(smallest == 1)
{
- SetPlayerColors(pl, COLOR_TEAM1 - 1);
+ SetPlayerColors(pl, FL_TEAM_1 - 1);
}
else if(smallest == 2)
{
- SetPlayerColors(pl, COLOR_TEAM2 - 1);
+ SetPlayerColors(pl, FL_TEAM_2 - 1);
}
else if(smallest == 3)
{
- SetPlayerColors(pl, COLOR_TEAM3 - 1);
+ SetPlayerColors(pl, FL_TEAM_3 - 1);
}
else if(smallest == 4)
{
- SetPlayerColors(pl, COLOR_TEAM4 - 1);
+ SetPlayerColors(pl, FL_TEAM_4 - 1);
}
else
{
//void() ctf_playerchanged;
void SV_ChangeTeam(float _color)
{
- float scolor, dcolor, steam, dteam, dbotcount, scount, dcount;
+ float scolor, dcolor, steam, dteam; //, dbotcount, scount, dcount;
// in normal deathmatch we can just apply the color and we're done
if(!teamplay) {
scolor = self.clientcolors & 0x0F;
dcolor = _color & 0x0F;
- if(scolor == COLOR_TEAM1 - 1)
+ if(scolor == FL_TEAM_1 - 1)
steam = 1;
- else if(scolor == COLOR_TEAM2 - 1)
+ else if(scolor == FL_TEAM_2 - 1)
steam = 2;
- else if(scolor == COLOR_TEAM3 - 1)
+ else if(scolor == FL_TEAM_3 - 1)
steam = 3;
- else // if(scolor == COLOR_TEAM4 - 1)
+ else // if(scolor == FL_TEAM_4 - 1)
steam = 4;
- if(dcolor == COLOR_TEAM1 - 1)
+ if(dcolor == FL_TEAM_1 - 1)
dteam = 1;
- else if(dcolor == COLOR_TEAM2 - 1)
+ else if(dcolor == FL_TEAM_2 - 1)
dteam = 2;
- else if(dcolor == COLOR_TEAM3 - 1)
+ else if(dcolor == FL_TEAM_3 - 1)
dteam = 3;
- else // if(dcolor == COLOR_TEAM4 - 1)
+ else // if(dcolor == FL_TEAM_4 - 1)
dteam = 4;
CheckAllowedTeams(self);
return; // changing teams is not allowed
}
- if(autocvar_g_balance_teams_prevent_imbalance)
+ // autocvar_g_balance_teams_prevent_imbalance only makes sense if autocvar_g_balance_teams is on, as it makes the team selection dialog pointless
+ if(autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
{
- t = FindSmallestTeam(self, TRUE);
- if(dteam != t)
+ GetTeamCounts(self);
+ if(!TeamSmallerEqThanTeam(dteam, steam, self))
{
- sprint(self, "Cannot change to the given team\n");
+ sprint(self, "Cannot change to a larger/better/shinier team\n");
return;
}
}
if(self.deadflag == DEAD_NO)
Damage(self, self, self, 100000, DEATH_TEAMCHANGE, self.origin, '0 0 0');
}
- //ctf_playerchanged();
}
void ShufflePlayerOutOfTeam (float source_team)
}
if(source_team == 1)
- steam = COLOR_TEAM1;
+ steam = FL_TEAM_1;
else if(source_team == 2)
- steam = COLOR_TEAM2;
+ steam = FL_TEAM_2;
else if(source_team == 3)
- steam = COLOR_TEAM3;
+ steam = FL_TEAM_3;
else // if(source_team == 4)
- steam = COLOR_TEAM4;
+ steam = FL_TEAM_4;
lowest_bot = world;
lowest_bot_score = 999999999;
if(selected.deadflag == DEAD_NO)
Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE, selected.origin, '0 0 0');
- centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", ColoredTeamName(selected.team)));
-}
-
-void CauseRebalance(float source_team, float howmany_toomany)
-{
- if(IsTeamBalanceForced() == 1)
- {
- bprint("Rebalancing Teams\n");
- ShufflePlayerOutOfTeam(source_team);
- }
-}
-
-// part of g_balance_teams_force
-// occasionally perform an audit of the teams to make
-// sure they're more or less balanced in player count.
-void AuditTeams()
-{
- float numplayers, numteams, smallest, toomany;
- float balance;
- balance = IsTeamBalanceForced();
- if(balance == 0)
- return;
-
- if(audit_teams_time > time)
- return;
-
- audit_teams_time = time + 4 + random();
-
-// bprint("Auditing teams\n");
-
- CheckAllowedTeams(world);
- GetTeamCounts(world);
-
-
- numteams = numplayers = smallest = 0;
- if(c1 >= 0)
- {
- numteams = numteams + 1;
- numplayers = numplayers + c1;
- smallest = c1;
- }
- if(c2 >= 0)
- {
- numteams = numteams + 1;
- numplayers = numplayers + c2;
- if(c2 < smallest)
- smallest = c2;
- }
- if(c3 >= 0)
- {
- numteams = numteams + 1;
- numplayers = numplayers + c3;
- if(c3 < smallest)
- smallest = c3;
- }
- if(c4 >= 0)
- {
- numteams = numteams + 1;
- numplayers = numplayers + c4;
- if(c4 < smallest)
- smallest = c4;
- }
-
- if(numplayers <= 0)
- return; // no players to move around
- if(numteams < 2)
- return; // don't bother shuffling if for some reason there aren't any teams
-
- toomany = smallest + 1;
-
- if(c1 && c1 > toomany)
- CauseRebalance(1, c1 - toomany);
- if(c2 && c2 > toomany)
- CauseRebalance(2, c2 - toomany);
- if(c3 && c3 > toomany)
- CauseRebalance(3, c3 - toomany);
- if(c4 && c4 > toomany)
- CauseRebalance(4, c4 - toomany);
-
- // if teams are still unbalanced, balance them further in the next audit,
- // which will happen sooner (keep doing rapid audits until things are in order)
- audit_teams_time = time + 0.7 + random()*0.3;
+ centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", Team_ColoredFullName(selected.team)));
}
// code from here on is just to support maps that don't have team entities
numteams = autocvar_g_tdm_teams;
numteams = bound(2, numteams, 4);
- tdm_spawnteam("Red", COLOR_TEAM1-1);
- tdm_spawnteam("Blue", COLOR_TEAM2-1);
+ tdm_spawnteam("Red", FL_TEAM_1-1);
+ tdm_spawnteam("Blue", FL_TEAM_2-1);
if(numteams >= 3)
- tdm_spawnteam("Yellow", COLOR_TEAM3-1);
+ tdm_spawnteam("Yellow", FL_TEAM_3-1);
if(numteams >= 4)
- tdm_spawnteam("Pink", COLOR_TEAM4-1);
+ tdm_spawnteam("Pink", FL_TEAM_4-1);
}
void tdm_delayedinit()