]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/scores.qc
Merge remote-tracking branch 'origin/samual/makemulti_inverse'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / scores.qc
index 38425a8ba180c67b116783366579e49c2576790c..3a8b830d74c04e82063566368b0c949bc7f52878 100644 (file)
@@ -10,11 +10,11 @@ var .float teamscores_primary;
 float scores_flags_primary;
 float teamscores_flags_primary;
 
-vector ScoreField_Compare(entity t1, entity t2, .float field, float fieldflags, vector previous) // returns: cmp value, best prio
+vector ScoreField_Compare(entity t1, entity t2, .float field, float fieldflags, vector previous, float strict) // returns: cmp value, best prio
 {
-       if(!(fieldflags & SFL_SORT_PRIO_MASK)) // column does not sort
+       if(!strict && !(fieldflags & SFL_SORT_PRIO_MASK)) // column does not sort
                return previous;
-       if(fieldflags & SFL_SORT_PRIO_MASK < previous_y)
+       if((fieldflags & SFL_SORT_PRIO_MASK) < previous_y)
                return previous;
        if(t1.field == t2.field)
                return previous;
@@ -123,7 +123,7 @@ float TeamScore_Add(entity player, float scorefield, float score)
        return TeamScore_AddToTeam(player.team, scorefield, score);
 }
 
-float TeamScore_Compare(entity t1, entity t2)
+float TeamScore_Compare(entity t1, entity t2, float strict)
 {
        if(!t1 || !t2) return (!t2) - !t1;
 
@@ -133,8 +133,12 @@ float TeamScore_Compare(entity t1, entity t2)
        {
                var .float f;
                f = teamscores[i];
-               result = ScoreField_Compare(t1, t2, f, teamscores_flags[i], result);
+               result = ScoreField_Compare(t1, t2, f, teamscores_flags[i], result, strict);
        }
+
+       if (result_x == 0 && strict)
+               result_x = t1.team - t2.team;
+
        return result_x;
 }
 
