]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/scoreboard.qc
Merge remote-tracking branch 'origin/master' into samual/notification_rewrite
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / scoreboard.qc
index 69a296796108022624ef2b5a7bb65c4fb9a9634d..e4e3767f1c2a5207c107c13ea607d5df4d8d76fb 100644 (file)
@@ -19,6 +19,7 @@ string TranslateScoresLabel(string l)
                case "bckills": return CTX(_("SCO^bckills"));
                case "bctime": return CTX(_("SCO^bctime"));
                case "caps": return CTX(_("SCO^caps"));
+               case "captime": return CTX(_("SCO^captime"));
                case "deaths": return CTX(_("SCO^deaths"));
                case "destroyed": return CTX(_("SCO^destroyed"));
                case "drops": return CTX(_("SCO^drops"));
@@ -128,23 +129,39 @@ void HUD_UpdatePlayerTeams()
        */
 }
 
+float HUD_CompareScore(float vl, float vr, float f)
+{
+       if(f & SFL_ZERO_IS_WORST)
+       {
+               if(vl == 0 && vr != 0)
+                       return 1;
+               if(vl != 0 && vr == 0)
+                       return 0;
+       }
+       if(vl > vr)
+               return IS_INCREASING(f);
+       if(vl < vr)
+               return IS_DECREASING(f);
+       return -1;
+}
+
 float HUD_ComparePlayerScores(entity left, entity right)
 {
-       float vl, vr;
+       float vl, vr, r, i;
        vl = GetPlayerColor(left.sv_entnum);
        vr = GetPlayerColor(right.sv_entnum);
 
        if(!left.gotscores)
-               vl = COLOR_SPECTATOR;
+               vl = FL_SPECTATOR;
        if(!right.gotscores)
-               vr = COLOR_SPECTATOR;
+               vr = FL_SPECTATOR;
 
        if(vl > vr)
                return true;
        if(vl < vr)
                return false;
 
-       if(vl == COLOR_SPECTATOR)
+       if(vl == FL_SPECTATOR)
        {
                // FIRST the one with scores (spectators), THEN the ones without (downloaders)
                // no other sorting
@@ -153,33 +170,23 @@ float HUD_ComparePlayerScores(entity left, entity right)
                return false;
        }
 
-       vl = left.scores[ps_primary];
-       vr = right.scores[ps_primary];
-       if(scores_flags[ps_primary] & SFL_ZERO_IS_WORST)
-       {
-               if(vl == 0 && vr != 0)
-                       return 1;
-               if(vl != 0 && vr == 0)
-                       return 0;
-       }
-       if(vl > vr)
-               return IS_INCREASING(scores_flags[ps_primary]);
-       if(vl < vr)
-               return IS_DECREASING(scores_flags[ps_primary]);
+       r = HUD_CompareScore(left.scores[ps_primary], right.scores[ps_primary], scores_flags[ps_primary]);
+       if (r >= 0)
+               return r;
+
+       r = HUD_CompareScore(left.scores[ps_secondary], right.scores[ps_secondary], scores_flags[ps_secondary]);
+       if (r >= 0)
+               return r;
 
-       vl = left.scores[ps_secondary];
-       vr = right.scores[ps_secondary];
-       if(scores_flags[ps_secondary] & SFL_ZERO_IS_WORST)
+       for(i = 0; i < MAX_SCORE; ++i)
        {
-               if(vl == 0 && vr != 0)
-                       return 1;
-               if(vl != 0 && vr == 0)
-                       return 0;
+               r = HUD_CompareScore(left.scores[i], right.scores[i], scores_flags[i]);
+               if (r >= 0)
+                       return r;
        }
-       if(vl > vr)
-               return IS_INCREASING(scores_flags[ps_secondary]);
-       if(vl < vr)
-               return IS_DECREASING(scores_flags[ps_secondary]);
+
+       if (left.sv_entnum < right.sv_entnum)
+               return true;
 
        return false;
 }
