]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/scoreboard.qc
Merge branch 'master' into terencehill/quickmenu
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / scoreboard.qc
index d86956b4d730818a75822f9a85a6983ea544e503..da5a7b2a771ab9cdb85a5101be323089fb21d9f7 100644 (file)
@@ -1,4 +1,14 @@
 #include "scoreboard.qh"
+#include "_all.qh"
+
+#include "hud.qh"
+
+#include "../common/constants.qh"
+#include "../common/mapinfo.qh"
+#include "../common/minigames/cl_minigames.qh"
+#include "../common/stats.qh"
+#include "../common/teams.qh"
+#include "../common/util.qh"
 
 float scoreboard_alpha_bg;
 float scoreboard_alpha_fg;
@@ -235,68 +245,68 @@ void HUD_UpdateTeamPos(entity Team)
 
 void Cmd_HUD_Help()
 {
-       print(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
-       print(_("^3|---------------------------------------------------------------|\n"));
-       print(_("Usage:\n"));
-       print(_("^2scoreboard_columns_set default\n"));
-       print(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
-       print(_("The following field names are recognized (case insensitive):\n"));
-       print(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
-
-       print(_("^3name^7 or ^3nick^7             Name of a player\n"));
-       print(_("^3ping^7                     Ping time\n"));
-       print(_("^3pl^7                       Packet loss\n"));
-       print(_("^3kills^7                    Number of kills\n"));
-       print(_("^3deaths^7                   Number of deaths\n"));
-       print(_("^3suicides^7                 Number of suicides\n"));
-       print(_("^3frags^7                    kills - suicides\n"));
-       print(_("^3kd^7                       The kill-death ratio\n"));
-       print(_("^3sum^7                      frags - deaths\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"));
-       print(_("^3lives^7                    Number of lives (LMS)\n"));
-       print(_("^3rank^7                     Player rank\n"));
-       print(_("^3pushes^7                   Number of players pushed into void\n"));
-       print(_("^3destroyed^7                Number of keys destroyed by pushing them into void\n"));
-       print(_("^3kckills^7                  Number of keys carrier kills\n"));
-       print(_("^3losses^7                   Number of times a key was lost\n"));
-       print(_("^3laps^7                     Number of laps finished (race/cts)\n"));
-       print(_("^3time^7                     Total time raced (race/cts)\n"));
-       print(_("^3fastest^7                  Time of fastest lap (race/cts)\n"));
-       print(_("^3ticks^7                    Number of ticks (DOM)\n"));
-       print(_("^3takes^7                    Number of domination points taken (DOM)\n"));
-       print(_("^3bckills^7                  Number of ball carrier kills\n"));
-       print(_("^3bctime^7                   Total amount of time holding the ball in Keepaway\n"));
-       print(_("^3score^7                    Total score\n\n"));
-
-       print(_("Before a field you can put a + or - sign, then a comma separated list\n"
+       LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"));
+       LOG_INFO(_("^3|---------------------------------------------------------------|\n"));
+       LOG_INFO(_("Usage:\n"));
+       LOG_INFO(_("^2scoreboard_columns_set default\n"));
+       LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ...\n"));
+       LOG_INFO(_("The following field names are recognized (case insensitive):\n"));
+       LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields.\n\n"));
+
+       LOG_INFO(_("^3name^7 or ^3nick^7             Name of a player\n"));
+       LOG_INFO(_("^3ping^7                     Ping time\n"));
+       LOG_INFO(_("^3pl^7                       Packet loss\n"));
+       LOG_INFO(_("^3kills^7                    Number of kills\n"));
+       LOG_INFO(_("^3deaths^7                   Number of deaths\n"));
+       LOG_INFO(_("^3suicides^7                 Number of suicides\n"));
+       LOG_INFO(_("^3frags^7                    kills - suicides\n"));
+       LOG_INFO(_("^3kd^7                       The kill-death ratio\n"));
+       LOG_INFO(_("^3sum^7                      frags - deaths\n"));
+       LOG_INFO(_("^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was captured\n"));
+       LOG_INFO(_("^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up\n"));
+       LOG_INFO(_("^3captime^7                  Time of fastest cap (CTF)\n"));
+       LOG_INFO(_("^3fckills^7                  Number of flag carrier kills\n"));
+       LOG_INFO(_("^3returns^7                  Number of flag returns\n"));
+       LOG_INFO(_("^3drops^7                    Number of flag drops\n"));
+       LOG_INFO(_("^3lives^7                    Number of lives (LMS)\n"));
+       LOG_INFO(_("^3rank^7                     Player rank\n"));
+       LOG_INFO(_("^3pushes^7                   Number of players pushed into void\n"));
+       LOG_INFO(_("^3destroyed^7                Number of keys destroyed by pushing them into void\n"));
+       LOG_INFO(_("^3kckills^7                  Number of keys carrier kills\n"));
+       LOG_INFO(_("^3losses^7                   Number of times a key was lost\n"));
+       LOG_INFO(_("^3laps^7                     Number of laps finished (race/cts)\n"));
+       LOG_INFO(_("^3time^7                     Total time raced (race/cts)\n"));
+       LOG_INFO(_("^3fastest^7                  Time of fastest lap (race/cts)\n"));
+       LOG_INFO(_("^3ticks^7                    Number of ticks (DOM)\n"));
+       LOG_INFO(_("^3takes^7                    Number of domination points taken (DOM)\n"));
+       LOG_INFO(_("^3bckills^7                  Number of ball carrier kills\n"));
+       LOG_INFO(_("^3bctime^7                   Total amount of time holding the ball in Keepaway\n"));
+       LOG_INFO(_("^3score^7                    Total score\n\n"));
+
+       LOG_INFO(_("Before a field you can put a + or - sign, then a comma separated list\n"
                "of game types, then a slash, to make the field show up only in these\n"
                "or in all but these game types. You can also specify 'all' as a\n"
                "field to show all fields available for the current game mode.\n\n"));
 
-       print(_("The special game type names 'teams' and 'noteams' can be used to\n"
+       LOG_INFO(_("The special game type names 'teams' and 'noteams' can be used to\n"
                "include/exclude ALL teams/noteams game modes.\n\n"));
 
-       print(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
-       print(_("will display name, ping and pl aligned to the left, and the fields\n"
+       LOG_INFO(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"));
+       LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields\n"
                "right of the vertical bar aligned to the right.\n"));
-       print(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+       LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
                "other gamemodes except DM.\n"));
 }
 
 #define HUD_DefaultColumnLayout() \
 "ping pl name | " \
-"-teams,race,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,race,ka/suicides +ft,tdm/suicides -race,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
+"-teams,rc,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,rc,ka/suicides +ft,tdm/suicides -rc,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
 "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes " \
 "+lms/lives +lms/rank " \
 "+kh/caps +kh/pushes +kh/destroyed " \
-"?+race/laps ?+race/time ?+race/fastest " \
+"?+rc/laps ?+rc/time ?+rc/fastest " \
 "+as/objectives +nb/faults +nb/goals +ka/pickups +ka/bckills +ka/bctime +ft/revivals " \
-"-lms,race,nb/score"
+"-lms,rc,nb/score"
 
 void Cmd_HUD_SetFields(float argc)
 {
@@ -349,7 +359,6 @@ void Cmd_HUD_SetFields(float argc)
 
        hud_fontsize = HUD_GetFontsize("hud_fontsize");
 
-       draw_beginBoldFont();
        for(i = 1; i < argc - 1; ++i)
        {
                float nocomplain;
@@ -377,41 +386,38 @@ void Cmd_HUD_SetFields(float argc)
                hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
                str = strtolower(str);
 
-               if(str == "ping") {
-                       hud_field[hud_num_fields] = SP_PING;
-               } else if(str == "pl") {
-                       hud_field[hud_num_fields] = SP_PL;
-               } else if(str == "kd" || str == "kdr" || str == "kdratio" || str == "k/d") {
-                       hud_field[hud_num_fields] = SP_KDRATIO;
-               } else if(str == "sum" || str == "diff" || str == "k-d") {
-                       hud_field[hud_num_fields] = SP_SUM;
-               } else if(str == "name" || str == "nick") {
-                       hud_field[hud_num_fields] = SP_NAME;
-                       have_name = 1;
-               } else if(str == "|") {
-                       hud_field[hud_num_fields] = SP_SEPARATOR;
-                       have_separator = 1;
-               } else {
-                       for(j = 0; j < MAX_SCORE; ++j)
-                               if(str == strtolower(scores_label[j]))
-                                       goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
-:notfound
-                       if(str == "frags")
-                       {
-                               j = SP_FRAGS;
-                       }
-                       else
+               switch(str)
+               {
+                       case "ping": hud_field[hud_num_fields] = SP_PING; break;
+                       case "pl": hud_field[hud_num_fields] = SP_PL; break;
+                       case "pl": hud_field[hud_num_fields] = SP_PL; break;
+                       case "kd": case "kdr": case "kdratio": case "k/d": hud_field[hud_num_fields] = SP_KDRATIO; break;
+                       case "sum": case "diff": case "k-d": hud_field[hud_num_fields] = SP_SUM; break;
+                       case "name": case "nick": hud_field[hud_num_fields] = SP_NAME; have_name = true; break;
+                       case "|": hud_field[hud_num_fields] = SP_SEPARATOR; have_separator = true; break;
+                       default:
                        {
-                               if (!nocomplain)
-                                       printf("^1Error:^7 Unknown score field: '%s'\n", str);
-                               continue;
-                       }
+                               for(j = 0; j < MAX_SCORE; ++j)
+                                       if(str == strtolower(scores_label[j]))
+                                               goto found; // sorry, but otherwise fteqcc -O3 miscompiles this and warns about "unreachable code"
+
+:notfound
+                               if(str == "frags")
+                                       j = SP_FRAGS;
+                               else
+                               {
+                                       if(!nocomplain)
+                                               LOG_INFOF("^1Error:^7 Unknown score field: '%s'\n", str);
+                                       continue;
+                               }
 :found
-                       hud_field[hud_num_fields] = j;
-                       if(j == ps_primary)
-                               have_primary = 1;
-                       if(j == ps_secondary)
-                               have_secondary = 1;
+                               hud_field[hud_num_fields] = j;
+                               if(j == ps_primary)
+                                       have_primary = 1;
+                               if(j == ps_secondary)
+                                       have_secondary = 1;
+
+                       }
                }
                ++hud_num_fields;
                if(hud_num_fields >= MAX_HUD_FIELDS)
@@ -440,7 +446,7 @@ void Cmd_HUD_SetFields(float argc)
                        hud_title[0] = strzone(TranslateScoresLabel("name"));
                        hud_field[0] = SP_NAME;
                        ++hud_num_fields;
-                       print("fixed missing field 'name'\n");
+                       LOG_INFO("fixed missing field 'name'\n");
 
                        if(!have_separator)
                        {
@@ -455,7 +461,7 @@ void Cmd_HUD_SetFields(float argc)
                                hud_field[1] = SP_SEPARATOR;
                                hud_size[1] = stringwidth("|", false, hud_fontsize);
                                ++hud_num_fields;
-                               print("fixed missing field '|'\n");
+                               LOG_INFO("fixed missing field '|'\n");
                        }
                }
                else if(!have_separator)
@@ -465,7 +471,7 @@ void Cmd_HUD_SetFields(float argc)
                        hud_size[hud_num_fields] = stringwidth("|", false, hud_fontsize);
                        hud_field[hud_num_fields] = SP_SEPARATOR;
                        ++hud_num_fields;
-                       print("fixed missing field '|'\n");
+                       LOG_INFO("fixed missing field '|'\n");
                }
                if(!have_secondary)
                {
@@ -474,7 +480,7 @@ void Cmd_HUD_SetFields(float argc)
                        hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
                        hud_field[hud_num_fields] = ps_secondary;
                        ++hud_num_fields;
-                       printf("fixed missing field '%s'\n", scores_label[ps_secondary]);
+                       LOG_INFOF("fixed missing field '%s'\n", scores_label[ps_secondary]);
                }
                if(!have_primary)
                {
@@ -483,12 +489,11 @@ void Cmd_HUD_SetFields(float argc)
                        hud_size[hud_num_fields] = stringwidth(hud_title[hud_num_fields], false, hud_fontsize);
                        hud_field[hud_num_fields] = ps_primary;
                        ++hud_num_fields;
-                       printf("fixed missing field '%s'\n", scores_label[ps_primary]);
+                       LOG_INFOF("fixed missing field '%s'\n", scores_label[ps_primary]);
                }
        }
 
        hud_field[hud_num_fields] = SP_END;
-       draw_endBoldFont();
 }
 
 // MOVEUP::
@@ -868,7 +873,6 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz
        }
 
        // print the strings of the columns headers and draw the columns
-       draw_beginBoldFont();
        int i;
        for(i = 0; i < hud_num_fields; ++i)
        {
@@ -912,7 +916,6 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz
                        pos.x -= hud_fontsize.x;
                }
        }
-       draw_endBoldFont();
 
        pos.x = xmin;
        pos.y += 1.25 * hud_fontsize.y; // skip the header
@@ -953,6 +956,8 @@ vector HUD_Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_siz
 float HUD_WouldDrawScoreboard() {
        if (autocvar__hud_configure)
                return 0;
+       else if (QuickMenu_IsOpened())
+               return 0;
        else if (HUD_Radar_Clickable())
                return 0;
        else if (scoreboard_showscores)
@@ -961,7 +966,7 @@ float HUD_WouldDrawScoreboard() {
                return 1;
        else if (intermission == 2)
                return 0;
-       else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS)
+       else if (spectatee_status != -1 && getstati(STAT_HEALTH) <= 0 && autocvar_cl_deathscoreboard && gametype != MAPINFO_TYPE_CTS && !active_minigame)
                return 1;
        else if (scoreboard_showscores_force)
                return 1;
@@ -971,18 +976,40 @@ float HUD_WouldDrawScoreboard() {
 float average_accuracy;
 vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
 {
+       WepSet weapons_stat = WepSet_GetFromStat();
+       WepSet weapons_inmap = WepSet_GetFromStat_InMap();
+       float initial_posx = pos.x;
        int i;
-       int weapon_cnt = WEP_COUNT - 3; // either vaporizer/vortex are hidden, no port-o-launch, no tuba
-       float rows;
-       if(autocvar_scoreboard_accuracy_doublerows)
+       float weapon_stats;
+       int disownedcnt = 0;
+       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       {
+               self = get_weaponinfo(i);
+               if(!self.weapon)
+                       continue;
+
+               weapon_stats = weapon_accuracy[i-WEP_FIRST];
+
+               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+                       ++disownedcnt;
+       }
+
+       int weapon_cnt = WEP_COUNT - disownedcnt;
+
+       if(weapon_cnt <= 0)
+               return pos;
+
+       int rows;
+       if(autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor(WEP_COUNT * 0.5))
                rows = 2;
        else
                rows = 1;
+       int columnns = ceil(weapon_cnt / rows);
+
        float height = 40;
        float fontsize = height * 1/3;
        float weapon_height = height * 2/3;
-       float weapon_width = sbwidth / weapon_cnt;
-       float g_instagib = 0;
+       float weapon_width = sbwidth / columnns / rows;
 
        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;
@@ -997,7 +1024,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
        drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
 
        // column highlighting
-       for(i = 0; i < weapon_cnt/rows; ++i)
+       for(i = 0; i < columnns; ++i)
        {
                if(!(i % 2))
                        drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
@@ -1010,29 +1037,29 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
        }
 
        average_accuracy = 0;
-       float weapons_with_stats;
-       weapons_with_stats = 0;
+       int weapons_with_stats = 0;
        if(rows == 2)
                pos.x += weapon_width / 2;
 
-       if(switchweapon == WEP_VAPORIZER)
-               g_instagib = 1; // TODO: real detection for instagib?
-
-       float weapon_stats;
        if(autocvar_scoreboard_accuracy_nocolors)
                rgb = '1 1 1';
        else
                Accuracy_LoadColors();
 
-       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       float oldposx = pos.x;
+       vector tmpos = pos;
+
+       int column;
+       for(i = WEP_FIRST, column = 0; i <= WEP_LAST; ++i)
        {
                self = get_weaponinfo(i);
                if (!self.weapon)
                        continue;
-               if ((i == WEP_VORTEX && g_instagib) || i == WEP_PORTO || (i == WEP_VAPORIZER && !g_instagib) || i == WEP_TUBA) // skip port-o-launch, vortex || vaporizer and tuba
-                       continue;
                weapon_stats = weapon_accuracy[i-WEP_FIRST];
 
+               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+                       continue;
+
                float weapon_alpha;
                if(weapon_stats >= 0)
                        weapon_alpha = scoreboard_alpha_fg;
@@ -1040,7 +1067,7 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                        weapon_alpha = 0.2 * scoreboard_alpha_fg;
 
                // weapon icon
-               drawpic_aspect_skin(pos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(tmpos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
                // the accuracy
                if(weapon_stats >= 0) {
                        weapons_with_stats += 1;
@@ -1055,24 +1082,24 @@ vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
                        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);
+                       drawstring(tmpos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                }
+               tmpos.x += weapon_width * rows;
                pos.x += weapon_width * rows;
-               if(rows == 2 && i == 6) {
-                       pos.x -= sbwidth;
+               if(rows == 2 && column == columnns - 1) {
+                       tmpos.x = oldposx;
+                       tmpos.y += height;
                        pos.y += height;
                }
+               ++column;
        }
 
        if(weapons_with_stats)
                average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
 
-       if(rows == 2)
-               pos.x -= weapon_width / 2;
-       pos.x -= sbwidth;
        pos.y += height;
-
-       pos.y +=  1.25 * hud_fontsize.y;
+       pos.y += 1.25 * hud_fontsize.y;
+       pos.x = initial_posx;
        return pos;
 }