X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fteamplay.qc;h=c3e6e95e0fa1701d34e908c395e7fbb6df76b087;hb=332b1bfac54491c16e6ef8a806fcc1d5dd768ef6;hp=db01a8f5887d76f1438bc357c5dddd05570ba389;hpb=55d3273e61152efe4244561d71c313512c20c20d;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index db01a8f58..c3e6e95e0 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -6,70 +6,13 @@ float c1, c2, c3, c4; // # 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(); @@ -150,37 +93,26 @@ void InitGameplayMode() 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 } - if(g_runematch) - { - // ActivateTeamplay(); - fraglimit_override = autocvar_g_runematch_point_limit; - leadlimit_override = autocvar_g_runematch_point_leadlimit; - runematch_init(); - } - if(g_lms) { fraglimit_override = autocvar_g_lms_lives_override; leadlimit_override = 0; // not supported by LMS if(fraglimit_override == 0) fraglimit_override = -1; - lms_lowest_lives = 9999; - lms_next_place = 0; - ScoreRules_lms(); + MUTATOR_ADD(gamemode_lms); } if(g_arena) @@ -228,6 +160,7 @@ void InitGameplayMode() { ActivateTeamplay(); have_team_spawns = -1; // request team spawns + MUTATOR_ADD(gamemode_onslaught); } if(g_race) @@ -433,13 +366,13 @@ void SetPlayerTeam(entity pl, float t, float s, float noprint) float _color; if(t == 4) - _color = COLOR_TEAM4 - 1; + _color = NUM_TEAM_4 - 1; else if(t == 3) - _color = COLOR_TEAM3 - 1; + _color = NUM_TEAM_3 - 1; else if(t == 2) - _color = COLOR_TEAM2 - 1; + _color = NUM_TEAM_2 - 1; else - _color = COLOR_TEAM1 - 1; + _color = NUM_TEAM_1 - 1; SetPlayerColors(pl,_color); @@ -447,7 +380,7 @@ void SetPlayerTeam(entity pl, float t, float s, float noprint) 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"); } } @@ -469,10 +402,10 @@ void CheckAllowedTeams (entity for_whom) 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 == NUM_TEAM_1) c1 = 0; + if (head.team == NUM_TEAM_2) c2 = 0; + if (head.team == NUM_TEAM_3) c3 = 0; + if (head.team == NUM_TEAM_4) c4 = 0; head = head.chain; } } @@ -514,13 +447,13 @@ void CheckAllowedTeams (entity for_whom) { if(!(g_domination && head.netname == "")) { - if(head.team == COLOR_TEAM1) + if(head.team == NUM_TEAM_1) c1 = 0; - else if(head.team == COLOR_TEAM2) + else if(head.team == NUM_TEAM_2) c2 = 0; - else if(head.team == COLOR_TEAM3) + else if(head.team == NUM_TEAM_3) c3 = 0; - else if(head.team == COLOR_TEAM4) + else if(head.team == NUM_TEAM_4) c4 = 0; } head = find(head, classname, teament_name); @@ -550,20 +483,18 @@ void CheckAllowedTeams (entity for_whom) } // if player has a forced team, ONLY allow that one - if(self.team_forced == COLOR_TEAM1 && c1 >= 0) + if(self.team_forced == NUM_TEAM_1 && c1 >= 0) c2 = c3 = c4 = -1; - else if(self.team_forced == COLOR_TEAM2 && c2 >= 0) + else if(self.team_forced == NUM_TEAM_2 && c2 >= 0) c1 = c3 = c4 = -1; - else if(self.team_forced == COLOR_TEAM3 && c3 >= 0) + else if(self.team_forced == NUM_TEAM_3 && c3 >= 0) c1 = c2 = c4 = -1; - else if(self.team_forced == COLOR_TEAM4 && c4 >= 0) + else if(self.team_forced == NUM_TEAM_4 && c4 >= 0) c1 = c2 = c3 = -1; } float PlayerValue(entity p) { - if(IsTeamBalanceForced() == 1) - return 1; return 1; // FIXME: it always returns 1... } @@ -595,7 +526,7 @@ void GetTeamCounts(entity ignore) bvalue = value; else bvalue = 0; - if(t == COLOR_TEAM1) + if(t == NUM_TEAM_1) { if(c1 >= 0) { @@ -603,7 +534,7 @@ void GetTeamCounts(entity ignore) cb1 = cb1 + bvalue; } } - if(t == COLOR_TEAM2) + if(t == NUM_TEAM_2) { if(c2 >= 0) { @@ -611,7 +542,7 @@ void GetTeamCounts(entity ignore) cb2 = cb2 + bvalue; } } - if(t == COLOR_TEAM3) + if(t == NUM_TEAM_3) { if(c3 >= 0) { @@ -619,7 +550,7 @@ void GetTeamCounts(entity ignore) cb3 = cb3 + bvalue; } } - if(t == COLOR_TEAM4) + if(t == NUM_TEAM_4) { if(c4 >= 0) { @@ -643,11 +574,73 @@ void GetTeamCounts(entity ignore) } } +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 @@ -688,49 +681,26 @@ float FindSmallestTeam(entity pl, float ignore_pl) 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; } @@ -749,13 +719,13 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) // 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 == NUM_TEAM_1) selectedteam = pl.team; - else if(c2 >= 0 && pl.team == COLOR_TEAM2) + else if(c2 >= 0 && pl.team == NUM_TEAM_2) selectedteam = pl.team; - else if(c3 >= 0 && pl.team == COLOR_TEAM3) + else if(c3 >= 0 && pl.team == NUM_TEAM_3) selectedteam = pl.team; - else if(c4 >= 0 && pl.team == COLOR_TEAM4) + else if(c4 >= 0 && pl.team == NUM_TEAM_4) selectedteam = pl.team; else selectedteam = -1; @@ -782,19 +752,19 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) TeamchangeFrags(self); if(smallest == 1) { - SetPlayerColors(pl, COLOR_TEAM1 - 1); + SetPlayerColors(pl, NUM_TEAM_1 - 1); } else if(smallest == 2) { - SetPlayerColors(pl, COLOR_TEAM2 - 1); + SetPlayerColors(pl, NUM_TEAM_2 - 1); } else if(smallest == 3) { - SetPlayerColors(pl, COLOR_TEAM3 - 1); + SetPlayerColors(pl, NUM_TEAM_3 - 1); } else if(smallest == 4) { - SetPlayerColors(pl, COLOR_TEAM4 - 1); + SetPlayerColors(pl, NUM_TEAM_4 - 1); } else { @@ -813,7 +783,7 @@ float JoinBestTeam(entity pl, float only_return_best, float forcebestteam) //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) { @@ -824,21 +794,21 @@ void SV_ChangeTeam(float _color) scolor = self.clientcolors & 0x0F; dcolor = _color & 0x0F; - if(scolor == COLOR_TEAM1 - 1) + if(scolor == NUM_TEAM_1 - 1) steam = 1; - else if(scolor == COLOR_TEAM2 - 1) + else if(scolor == NUM_TEAM_2 - 1) steam = 2; - else if(scolor == COLOR_TEAM3 - 1) + else if(scolor == NUM_TEAM_3 - 1) steam = 3; - else // if(scolor == COLOR_TEAM4 - 1) + else // if(scolor == NUM_TEAM_4 - 1) steam = 4; - if(dcolor == COLOR_TEAM1 - 1) + if(dcolor == NUM_TEAM_1 - 1) dteam = 1; - else if(dcolor == COLOR_TEAM2 - 1) + else if(dcolor == NUM_TEAM_2 - 1) dteam = 2; - else if(dcolor == COLOR_TEAM3 - 1) + else if(dcolor == NUM_TEAM_3 - 1) dteam = 3; - else // if(dcolor == COLOR_TEAM4 - 1) + else // if(dcolor == NUM_TEAM_4 - 1) dteam = 4; CheckAllowedTeams(self); @@ -861,62 +831,15 @@ void SV_ChangeTeam(float _color) 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) { - // only allow changing to a smaller or equal size team - - // find out what teams are available - //CheckAllowedTeams(); - // count how many players on each team - GetTeamCounts(world); - - // get desired team - if(dteam == 1 && c1 >= 0)//dcolor == COLOR_TEAM1 - 1) - { - dcount = c1; - dbotcount = cb1; - } - else if(dteam == 2 && c2 >= 0)//dcolor == COLOR_TEAM2 - 1) - { - dcount = c2; - dbotcount = cb2; - } - else if(dteam == 3 && c3 >= 0)//dcolor == COLOR_TEAM3 - 1) - { - dcount = c3; - dbotcount = cb3; - } - else if(dteam == 4 && c4 >= 0)//dcolor == COLOR_TEAM4 - 1) - { - dcount = c4; - dbotcount = cb4; - } - else + GetTeamCounts(self); + if(!TeamSmallerEqThanTeam(dteam, steam, self)) { - sprint(self, "Cannot change to an invalid team\n"); - + sprint(self, "Cannot change to a larger/better/shinier team\n"); return; } - - // get starting team - if(steam == 1)//scolor == COLOR_TEAM1 - 1) - scount = c1; - else if(steam == 2)//scolor == COLOR_TEAM2 - 1) - scount = c2; - else if(steam == 3)//scolor == COLOR_TEAM3 - 1) - scount = c3; - else // if(steam == 4)//scolor == COLOR_TEAM4 - 1) - scount = c4; - - if(scount) // started at a valid, nonempty team - { - // check if we're trying to change to a larger team that doens't have bots to swap with - if(dcount >= scount && dbotcount <= 0) - { - sprint(self, "Cannot change to a larger team\n"); - return; // can't change to a larger team - } - } } // bprint("allow change teams from ", ftos(steam), " to ", ftos(dteam), "\n"); @@ -935,7 +858,6 @@ void SV_ChangeTeam(float _color) if(self.deadflag == DEAD_NO) Damage(self, self, self, 100000, DEATH_TEAMCHANGE, self.origin, '0 0 0'); } - //ctf_playerchanged(); } void ShufflePlayerOutOfTeam (float source_team) @@ -975,13 +897,13 @@ void ShufflePlayerOutOfTeam (float source_team) } if(source_team == 1) - steam = COLOR_TEAM1; + steam = NUM_TEAM_1; else if(source_team == 2) - steam = COLOR_TEAM2; + steam = NUM_TEAM_2; else if(source_team == 3) - steam = COLOR_TEAM3; + steam = NUM_TEAM_3; else // if(source_team == 4) - steam = COLOR_TEAM4; + steam = NUM_TEAM_4; lowest_bot = world; lowest_bot_score = 999999999; @@ -1076,88 +998,7 @@ void ShufflePlayerOutOfTeam (float source_team) 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 @@ -1181,12 +1022,12 @@ void tdm_spawnteams() 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", NUM_TEAM_1-1); + tdm_spawnteam("Blue", NUM_TEAM_2-1); if(numteams >= 3) - tdm_spawnteam("Yellow", COLOR_TEAM3-1); + tdm_spawnteam("Yellow", NUM_TEAM_3-1); if(numteams >= 4) - tdm_spawnteam("Pink", COLOR_TEAM4-1); + tdm_spawnteam("Pink", NUM_TEAM_4-1); } void tdm_delayedinit()