@@ -198,26 +205,30 @@ void HUD_UpdatePlayerPos(entity player)
 
 float HUD_CompareTeamScores(entity left, entity right)
 {
-       float vl, vr;
+       float i, r;
 
-       if(left.team == COLOR_SPECTATOR)
+       if(left.team == FL_SPECTATOR)
                return 1;
-       if(right.team == COLOR_SPECTATOR)
+       if(right.team == FL_SPECTATOR)
                return 0;
 
-       vl = left.teamscores[ts_primary];
-       vr = right.teamscores[ts_primary];
-       if(vl > vr)
-               return IS_INCREASING(teamscores_flags[ts_primary]);
-       if(vl < vr)
-               return IS_DECREASING(teamscores_flags[ts_primary]);
+       r = HUD_CompareScore(left.teamscores[ts_primary], right.teamscores[ts_primary], teamscores_flags[ts_primary]);
+       if (r >= 0)
+               return r;
 
-       vl = left.teamscores[ts_secondary];
-       vr = right.teamscores[ts_secondary];
-       if(vl > vr)
-               return IS_INCREASING(teamscores_flags[ts_secondary]);
-       if(vl < vr)
-               return IS_DECREASING(teamscores_flags[ts_secondary]);
+       r = HUD_CompareScore(left.teamscores[ts_secondary], right.teamscores[ts_secondary], teamscores_flags[ts_secondary]);
+       if (r >= 0)
+               return r;
+
+       for(i = 0; i < MAX_SCORE; ++i)
+       {
+               r = HUD_CompareScore(left.teamscores[i], right.teamscores[i], teamscores_flags[i]);
+               if (r >= 0)
+                       return r;
+       }
+
+       if (left.team < right.team)
+               return true;
 
        return false;
 }
