X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fclient%2Fhud%2Fpanel%2Fscoreboard.qc;h=0d0a44b6a295f839a7516ac210f96a685edee8bc;hp=c4e87a3cd9f15c4bfccc9892bc569e5cea728056;hb=7694d3a08ee8c23663b5e2be32a43e40a43cd2e0;hpb=4ef98ee6edc20f834fe6b9841fa21650b4b418d7 diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index c4e87a3cd..0d0a44b6a 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -1,18 +1,20 @@ #include "scoreboard.qh" -#include #include +#include +#include +#include #include #include -#include "quickmenu.qh" -#include #include -#include +#include #include #include +#include #include #include #include +#include // Scoreboard (#24) @@ -29,9 +31,11 @@ void Scoreboard_Draw_Export(int fh) HUD_Write_Cvar("hud_panel_scoreboard_table_highlight"); HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha"); HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha_self"); + HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha_eliminated"); HUD_Write_Cvar("hud_panel_scoreboard_bg_teams_color_team"); HUD_Write_Cvar("hud_panel_scoreboard_accuracy_doublerows"); HUD_Write_Cvar("hud_panel_scoreboard_accuracy_nocolors"); + HUD_Write_Cvar("hud_panel_scoreboard_spectators_position"); } const int MAX_SBT_FIELDS = MAX_SCORE; @@ -51,6 +55,7 @@ float sbt_fg_alpha_self; bool sbt_highlight; float sbt_highlight_alpha; float sbt_highlight_alpha_self; +float sbt_highlight_alpha_eliminated; // provide basic panel cvars to old clients // TODO remove them after a future release (0.8.2+) @@ -73,9 +78,11 @@ float autocvar_hud_panel_scoreboard_table_fg_alpha_self = 1; bool autocvar_hud_panel_scoreboard_table_highlight = true; float autocvar_hud_panel_scoreboard_table_highlight_alpha = 0.2; float autocvar_hud_panel_scoreboard_table_highlight_alpha_self = 0.4; +float autocvar_hud_panel_scoreboard_table_highlight_alpha_eliminated = 0.6; float autocvar_hud_panel_scoreboard_bg_teams_color_team = 0; float autocvar_hud_panel_scoreboard_namesize = 15; float autocvar_hud_panel_scoreboard_team_size_position = 0; +float autocvar_hud_panel_scoreboard_spectators_position = 1; bool autocvar_hud_panel_scoreboard_accuracy = true; bool autocvar_hud_panel_scoreboard_accuracy_doublerows = false; @@ -83,6 +90,13 @@ bool autocvar_hud_panel_scoreboard_accuracy_nocolors = false; float autocvar_hud_panel_scoreboard_accuracy_showdelay = 2; float autocvar_hud_panel_scoreboard_accuracy_showdelay_minpos = 0.75; +bool autocvar_hud_panel_scoreboard_itemstats = true; +bool autocvar_hud_panel_scoreboard_itemstats_doublerows = false; +int autocvar_hud_panel_scoreboard_itemstats_filter = 1; +int autocvar_hud_panel_scoreboard_itemstats_filter_mask = 12; +float autocvar_hud_panel_scoreboard_itemstats_showdelay = 2.2; // slightly more delayed than accuracy +float autocvar_hud_panel_scoreboard_itemstats_showdelay_minpos = 0.75; + bool autocvar_hud_panel_scoreboard_dynamichud = false; float autocvar_hud_panel_scoreboard_maxheight = 0.6; @@ -90,6 +104,9 @@ bool autocvar_hud_panel_scoreboard_others_showscore = true; bool autocvar_hud_panel_scoreboard_spectators_showping = true; bool autocvar_hud_panel_scoreboard_spectators_aligned = false; float autocvar_hud_panel_scoreboard_minwidth = 0.4; +bool autocvar_hud_panel_scoreboard_playerid = false; +string autocvar_hud_panel_scoreboard_playerid_prefix = "#"; +string autocvar_hud_panel_scoreboard_playerid_suffix = " "; // mode 0: returns translated label // mode 1: prints name and description of all the labels @@ -150,6 +167,8 @@ string Label_getInfo(string label, int mode) void PrintScoresLabels() { Label_getInfo(string_null, 1); } string TranslateScoresLabel(string label) { return Label_getInfo(label, 0); } +#define SB_EXTRA_SORTING_FIELDS 5 +PlayerScoreField sb_extra_sorting_field[SB_EXTRA_SORTING_FIELDS]; void Scoreboard_InitScores() { int i, f; @@ -162,6 +181,13 @@ void Scoreboard_InitScores() ps_primary = it; if(f == SFL_SORT_PRIO_SECONDARY) ps_secondary = it; + if(ps_primary == it || ps_secondary == it) + continue; + if (scores_label(it) == "kills") sb_extra_sorting_field[0] = it; + if (scores_label(it) == "deaths") sb_extra_sorting_field[1] = it; + if (scores_label(it) == "suicides") sb_extra_sorting_field[2] = it; + if (scores_label(it) == "dmg") sb_extra_sorting_field[3] = it; + if (scores_label(it) == "dmgtaken") sb_extra_sorting_field[4] = it; }); if(ps_secondary == NULL) ps_secondary = ps_primary; @@ -183,6 +209,11 @@ void Scoreboard_InitScores() //float lastpnum; void Scoreboard_UpdatePlayerTeams() { + static float update_time; + if (time <= update_time) + return; + update_time = time; + entity pl, tmp; //int num = 0; for(pl = players.sort_next; pl; pl = pl.sort_next) @@ -225,14 +256,8 @@ int Scoreboard_CompareScore(int vl, int vr, int f) float Scoreboard_ComparePlayerScores(entity left, entity right) { - float vl, vr, r; - vl = entcs_GetTeam(left.sv_entnum); - vr = entcs_GetTeam(right.sv_entnum); - - if(!left.gotscores) - vl = NUM_SPECTATOR; - if(!right.gotscores) - vr = NUM_SPECTATOR; + int vl = (left.gotscores) ? entcs_GetTeam(left.sv_entnum) : NUM_SPECTATOR; + int vr = (right.gotscores) ? entcs_GetTeam(right.sv_entnum) : NUM_SPECTATOR; if(vl > vr) return true; @@ -248,18 +273,26 @@ float Scoreboard_ComparePlayerScores(entity left, entity right) return false; } - r = Scoreboard_CompareScore(left.scores(ps_primary), right.scores(ps_primary), scores_flags(ps_primary)); - if (r >= 0) - return r; - - r = Scoreboard_CompareScore(left.scores(ps_secondary), right.scores(ps_secondary), scores_flags(ps_secondary)); - if (r >= 0) - return r; + entity fld = NULL; + int r; + for (int i = -2; i < SB_EXTRA_SORTING_FIELDS; ++i) + { + if (i < 0) + { + if (!fld) fld = ps_primary; + else if (ps_secondary == ps_primary) continue; + else fld = ps_secondary; + } + else + { + fld = sb_extra_sorting_field[i]; + if (fld == ps_primary || fld == ps_secondary) continue; + } + if (!fld) continue; - FOREACH(Scores, true, { - r = Scoreboard_CompareScore(left.scores(it), right.scores(it), scores_flags(it)); + r = Scoreboard_CompareScore(left.scores(fld), right.scores(fld), scores_flags(fld)); if (r >= 0) return r; - }); + } if (left.sv_entnum < right.sv_entnum) return true; @@ -282,26 +315,29 @@ void Scoreboard_UpdatePlayerPos(entity player) float Scoreboard_CompareTeamScores(entity left, entity right) { - int i, r; - if(left.team == NUM_SPECTATOR) return 1; if(right.team == NUM_SPECTATOR) return 0; - r = Scoreboard_CompareScore(left.teamscores(ts_primary), right.teamscores(ts_primary), teamscores_flags(ts_primary)); - if (r >= 0) - return r; - - r = Scoreboard_CompareScore(left.teamscores(ts_secondary), right.teamscores(ts_secondary), teamscores_flags(ts_secondary)); - if (r >= 0) - return r; - - for(i = 0; i < MAX_TEAMSCORE; ++i) + int fld_idx = -1; + int r; + for(int i = -2; i < MAX_TEAMSCORE; ++i) { - r = Scoreboard_CompareScore(left.teamscores(i), right.teamscores(i), teamscores_flags(i)); - if (r >= 0) - return r; + if (i < 0) + { + if (fld_idx == -1) fld_idx = ts_primary; + else if (ts_secondary == ts_primary) continue; + else fld_idx = ts_secondary; + } + else + { + fld_idx = i; + if (fld_idx == ts_primary || fld_idx == ts_secondary) continue; + } + + r = Scoreboard_CompareScore(left.teamscores(fld_idx), right.teamscores(fld_idx), teamscores_flags(fld_idx)); + if (r >= 0) return r; } if (left.team < right.team) @@ -409,9 +445,16 @@ void Cmd_Scoreboard_SetFields(int argc) cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS); argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " "); } - else if(argv(2) == "all") + else if(argv(2) == "all" || argv(2) == "ALL") { - string s = "ping pl name |"; // scores without a label + string s = "ping pl name |"; // scores without label (not really scores) + if(argv(2) == "ALL") + { + // scores without label + s = strcat(s, " ", "sum"); + s = strcat(s, " ", "kdratio"); + s = strcat(s, " ", "frags"); + } FOREACH(Scores, true, { if(it != ps_primary) if(it != ps_secondary) @@ -450,25 +493,27 @@ void Cmd_Scoreboard_SetFields(int argc) continue; } + str = strtolower(str); strcpy(sbt_field_title[sbt_num_fields], TranslateScoresLabel(str)); sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize); - str = strtolower(str); PlayerScoreField j; switch(str) { + // fields without a label (not networked via the score system) case "ping": sbt_field[sbt_num_fields] = SP_PING; break; case "pl": sbt_field[sbt_num_fields] = SP_PL; break; - case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break; - case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break; case "name": case "nick": sbt_field[sbt_num_fields] = SP_NAME; have_name = true; break; case "|": sbt_field[sbt_num_fields] = SP_SEPARATOR; have_separator = true; break; - case "elo": sbt_field[sbt_num_fields] = SP_ELO; break; - case "dmg": case "damage": sbt_field[sbt_num_fields] = SP_DMG; break; - case "dmgtaken": case "damagetaken": sbt_field[sbt_num_fields] = SP_DMGTAKEN; break; - case "fps": sbt_field[sbt_num_fields] = SP_FPS; break; - default: + case "kd": case "kdr": case "kdratio": sbt_field[sbt_num_fields] = SP_KDRATIO; break; + case "sum": case "diff": case "k-d": sbt_field[sbt_num_fields] = SP_SUM; break; + case "frags": sbt_field[sbt_num_fields] = SP_FRAGS; break; + default: // fields with a label { + // map alternative labels + if (str == "damage") str = "dmg"; + if (str == "damagetaken") str = "dmgtaken"; + FOREACH(Scores, true, { if (str == strtolower(scores_label(it))) { j = it; @@ -476,16 +521,15 @@ void Cmd_Scoreboard_SetFields(int argc) } }); -LABEL(notfound) - if(str == "frags") - j = SP_FRAGS; - else - { - if(!nocomplain) - LOG_INFOF("^1Error:^7 Unknown score field: '%s'", str); - continue; - } -LABEL(found) + // NOTE: can't check STAT(SHOWFPS) here, if checked too early it returns false anyway + if(!nocomplain && str != "fps") // server can disable the fps field + LOG_INFOF("^1Error:^7 Unknown score field: '%s'", str); + + strfree(sbt_field_title[sbt_num_fields]); + sbt_field_size[sbt_num_fields] = 0; + continue; + + LABEL(found) sbt_field[sbt_num_fields] = j; if(j == ps_primary) have_primary = true; @@ -511,7 +555,7 @@ LABEL(found) { if(!have_name) { - strunzone(sbt_field_title[sbt_num_fields]); + strfree(sbt_field_title[sbt_num_fields]); for(i = sbt_num_fields; i > 0; --i) { sbt_field_title[i] = sbt_field_title[i-1]; @@ -525,7 +569,7 @@ LABEL(found) if(!have_separator) { - strunzone(sbt_field_title[sbt_num_fields]); + strfree(sbt_field_title[sbt_num_fields]); for(i = sbt_num_fields; i > 1; --i) { sbt_field_title[i] = sbt_field_title[i-1]; @@ -568,6 +612,13 @@ LABEL(found) sbt_field[sbt_num_fields] = SP_END; } +string Scoreboard_AddPlayerId(string pl_name, entity pl) +{ + string pref = autocvar_hud_panel_scoreboard_playerid_prefix; + string suf = autocvar_hud_panel_scoreboard_playerid_suffix; + return strcat(pref, itos(pl.sv_entnum + 1), suf, pl_name); +} + // MOVEUP:: vector sbt_field_rgb; string sbt_field_icon0; @@ -636,7 +687,10 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field) return str; case SP_NAME: - return Scoreboard_GetName(pl); + str = Scoreboard_GetName(pl); + if (autocvar_hud_panel_scoreboard_playerid) + str = Scoreboard_AddPlayerId(str, pl); + return str; case SP_FRAGS: f = pl.(scores(SP_KILLS)); @@ -857,7 +911,7 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i vector pos = item_pos; // put a "self indicator" beside the self row, unicode U+25C0 (black left-pointing triangle) if (is_self) - drawstring(pos+eX*(panel_size.x+.5*hud_fontsize.x)+eY, "\xE2\x97\x80", vec2(hud_fontsize.x, hud_fontsize.y), rgb, panel_fg_alpha, DRAWFLAG_NORMAL); + drawstring(pos + eX * (panel_size.x + 0.5 * hud_fontsize.x) + eY, "\xE2\x97\x80", hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL); pos.x += hud_fontsize.x * 0.5; pos.y += (1.25 - 1) / 2 * hud_fontsize.y; // center text vertically @@ -933,7 +987,7 @@ void Scoreboard_DrawItem(vector item_pos, vector rgb, entity pl, bool is_self, i } if(pl.eliminated) - drawfill(h_pos, h_size, '0 0 0', 0.5 * panel_fg_alpha, DRAWFLAG_NORMAL); + drawfill(h_pos, h_size, '0 0 0', sbt_highlight_alpha_eliminated, DRAWFLAG_NORMAL); } vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity ignored_pl, entity pl, int pl_number) @@ -984,7 +1038,10 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity else if(autocvar_hud_panel_scoreboard_others_showscore) field = Scoreboard_GetField(pl, SP_SCORE); - string str = textShortenToWidth(entcs_GetName(pl.sv_entnum), namesize, hud_fontsize, stringwidth_colors); + string str = entcs_GetName(pl.sv_entnum); + if (autocvar_hud_panel_scoreboard_playerid) + str = Scoreboard_AddPlayerId(str, pl); + str = textShortenToWidth(str, namesize, hud_fontsize, stringwidth_colors); float column_width = stringwidth(str, true, hud_fontsize); if((this_team == NUM_SPECTATOR) && autocvar_hud_panel_scoreboard_spectators_aligned) { @@ -1033,7 +1090,7 @@ vector Scoreboard_DrawOthers(vector item_pos, vector rgb, int this_team, entity { h_size.x = column_width + hud_fontsize.x * 0.25; h_size.y = hud_fontsize.y; - drawfill(pos - hud_fontsize.x * 0.25 * eX, h_size, '0 0 0', 0.5 * panel_fg_alpha, DRAWFLAG_NORMAL); + drawfill(pos - hud_fontsize.x * 0.25 * eX, h_size, '0 0 0', sbt_highlight_alpha_eliminated, DRAWFLAG_NORMAL); } pos.x += column_width; pos.x += hud_fontsize.x; @@ -1069,7 +1126,7 @@ vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size) panel_size.y += panel_bg_padding * 2; HUD_Panel_DrawBg(); - vector end_pos = panel_pos + eY * (panel_size.y + 0.5* hud_fontsize.y); + vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y); if(panel.current_panel_bg != "0") end_pos.y += panel_bg_border * 2; @@ -1151,7 +1208,7 @@ bool Scoreboard_WouldDraw() { return true; } - else if (scoreboard_showscores_force) + else if (scoreboard_showscores_force || MUTATOR_CALLHOOK(DrawScoreboard_Force)) return true; return false; } @@ -1159,14 +1216,7 @@ bool Scoreboard_WouldDraw() float average_accuracy; vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) { - if (frametime) - { - if (scoreboard_fade_alpha == 1) - scoreboard_acc_fade_alpha = min(1, scoreboard_acc_fade_alpha + frametime * 10); - else - scoreboard_acc_fade_alpha = 1; // sync fading with the scoreboard - } - vector initial_pos = pos; + scoreboard_acc_fade_alpha = min(scoreboard_fade_alpha, scoreboard_acc_fade_alpha + frametime * 10); WepSet weapons_stat = WepSet_GetFromStat(); WepSet weapons_inmap = WepSet_GetFromStat_InMap(); @@ -1196,10 +1246,11 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) int rows = 1; if (autocvar_hud_panel_scoreboard_accuracy_doublerows && weapon_cnt >= floor((REGISTRY_COUNT(Weapons) - nHidden - 1) * 0.5)) rows = 2; - int columnns = ceil(weapon_cnt / rows); + int columns = ceil(weapon_cnt / rows); - float weapon_height = 29; - float height = hud_fontsize.y + weapon_height; + float aspect = max(0.001, autocvar_hud_panel_weapons_aspect); + float weapon_height = hud_fontsize.y * 2.3 / aspect; + float height = weapon_height + hud_fontsize.y; drawstring(pos + eX * panel_bg_padding, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL); pos.y += 1.25 * hud_fontsize.y; @@ -1215,7 +1266,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) HUD_Panel_DrawBg(); panel_bg_alpha = panel_bg_alpha_save; - vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y); + vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y); if(panel.current_panel_bg != "0") end_pos.y += panel_bg_border * 2; @@ -1228,7 +1279,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) pos = panel_pos; vector tmp = panel_size; - float weapon_width = tmp.x / columnns / rows; + float weapon_width = tmp.x / columns / rows; if (sbt_bg_alpha) drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL); @@ -1236,7 +1287,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) if(sbt_highlight) { // column highlighting - for (int i = 0; i < columnns; ++i) + for (int i = 0; i < columns; ++i) if ((i % 2) == 0) drawfill(pos + eX * weapon_width * rows * i, vec2(weapon_width * rows, height * rows), '0 0 0', sbt_highlight_alpha * scoreboard_acc_fade_alpha, DRAWFLAG_NORMAL); @@ -1281,11 +1332,8 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) weapons_with_stats += 1; average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy - string s; - s = sprintf("%d%%", weapon_stats * 100); - - float padding; - padding = (weapon_width - stringwidth(s, false, hud_fontsize)) / 2; // center the accuracy value + string s = sprintf("%d%%", weapon_stats * 100); + float padding = (weapon_width - stringwidth(s, false, hud_fontsize)) / 2; if(!autocvar_hud_panel_scoreboard_accuracy_nocolors) rgb = Accuracy_GetColor(weapon_stats); @@ -1294,7 +1342,7 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) } tmpos.x += weapon_width * rows; pos.x += weapon_width * rows; - if (rows == 2 && column == columnns - 1) { + if (rows == 2 && column == columns - 1) { tmpos.x = oldposx; tmpos.y += height; pos.y += height; @@ -1307,9 +1355,132 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size) panel_size.x += panel_bg_padding * 2; // restore initial width - if (scoreboard_acc_fade_alpha == 1) - return end_pos; - return initial_pos + (end_pos - initial_pos) * scoreboard_acc_fade_alpha; + return end_pos; +} + +bool is_item_filtered(entity it) +{ + if (!autocvar_hud_panel_scoreboard_itemstats_filter) + return false; + int mask = autocvar_hud_panel_scoreboard_itemstats_filter_mask; + if (mask <= 0) + return false; + if (it.instanceOfArmor || it.instanceOfHealth) + { + int ha_mask = floor(mask) % 10; + switch (ha_mask) + { + default: return false; + case 4: if (it == ITEM_HealthMega || it == ITEM_ArmorMega) return true; // else fallthrough + case 3: if (it == ITEM_HealthBig || it == ITEM_ArmorBig) return true; // else fallthrough + case 2: if (it == ITEM_HealthMedium || it == ITEM_ArmorMedium) return true; // else fallthrough + case 1: if (it == ITEM_HealthSmall || it == ITEM_ArmorSmall) return true; // else fallthrough + } + } + if (it.instanceOfAmmo) + { + int ammo_mask = floor(mask / 10) % 10; + return (ammo_mask == 1); + } + return false; +} + +vector Scoreboard_ItemStats_Draw(vector pos, vector rgb, vector bg_size) +{ + scoreboard_itemstats_fade_alpha = min(scoreboard_fade_alpha, scoreboard_itemstats_fade_alpha + frametime * 10); + + int disowned_cnt = 0; + int uninteresting_cnt = 0; + IL_EACH(default_order_items, true, { + int q = g_inventory.inv_items[it.m_id]; + //q = 1; // debug: display all items + if (is_item_filtered(it)) + ++uninteresting_cnt; + else if (!q) + ++disowned_cnt; + }); + int items_cnt = REGISTRY_COUNT(Items) - uninteresting_cnt; + int n = items_cnt - disowned_cnt; + if (n <= 0) return pos; + + int rows = (autocvar_hud_panel_scoreboard_itemstats_doublerows && n >= floor(REGISTRY_COUNT(Items) / 2)) ? 2 : 1; + int columns = max(6, ceil(n / rows)); + + float item_height = hud_fontsize.y * 2.3; + float height = item_height + hud_fontsize.y; + + drawstring(pos + eX * panel_bg_padding, _("Item stats"), hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + pos.y += 1.25 * hud_fontsize.y; + if(panel.current_panel_bg != "0") + pos.y += panel_bg_border; + + panel_pos = pos; + panel_size.y = height * rows; + panel_size.y += panel_bg_padding * 2; + + float panel_bg_alpha_save = panel_bg_alpha; + panel_bg_alpha *= scoreboard_itemstats_fade_alpha; + HUD_Panel_DrawBg(); + panel_bg_alpha = panel_bg_alpha_save; + + vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y); + if(panel.current_panel_bg != "0") + end_pos.y += panel_bg_border * 2; + + if(panel_bg_padding) + { + panel_pos += '1 1 0' * panel_bg_padding; + panel_size -= '2 2 0' * panel_bg_padding; + } + + pos = panel_pos; + vector tmp = panel_size; + + float item_width = tmp.x / columns / rows; + + if (sbt_bg_alpha) + drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", bg_size, tmp, rgb, sbt_bg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + + if(sbt_highlight) + { + // column highlighting + for (int i = 0; i < columns; ++i) + if ((i % 2) == 0) + drawfill(pos + eX * item_width * rows * i, vec2(item_width * rows, height * rows), '0 0 0', sbt_highlight_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + + // row highlighting + for (int i = 0; i < rows; ++i) + drawfill(pos + eY * (item_height + height * i), vec2(panel_size.x, hud_fontsize.y), rgb, sbt_highlight_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + } + + if (rows == 2) + pos.x += item_width / 2; + + float oldposx = pos.x; + vector tmpos = pos; + + int column = 0; + IL_EACH(default_order_items, !is_item_filtered(it), { + int n = g_inventory.inv_items[it.m_id]; + //n = 1 + floor(i * 3 + 4.8) % 7; // debug: display a value for each item + if (n <= 0) continue; + drawpic_aspect_skin(tmpos, it.m_icon, eX * item_width + eY * item_height, '1 1 1', panel_fg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + string s = ftos(n); + float padding = (item_width - stringwidth(s, false, hud_fontsize)) / 2; + drawstring(tmpos + vec2(padding, item_height), s, hud_fontsize, '1 1 1', panel_fg_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL); + tmpos.x += item_width * rows; + pos.x += item_width * rows; + if (rows == 2 && column == columns - 1) { + tmpos.x = oldposx; + tmpos.y += height; + pos.y += height; + } + ++column; + }); + + panel_size.x += panel_bg_padding * 2; // restore initial width + + return end_pos; } vector MapStats_DrawKeyValue(vector pos, string key, string value) { @@ -1359,7 +1530,7 @@ vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) { panel_size.y += panel_bg_padding * 2; HUD_Panel_DrawBg(); - vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y); + vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y); if(panel.current_panel_bg != "0") end_pos.y += panel_bg_border * 2; @@ -1393,7 +1564,9 @@ vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) { return end_pos; } - +int rankings_rows = 0; +int rankings_columns = 0; +int rankings_cnt = 0; vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size) { int i; @@ -1407,7 +1580,6 @@ vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector vector hl_rgb = rgb + '0.5 0.5 0.5'; - pos.y += hud_fontsize.y; drawstring(pos + eX * panel_bg_padding, ranktitle, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); pos.y += 1.25 * hud_fontsize.y; if(panel.current_panel_bg != "0") @@ -1432,20 +1604,25 @@ vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector float ranksize = 3 * hud_fontsize.x; float timesize = 5 * hud_fontsize.x; vector columnsize = vec2(ranksize + timesize + namesize + hud_fontsize.x, 1.25 * hud_fontsize.y); - int columns = max(1, floor((panel_size.x - 2 * panel_bg_padding) / columnsize.x)); - columns = min(columns, RANKINGS_RECEIVED_CNT); + rankings_columns = max(1, floor((panel_size.x - 2 * panel_bg_padding) / columnsize.x)); + rankings_columns = min(rankings_columns, RANKINGS_RECEIVED_CNT); + if (!rankings_cnt) + { + rankings_cnt = RANKINGS_RECEIVED_CNT; + rankings_rows = ceil(rankings_cnt / rankings_columns); + } // expand name column to fill the entire row - float available_space = (panel_size.x - 2 * panel_bg_padding - columnsize.x * columns) / columns; + float available_space = (panel_size.x - 2 * panel_bg_padding - columnsize.x * rankings_columns) / rankings_columns; namesize += available_space; columnsize.x += available_space; - panel_size.y = ceil(RANKINGS_RECEIVED_CNT / columns) * 1.25 * hud_fontsize.y; + panel_size.y = rankings_rows * 1.25 * hud_fontsize.y; panel_size.y += panel_bg_padding * 2; HUD_Panel_DrawBg(); - vector end_pos = panel_pos + eY * (panel_size.y + hud_fontsize.y); + vector end_pos = panel_pos + eY * (panel_size.y + 0.5 * hud_fontsize.y); if(panel.current_panel_bg != "0") end_pos.y += panel_bg_border * 2; @@ -1464,7 +1641,7 @@ vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector string str = ""; int column = 0, j = 0; string zoned_name_self = strzone(strdecolorize(entcs_GetName(player_localnum))); - for(i = 0; i < RANKINGS_RECEIVED_CNT; ++i) + for(i = 0; i < rankings_cnt; ++i) { float t; t = grecordtime[i]; @@ -1486,11 +1663,11 @@ vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector pos.y += 1.25 * hud_fontsize.y; j++; - if(j >= ceil(RANKINGS_RECEIVED_CNT / columns)) + if(j >= rankings_rows) { column++; j = 0; - pos.x += panel_size.x / columns; + pos.x += panel_size.x / rankings_columns; pos.y = panel_pos.y; } } @@ -1533,6 +1710,72 @@ bool Scoreboard_AccuracyStats_WouldDraw(float ypos) return true; } +bool have_item_stats; +bool Scoreboard_ItemStats_WouldDraw(float ypos) +{ + if (MUTATOR_CALLHOOK(DrawScoreboardItemStats)) + return false; + if (!autocvar_hud_panel_scoreboard_itemstats || !g_inventory || warmup_stage || ypos > 0.91 * vid_conheight) + return false; + + if (time < scoreboard_time + autocvar_hud_panel_scoreboard_itemstats_showdelay + && ypos > autocvar_hud_panel_scoreboard_itemstats_showdelay_minpos * vid_conheight + && !intermission) + { + return false; + } + + if (!have_item_stats) + { + IL_EACH(default_order_items, true, { + if (!is_item_filtered(it)) + { + int q = g_inventory.inv_items[it.m_id]; + //q = 1; // debug: display all items + if (q) + { + have_item_stats = true; + break; + } + } + }); + if (!have_item_stats) + return false; + } + + return true; +} + +vector Scoreboard_Spectators_Draw(vector pos) { + + entity pl, tm; + string str = ""; + + for(pl = players.sort_next; pl; pl = pl.sort_next) + { + if(pl.team == NUM_SPECTATOR) + { + for(tm = teams.sort_next; tm; tm = tm.sort_next) + if(tm.team == NUM_SPECTATOR) + break; + str = sprintf("%s (%d)", _("Spectators"), tm.team_size); + draw_beginBoldFont(); + drawstring(pos, str, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); + draw_endBoldFont(); + pos.y += 1.25 * hud_fontsize.y; + + pos = Scoreboard_DrawOthers(pos, '0 0 0', pl.team, NULL, pl, 0); + pos.y += 1.25 * hud_fontsize.y; + + break; + } + } + if (str != "") // if there's at least one spectator + pos.y += 0.5 * hud_fontsize.y; + + return pos; +} + void Scoreboard_Draw() { if(!autocvar__hud_configure) @@ -1541,7 +1784,7 @@ void Scoreboard_Draw() // frametime checks allow to toggle the scoreboard even when the game is paused if(scoreboard_active) { - if (scoreboard_fade_alpha < 1) + if (scoreboard_fade_alpha == 0) scoreboard_time = time; if(hud_configure_menu_open == 1) scoreboard_fade_alpha = 1; @@ -1568,6 +1811,7 @@ void Scoreboard_Draw() if (!scoreboard_fade_alpha) { scoreboard_acc_fade_alpha = 0; + scoreboard_itemstats_fade_alpha = 0; return; } } @@ -1588,6 +1832,7 @@ void Scoreboard_Draw() sbt_highlight = autocvar_hud_panel_scoreboard_table_highlight; sbt_highlight_alpha = autocvar_hud_panel_scoreboard_table_highlight_alpha * panel_fg_alpha; sbt_highlight_alpha_self = autocvar_hud_panel_scoreboard_table_highlight_alpha_self * panel_fg_alpha; + sbt_highlight_alpha_eliminated = autocvar_hud_panel_scoreboard_table_highlight_alpha_eliminated * panel_fg_alpha; sbt_fg_alpha = autocvar_hud_panel_scoreboard_table_fg_alpha * panel_fg_alpha; sbt_fg_alpha_self = autocvar_hud_panel_scoreboard_table_fg_alpha_self * panel_fg_alpha; @@ -1597,13 +1842,16 @@ void Scoreboard_Draw() float excess = max(0, max_namesize - autocvar_hud_panel_scoreboard_namesize * hud_fontsize.x); float fixed_scoreboard_width = bound(vid_conwidth * autocvar_hud_panel_scoreboard_minwidth, vid_conwidth - excess, vid_conwidth * 0.93); - panel_pos.x = 0.5 * (vid_conwidth - fixed_scoreboard_width); + scoreboard_left = 0.5 * (vid_conwidth - fixed_scoreboard_width); + scoreboard_right = scoreboard_left + fixed_scoreboard_width; + panel_pos.x = scoreboard_left; panel_size.x = fixed_scoreboard_width; Scoreboard_UpdatePlayerTeams(); + scoreboard_top = panel_pos.y; vector pos = panel_pos; - entity pl, tm; + entity tm; string str; vector str_pos; @@ -1813,50 +2061,56 @@ void Scoreboard_Draw() pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size); } + // draw scoreboard spectators before accuracy and item stats + if (autocvar_hud_panel_scoreboard_spectators_position == 0) { + pos = Scoreboard_Spectators_Draw(pos); + } + + // draw accuracy and item stats if (Scoreboard_AccuracyStats_WouldDraw(pos.y)) pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size); + if (Scoreboard_ItemStats_WouldDraw(pos.y)) + pos = Scoreboard_ItemStats_Draw(pos, panel_bg_color, bg_size); + + // draw scoreboard spectators after accuracy and item stats and before rankings + if (autocvar_hud_panel_scoreboard_spectators_position == 1) { + pos = Scoreboard_Spectators_Draw(pos); + } if(MUTATOR_CALLHOOK(ShowRankings)) { string ranktitle = M_ARGV(0, string); + string unit = GetSpeedUnit(autocvar_hud_panel_physics_speed_unit); if(race_speedaward) { - drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, ColorTranslateRGB(race_speedaward_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); + drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, unit, ColorTranslateRGB(race_speedaward_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); pos.y += 1.25 * hud_fontsize.y; } if(race_speedaward_alltimebest) { - drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, race_speedaward_alltimebest_unit, ColorTranslateRGB(race_speedaward_alltimebest_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); + drawcolorcodedstring(pos, sprintf(_("All-time fastest: %d%s ^7(%s^7)"), race_speedaward_alltimebest, unit, ColorTranslateRGB(race_speedaward_alltimebest_holder)), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); pos.y += 1.25 * hud_fontsize.y; } + if (race_speedaward || race_speedaward_alltimebest) + pos.y += 0.25 * hud_fontsize.y; pos = Scoreboard_Rankings_Draw(pos, ranktitle, playerslots[player_localnum], panel_bg_color, bg_size); } + else + rankings_cnt = 0; - pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size); - - // List spectators - for(pl = players.sort_next; pl; pl = pl.sort_next) - { - if(pl.team == NUM_SPECTATOR) - { - for(tm = teams.sort_next; tm; tm = tm.sort_next) - if(tm.team == NUM_SPECTATOR) - break; - str = sprintf("%s (%d)", _("Spectators"), tm.team_size); - draw_beginBoldFont(); - drawstring(pos, str, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); - draw_endBoldFont(); - pos.y += 1.25 * hud_fontsize.y; + // draw scoreboard spectators after rankings + if (autocvar_hud_panel_scoreboard_spectators_position == 2) { + pos = Scoreboard_Spectators_Draw(pos); + } - pos = Scoreboard_DrawOthers(pos, '0 0 0', pl.team, NULL, pl, 0); - pos.y += 1.25 * hud_fontsize.y; + pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size); - break; - } + // draw scoreboard spectators after mapstats + if (autocvar_hud_panel_scoreboard_spectators_position == 3) { + pos = Scoreboard_Spectators_Draw(pos); } // print information about respawn status float respawn_time = STAT(RESPAWN_TIME); - if(!intermission) - if(respawn_time) + if(!intermission && respawn_time) { if(respawn_time < 0) { @@ -1891,5 +2145,26 @@ void Scoreboard_Draw() drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); } - scoreboard_bottom = pos.y + 2 * hud_fontsize.y; + pos.y += hud_fontsize.y; + if (scoreboard_fade_alpha < 1) + scoreboard_bottom = scoreboard_top + (pos.y - scoreboard_top) * scoreboard_fade_alpha; + else if (pos.y != scoreboard_bottom) + { + if (pos.y > scoreboard_bottom) + scoreboard_bottom = min(pos.y, scoreboard_bottom + frametime * 10 * (pos.y - scoreboard_top)); + else + scoreboard_bottom = max(pos.y, scoreboard_bottom - frametime * 10 * (pos.y - scoreboard_top)); + } + + if (rankings_cnt) + { + if (scoreboard_fade_alpha == 1) + { + if (scoreboard_bottom > 0.95 * vid_conheight) + rankings_rows = max(1, rankings_rows - 1); + else if (scoreboard_bottom + 1.25 * hud_fontsize.y < 0.95 * vid_conheight) + rankings_rows = min(ceil(RANKINGS_RECEIVED_CNT / rankings_columns), rankings_rows + 1); + } + rankings_cnt = rankings_rows * rankings_columns; + } }