@@ -146,7 +150,7 @@ void ScoreInfo_SetLabel_PlayerScore(float i, string label, float scoreflags)
 {
        scores_label[i] = label;
        scores_flags[i] = scoreflags;
-       if(scoreflags & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+       if((scoreflags & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
        {
                scores_primary = scores[i];
                scores_flags_primary = scoreflags;
@@ -162,11 +166,16 @@ void ScoreInfo_SetLabel_TeamScore(float i, string label, float scoreflags)
 {
        teamscores_label[i] = label;
        teamscores_flags[i] = scoreflags;
-       if(scoreflags & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+       if((scoreflags & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
        {
                teamscores_primary = teamscores[i];
                teamscores_flags_primary = scoreflags;
        }
+       if(label != "")
+       {
+               PlayerStats_AddEvent(strcat(PLAYERSTATS_TOTAL, label));
+               PlayerStats_AddEvent(strcat(PLAYERSTATS_SCOREBOARD, label));
+       }
 }
 
 float ScoreInfo_SendEntity(entity to, float sf)
@@ -200,13 +209,13 @@ void ScoreInfo_Init(float teams)
                Net_LinkEntity(scores_initialized, FALSE, 0, ScoreInfo_SendEntity);
        }
        if(teams >= 1)
-               TeamScore_Spawn(FL_TEAM_1, "Red");
+               TeamScore_Spawn(NUM_TEAM_1, "Red");
        if(teams >= 2)
-               TeamScore_Spawn(FL_TEAM_2, "Blue");
+               TeamScore_Spawn(NUM_TEAM_2, "Blue");
        if(teams >= 3)
-               TeamScore_Spawn(FL_TEAM_3, "Yellow");
+               TeamScore_Spawn(NUM_TEAM_3, "Yellow");
        if(teams >= 4)
-               TeamScore_Spawn(FL_TEAM_4, "Pink");
+               TeamScore_Spawn(NUM_TEAM_4, "Pink");
 }
 
 /*
@@ -244,18 +253,18 @@ float PlayerScore_SendEntity(entity to, float sendflags)
        return TRUE;
 }
 
-void PlayerScore_Clear(entity player)
+float PlayerScore_Clear(entity player)
 {
        entity sk;
        float i;
 
        if(teamscores_entities_count)
-               return;
+               return 0;
+
+       if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
 
-       if(g_lms) return;
-       if(g_arena || g_ca) return;
-       if(g_cts) return; // in CTS, you don't lose score by observing
-       if(g_race && g_race_qualifying) return; // in qualifying, you don't lose score by observing
+       if(g_cts) return 0; // in CTS, you don't lose score by observing
+       if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
 
        sk = player.scorekeeper;
        for(i = 0; i < MAX_SCORE; ++i)
@@ -265,6 +274,8 @@ void PlayerScore_Clear(entity player)
                                sk.SendFlags |= pow(2, i);
                sk.(scores[i]) = 0;
        }
+
+       return 1;
 }
 
 void Score_ClearAll()
@@ -323,7 +334,7 @@ float PlayerScore_Add(entity player, float scorefield, float score)
        entity s;
 
        if(gameover)
-       if not(g_lms && scorefield == SP_LMS_RANK) // allow writing to this field in intermission as it is needed for newly joining players
+       if(!(g_lms && scorefield == SP_LMS_RANK)) // allow writing to this field in intermission as it is needed for newly joining players
                score = 0;
 
        if(!scores_initialized) return 0; // FIXME remove this when everything uses this system
@@ -338,7 +349,7 @@ float PlayerScore_Add(entity player, float scorefield, float score)
        if(score)
                if(scores_label[scorefield] != "")
                        s.SendFlags |= pow(2, scorefield);
-       if(!inWarmupStage)
+       if(!warmup_stage)
                PlayerStats_Event(s.owner, strcat(PLAYERSTATS_TOTAL, scores_label[scorefield]), score);
        return (s.(scores[scorefield]) += score);
 }
@@ -352,7 +363,7 @@ float PlayerTeamScore_Add(entity player, float pscorefield, float tscorefield, f
        return r;
 }
 
-float PlayerScore_Compare(entity t1, entity t2)
+float PlayerScore_Compare(entity t1, entity t2, float strict)
 {
        if(!t1 || !t2) return (!t2) - !t1;
 
@@ -362,8 +373,12 @@ float PlayerScore_Compare(entity t1, entity t2)
        {
                var .float f;
                f = scores[i];
-               result = ScoreField_Compare(t1, t2, f, scores_flags[i], result);
+               result = ScoreField_Compare(t1, t2, f, scores_flags[i], result, strict);
        }
+
+       if (result_x == 0 && strict)
+               result_x = num_for_edict(t1.owner) - num_for_edict(t2.owner);
+
        return result_x;
 }
 
@@ -383,15 +398,15 @@ void WinningConditionHelper()
        // so to match pure, match for :P0:
        // to match full, match for :S0:
 
+       fullstatus = autocvar_g_full_getstatus_responses;
+
        s = GetGametype();
        s = strcat(s, ":", autocvar_g_xonoticversion);
        s = strcat(s, ":P", ftos(cvar_purechanges_count));
        s = strcat(s, ":S", ftos(nJoinAllowed(world)));
        s = strcat(s, ":F", ftos(serverflags));
        s = strcat(s, ":M", modname);
-       s = strcat(s, "::", GetPlayerScoreString(world, 1)); // make this 1 once we can, note: this doesn't contain any :<letter>
-
-       fullstatus = autocvar_g_full_getstatus_responses;
+       s = strcat(s, "::", GetPlayerScoreString(world, (fullstatus ? 1 : 2)));
 
        if(teamscores_entities_count)
        {
@@ -409,7 +424,7 @@ void WinningConditionHelper()
                for(t = 0; t < 16; ++t)
                {
                        sk = teamscorekeepers[t];
-                       c = TeamScore_Compare(winnerscorekeeper, sk);
+                       c = TeamScore_Compare(winnerscorekeeper, sk, 1);
                        if(c < 0)
                        {
                                WinningConditionHelper_secondteam = WinningConditionHelper_winnerteam;
@@ -419,7 +434,7 @@ void WinningConditionHelper()
                        }
                        else
                        {
-                               c = TeamScore_Compare(secondscorekeeper, sk);
+                               c = TeamScore_Compare(secondscorekeeper, sk, 1);
                                if(c < 0)
                                {
                                        WinningConditionHelper_secondteam = t + 1;
@@ -428,7 +443,7 @@ void WinningConditionHelper()
                        }
                }
 
-               WinningConditionHelper_equality = (TeamScore_Compare(winnerscorekeeper, secondscorekeeper) == 0);
+               WinningConditionHelper_equality = (TeamScore_Compare(winnerscorekeeper, secondscorekeeper, 0) == 0);
                if(WinningConditionHelper_equality)
                        WinningConditionHelper_winnerteam = WinningConditionHelper_secondteam = -1;
 
@@ -449,7 +464,7 @@ void WinningConditionHelper()
                FOR_EACH_PLAYER(p)
                {
                        sk = p.scorekeeper;
-                       c = PlayerScore_Compare(winnerscorekeeper, sk);
+                       c = PlayerScore_Compare(winnerscorekeeper, sk, 1);
                        if(c < 0)
                        {
                                WinningConditionHelper_second = WinningConditionHelper_winner;
@@ -459,7 +474,7 @@ void WinningConditionHelper()
                        }
                        else
                        {
-                               c = PlayerScore_Compare(secondscorekeeper, sk);
+                               c = PlayerScore_Compare(secondscorekeeper, sk, 1);
                                if(c < 0)
                                {
                                        WinningConditionHelper_second = p;
@@ -468,7 +483,7 @@ void WinningConditionHelper()
                        }
                }
 
-               WinningConditionHelper_equality = (PlayerScore_Compare(winnerscorekeeper, secondscorekeeper) == 0);
+               WinningConditionHelper_equality = (PlayerScore_Compare(winnerscorekeeper, secondscorekeeper, 0) == 0);
                if(WinningConditionHelper_equality)
                        WinningConditionHelper_winner = WinningConditionHelper_second = world;
 
@@ -513,16 +528,16 @@ void WinningConditionHelper()
                if(fullstatus)
                {
                        s = GetPlayerScoreString(p, 1);
-                       if(clienttype(p) == CLIENTTYPE_REAL)
+                       if(IS_REAL_CLIENT(p))
                                s = strcat(s, ":human");
                        else
                                s = strcat(s, ":bot");
-                       if(p.classname != "player" && !g_arena && !g_ca && !g_lms)
+                       if(!IS_PLAYER(p) && p.caplayer != 1 && !g_lms)
                                s = strcat(s, ":spectator");
                }
                else
                {
-                       if(p.classname == "player" || g_arena || g_ca || g_lms)
+                       if(IS_PLAYER(p) || p.caplayer == 1 || g_lms)
                                s = GetPlayerScoreString(p, 2);
                        else
                                s = "-666";
@@ -538,9 +553,9 @@ string GetScoreLogLabel(string label, float fl)
 {
        if(fl & SFL_LOWER_IS_BETTER)
                label = strcat(label, "<");
-       if(fl & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+       if((fl & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
                label = strcat(label, "!!");
-       else if(fl & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
+       else if((fl & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
                label = strcat(label, "!");
        return label;
 }
@@ -557,7 +572,7 @@ string GetPlayerScoreString(entity pl, float shortString)
        {
                // label
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
                        {
                                f = scores_flags[i];
                                l = scores_label[i];
@@ -565,7 +580,7 @@ string GetPlayerScoreString(entity pl, float shortString)
                        }
                if(shortString < 2)
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
                        {
                                f = scores_flags[i];
                                l = scores_label[i];
@@ -573,8 +588,8 @@ string GetPlayerScoreString(entity pl, float shortString)
                        }
                if(shortString < 1)
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
                        {
                                f = scores_flags[i];
                                l = scores_label[i];
@@ -585,16 +600,16 @@ string GetPlayerScoreString(entity pl, float shortString)
        else if((sk = pl.scorekeeper))
        {
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
                                out = strcat(out, ftos(sk.(scores[i])), ",");
                if(shortString < 2)
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
                                out = strcat(out, ftos(sk.(scores[i])), ",");
                if(shortString < 1)
                for(i = 0; i < MAX_SCORE; ++i)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY)
-                       if(scores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+                       if((scores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
                                out = strcat(out, ftos(sk.(scores[i])), ",");
                out = substring(out, 0, strlen(out) - 1);
        }
@@ -612,25 +627,25 @@ string GetTeamScoreString(float tm, float shortString)
        if(tm == 0)
        {
                // label
-               for(i = 0; i < MAX_SCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
                        {
                                f = teamscores_flags[i];
                                l = teamscores_label[i];
                                out = strcat(out, GetScoreLogLabel(l, f), ",");
                        }
                if(shortString < 2)
-               for(i = 0; i < MAX_SCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
                        {
                                f = teamscores_flags[i];
                                l = teamscores_label[i];
                                out = strcat(out, GetScoreLogLabel(l, f), ",");
                        }
                if(shortString < 1)
-               for(i = 0; i < MAX_SCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
                        {
                                f = teamscores_flags[i];
                                l = teamscores_label[i];
@@ -641,67 +656,73 @@ string GetTeamScoreString(float tm, float shortString)
        else if((sk = teamscorekeepers[tm - 1]))
        {
                for(i = 0; i < MAX_TEAMSCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_PRIMARY)
                                out = strcat(out, ftos(sk.(teamscores[i])), ",");
                if(shortString < 2)
                for(i = 0; i < MAX_TEAMSCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) == SFL_SORT_PRIO_SECONDARY)
                                out = strcat(out, ftos(sk.(teamscores[i])), ",");
                if(shortString < 1)
                for(i = 0; i < MAX_TEAMSCORE; ++i)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY)
-                       if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_PRIMARY)
+                       if((teamscores_flags[i] & SFL_SORT_PRIO_MASK) != SFL_SORT_PRIO_SECONDARY)
                                out = strcat(out, ftos(sk.(teamscores[i])), ",");
                out = substring(out, 0, strlen(out) - 1);
        }
        return out;
 }
 
-float PlayerTeamScore_Compare(entity p1, entity p2)
+float PlayerTeamScore_Compare(entity p1, entity p2, float teams, float strict)
 {
-       if(teamscores_entities_count)
+       if(teams && teamscores_entities_count)
+       {
                if(p1.team != p2.team)
                {
                        entity t1, t2;
                        float r;
                        t1 = teamscorekeepers[p1.team - 1];
                        t2 = teamscorekeepers[p2.team - 1];
-                       r = TeamScore_Compare(t1, t2);
-                       if(r == 0) // ensure a deterministic order
-                               r = p1.team - p2.team;
+                       r = TeamScore_Compare(t1, t2, ((teams >= 0) ? 1 : strict));
                        return r;
                }
-       
-       return PlayerScore_Compare(p1.scorekeeper, p2.scorekeeper);
+               if(teams < 0)
+                       return 0;
+       }
+
+       return PlayerScore_Compare(p1.scorekeeper, p2.scorekeeper, strict);
 }
 
-entity PlayerScore_Sort(.float field)
+entity PlayerScore_Sort(.float field, float teams, float strict, float nospectators)
 {
        entity p, plist, pprev, pbest, pbestprev, pfirst, plast;
-       float i;
+       float i, j;
 
        plist = world;
 
        FOR_EACH_CLIENT(p)
                p.field = 0;
 
-       FOR_EACH_PLAYER(p) if(p.scorekeeper)
+       FOR_EACH_CLIENT(p) if(p.scorekeeper)
        {
+               if(nospectators)
+                       if(p.frags == FRAGS_SPECTATOR)
+                               continue;
+
                p.chain = plist;
                plist = p;
        }
        // Now plist points to the whole list.
-       
+
        pfirst = plast = world;
 
-       i = 0;
+       i = j = 0;
        while(plist)
        {
                pprev = pbestprev = world;
                pbest = plist;
                for(p = plist; (pprev = p), (p = p.chain); )
                {
-                       if(PlayerTeamScore_Compare(p, pbest) > 0)
+                       if(PlayerTeamScore_Compare(p, pbest, teams, strict) > 0)
                        {
                                pbest = p;
                                pbestprev = pprev;
@@ -715,9 +736,13 @@ entity PlayerScore_Sort(.float field)
                        pbestprev.chain = pbest.chain;
                pbest.chain = world;
 
-               pbest.field = ++i;
+               ++i;
+               if(!plast || PlayerTeamScore_Compare(plast, pbest, teams, 0))
+                       j = i;
 
-               if not(pfirst)
+               pbest.field = j;
+
+               if (!pfirst)
                        pfirst = pbest;
                if(plast)
                        plast.chain = pbest;
@@ -740,7 +765,7 @@ float TeamScore_GetCompareValue(float t)
        }
 
        sk = teamscorekeepers[t - 1];
-       if not(sk)
+       if (!sk)
                return -999999999;
        s = sk.teamscores_primary;
        if(teamscores_flags_primary & SFL_ZERO_IS_WORST)
@@ -788,7 +813,7 @@ void Score_NicePrint_Team(entity to, float t, float w)
                s = "Scores:";
 
        s = strcat(s, strpad(max(0, NAMEWIDTH - strlennocol(s)), ""));
-       
+
        for(i = 0; i < MAX_SCORE; ++i)
                if(scores_label[i] != "")
                {
@@ -822,7 +847,7 @@ void Score_NicePrint_Player(entity to, entity p, float w)
                        break;
                }
        }
-       
+
        for(i = 0; i < MAX_SCORE; ++i)
                if(scores_label[i] != "")
                {
@@ -857,7 +882,7 @@ void Score_NicePrint(entity to)
                        ++t;
        w = bound(6, floor(SCORESWIDTH / t - 1), 9);
 
-       p = PlayerScore_Sort(score_dummyfield);
+       p = PlayerScore_Sort(score_dummyfield, 1, 1, 0);
        t = -1;
 
        if(!teamscores_entities_count)
@@ -871,12 +896,12 @@ void Score_NicePrint(entity to)
                t = p.team;
                p = p.chain;
        }
-       
+
        t = 0;
        FOR_EACH_CLIENT(p)
-       if(p.classname != "player")
+       if (!IS_PLAYER(p))
        {
-               if not(t)
+               if (!t)
                        Score_NicePrint_Spectators(to);
                Score_NicePrint_Spectator(to, p);
                t = 1;
@@ -907,6 +932,7 @@ void PlayerScore_TeamStats(void)
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(sk.(teamscores[i]) != 0)
                                if(teamscores_label[i] != "")
-                                       PlayerStats_TeamScore(t, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label[i]), sk.(teamscores[i]));
+                                       // the +1 is important here!
+                                       PlayerStats_TeamScore(t+1, strcat(PLAYERSTATS_SCOREBOARD, teamscores_label[i]), sk.(teamscores[i]));
        }
 }