@@ -254,6 +265,7 @@ void Cmd_HUD_Help()
        print(_("^3kd^7                       The kill-death ratio\n"));
        print(_("^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was captured\n"));
        print(_("^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
+       print(_("^3captime^7                  Time of fastest cap (CTF)\n"));
        print(_("^3fckills^7                  Number of flag carrier kills\n"));
        print(_("^3returns^7                  Number of flag returns\n"));
        print(_("^3drops^7                    Number of flag drops\n"));
@@ -304,20 +316,20 @@ void Cmd_HUD_SetFields(float argc)
 {
        float i, j, slash;
        string str, pattern;
-       float have_name, have_primary, have_secondary, have_separator;
+       float have_name = 0, have_primary = 0, have_secondary = 0, have_separator = 0;
        float missing;
 
        // TODO: re enable with gametype dependant cvars?
        if(argc < 3) // no arguments provided
-               argc = tokenizebyseparator(strcat("x ", autocvar_scoreboard_columns), " ");
+               argc = tokenizebyseparator(strcat("0 1 ", autocvar_scoreboard_columns), " ");
 
        if(argc < 3)
-               argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
+               argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
 
        if(argc == 3)
        {
                if(argv(2) == "default")
-                       argc = tokenizebyseparator(strcat("x ", HUD_DefaultColumnLayout()), " ");
+                       argc = tokenizebyseparator(strcat("0 1 ", HUD_DefaultColumnLayout()), " ");
                else if(argv(2) == "all")
                {
                        string s;
@@ -332,17 +344,17 @@ void Cmd_HUD_SetFields(float argc)
                        if(ps_secondary != ps_primary)
                                s = strcat(s, " ", scores_label[ps_secondary]);
                        s = strcat(s, " ", scores_label[ps_primary]);
-                       argc = tokenizebyseparator(strcat("x ", s), " ");
+                       argc = tokenizebyseparator(strcat("0 1 ", s), " ");
                }
        }
 
 
        hud_num_fields = 0;
 
-       hud_fontsize = HUD_GetFontsize("hud_fontsize"); 
+       hud_fontsize = HUD_GetFontsize("hud_fontsize");
 
        draw_beginBoldFont();
-       for(i = 0; i < argc - 1; ++i)
+       for(i = 1; i < argc - 1; ++i)
        {
                float nocomplain;
                str = argv(i+1);
@@ -657,11 +669,11 @@ string HUD_FixScoreboardColumnWidth(float i, string str)
 void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_number)
 {
        vector tmp, rgb;
-       rgb = GetTeamRGB(pl.team);
+       rgb = Team_ColorRGB(pl.team);
        string str;
        float i, field;
        float is_spec;
-       is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR);
+       is_spec = (GetPlayerColor(pl.sv_entnum) == FL_SPECTATOR);
 
        if((rgb == '1 1 1') && (!is_spec)) {
                rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
@@ -789,7 +801,7 @@ void HUD_PrintScoreboardItem(vector pos, entity pl, float is_self, float pl_numb
 vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
 {
        float body_table_height, i;
-       vector tmp, column_dim;
+       vector tmp = '0 0 0', column_dim = '0 0 0';
        entity pl;
 
        body_table_height = 1.25 * hud_fontsize_y * max(1, tm.team_size); // no player? show 1 empty line
@@ -905,7 +917,7 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz
        else
                for(pl = players.sort_next; pl; pl = pl.sort_next)
                {
-                       if(pl.team == COLOR_SPECTATOR)
+                       if(pl.team == FL_SPECTATOR)
                                continue;
                        HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), i);
                        pos_y += 1.25 * hud_fontsize_y;
@@ -953,7 +965,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
 
        drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
        pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
-       vector tmp;
+       vector tmp = '0 0 0';
        tmp_x = sbwidth;
        tmp_y = height * rows;
 
@@ -986,12 +998,10 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                g_minstagib = 1; // TODO: real detection for minstagib?
 
        float weapon_stats;
-
-       if (!acc_levels)
+       if(autocvar_scoreboard_accuracy_nocolors)
                rgb = '1 1 1';
-       else if (acc_col[0] == '-1 0 0')
-               for (i = 0; i < acc_levels; ++i)
-                       acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
+       else
+               Accuracy_LoadColors();
 
        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
        {
@@ -1021,20 +1031,8 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                        float padding;
                        padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
 
-                       if (acc_levels)
-                       {
-                               // find the max level lower than weapon_stats
-                               float j;
-                               j = acc_levels-1;
-                               while ( j && weapon_stats < acc_lev[j] )
-                                       --j;
-
-                               // inject color j+1 in color j, how much depending on how much weapon_stats is higher than level j
-                               float factor;
-                               factor = (weapon_stats - acc_lev[j]) / (acc_lev[j+1] - acc_lev[j]);
-                               rgb = acc_col[j];
-                               rgb = rgb + factor * (acc_col[j+1] - rgb);
-                       }
+                       if(!autocvar_scoreboard_accuracy_nocolors)
+                               rgb = Accuracy_GetColor(weapon_stats);
 
                        drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                }
@@ -1046,7 +1044,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
        }
 
        if(weapons_with_stats)
-               average_accuracy = floor(average_accuracy / weapons_with_stats);
+               average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
 
        if(rows == 2)
                pos_x -= weapon_width / 2;
@@ -1090,7 +1088,7 @@ vector HUD_DrawMapStats(vector pos, vector rgb, vector bg_size) {
        pos_y += 1.25 * hud_fontsize_y + autocvar_scoreboard_border_thickness;
        
        // draw table   
-       vector tmp;
+       vector tmp = '0 0 0';
        tmp_x = sbwidth;
        tmp_y = hud_fontsize_y * rows;
 
@@ -1122,7 +1120,7 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl,  vector rgb, vector bg_
                return pos;
 
        float is_spec;
-       is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR);
+       is_spec = (GetPlayerColor(pl.sv_entnum) == FL_SPECTATOR);
        vector hl_rgb;
        hl_rgb_x = autocvar_scoreboard_color_bg_r + 0.5;
        hl_rgb_y = autocvar_scoreboard_color_bg_g + 0.5;
@@ -1131,7 +1129,7 @@ vector HUD_DrawScoreboardRankings(vector pos, entity pl,  vector rgb, vector bg_
        pos_y += hud_fontsize_y;
        drawstring(pos, _("Rankings"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
        pos_y += hud_fontsize_y + autocvar_scoreboard_border_thickness;
-       vector tmp;
+       vector tmp = '0 0 0';
        tmp_x = sbwidth;
        tmp_y = 1.25 * hud_fontsize_y * RANKINGS_RECEIVED_CNT;
 
@@ -1239,11 +1237,11 @@ void HUD_DrawScoreboard()
                team_score_baseoffset = eY * (2 * autocvar_scoreboard_border_thickness + hud_fontsize_y) - eX * (autocvar_scoreboard_border_thickness + hud_fontsize_x * 0.25);
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
                {
-                       if(tm.team == COLOR_SPECTATOR)
+                       if(tm.team == FL_SPECTATOR)
                                continue;
 
                        draw_beginBoldFont();
-                       rgb = GetTeamRGB(tm.team);
+                       rgb = Team_ColorRGB(tm.team);
                        str = ftos(tm.(teamscores[ts_primary]));
                        drawstring(pos + team_score_baseoffset - eX * stringwidth(str, FALSE, hud_fontsize * 1.5), str, hud_fontsize * 1.5, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
 
@@ -1256,16 +1254,26 @@ void HUD_DrawScoreboard()
 
                        pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
                }
+
+#ifdef GMQCC
+               rgb = '0 0 0';
+#endif
+               rgb_x = autocvar_scoreboard_color_bg_r;
+               rgb_y = autocvar_scoreboard_color_bg_g;
+               rgb_z = autocvar_scoreboard_color_bg_b;
        }
        else
        {
+#ifdef GMQCC
+               rgb = '0 0 0';
+#endif
                rgb_x = autocvar_scoreboard_color_bg_r;
                rgb_y = autocvar_scoreboard_color_bg_g;
                rgb_z = autocvar_scoreboard_color_bg_b;
 
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
                {
-                       if(tm.team == COLOR_SPECTATOR)
+                       if(tm.team == FL_SPECTATOR)
                                continue;
 
                        pos = HUD_Scoreboard_MakeTable(pos, tm, rgb, bg_size);
@@ -1281,18 +1289,18 @@ void HUD_DrawScoreboard()
                        drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_holder), hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                        pos_y += 1.25 * hud_fontsize_y;
                }
-               pos = HUD_DrawScoreboardRankings(pos, pl, rgb, bg_size);
+               pos = HUD_DrawScoreboardRankings(pos, playerslots[player_localnum], rgb, bg_size);
        }
        else if(autocvar_scoreboard_accuracy && spectatee_status != -1 && !warmup_stage) {
                if(teamplay)
-                       pos = HUD_DrawScoreboardAccuracyStats(pos, GetTeamRGB(myteam), bg_size);
+                       pos = HUD_DrawScoreboardAccuracyStats(pos, Team_ColorRGB(myteam), bg_size);
                else
                        pos = HUD_DrawScoreboardAccuracyStats(pos, rgb, bg_size);
        }
 
                
        if(teamplay)
-               pos = HUD_DrawMapStats(pos, GetTeamRGB(myteam), bg_size);
+               pos = HUD_DrawMapStats(pos, Team_ColorRGB(myteam), bg_size);
        else
                pos = HUD_DrawMapStats(pos, rgb, bg_size);
 
@@ -1302,7 +1310,7 @@ void HUD_DrawScoreboard()
        tmp = pos;
        for(pl = players.sort_next; pl; pl = pl.sort_next)
        {
-               if(pl.team != COLOR_SPECTATOR)
+               if(pl.team != FL_SPECTATOR)
                        continue;
                pos_y += 1.25 * hud_fontsize_y;
                HUD_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localnum), specs);
@@ -1372,9 +1380,29 @@ void HUD_DrawScoreboard()
                }
        }
 
-
        pos_y += 1.2 * hud_fontsize_y;
        drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
 
+       // print information about respawn status
+       float respawn_time = getstatf(STAT_RESPAWN_TIME);
+       if(respawn_time)
+       {
+               if(respawn_time < 0)
+               {
+                       // a negative number means we are awaiting respawn, time value is still the same
+                       respawn_time *= -1; // remove mark now that we checked it
+                       respawn_time = max(time, respawn_time); // don't show a negative value while the server is respawning the player (lag)
+                       
+                       str = sprintf(_("^1Respawning in ^3%s^1 seconds..."), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals));
+               }
+               else if(time < respawn_time)
+                       str = sprintf(_("You are dead, wait ^3%s^7 seconds before respawning"), ftos_decimals(respawn_time - time, autocvar_scoreboard_respawntime_decimals));
+               else if(time >= respawn_time)
+                       str = sprintf(_("You are dead, press ^2%s^7 to respawn"), getcommandkey("jump", "+jump"));
+
+               pos_y += 1.2 * hud_fontsize_y;
+               drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, TRUE, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+       }
+
        scoreboard_bottom = pos_y + 2 * hud_fontsize_y;
 }