- before_script:
- - ln -s $PWD data/xonotic-data.pk3dir
-
- - git clone --depth=1 --branch=master https://gitlab.com/xonotic/gmqcc.git gmqcc
- - cd gmqcc && make -j $(nproc) && export QCC="$PWD/gmqcc"
- - cd ..
-
- report_cloc:
- stage: test
- script:
- - cloc --force-lang-def=qcsrc/tools/cloc.txt --sql 1 --sql-project xonotic qcsrc | sqlite3 code.db
- - sqlite3 code.db 'select file,nCode from t where nCode > 1000 order by nBlank+nComment+nCode desc'
-
- test_compilation_units:
- stage: test
- script:
- - ./qcsrc/tools/compilationunits.sh
-
- test_sv_game:
- stage: test
- script:
- - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces
- - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"
- - cd ..
-
- - mkdir -p data/maps
- - wget -O data/stormkeep.pk3 http://beta.xonotic.org/autobuild-bsp/latest/stormkeep.pk3
- - wget -O data/maps/stormkeep.mapinfo https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.mapinfo
- - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
- - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
- - make
- - EXPECT=d357b667dc459574d1b4ae1a195d3d1f
- - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
- | tee /dev/stderr
- | grep '^:'
- | grep -v '^:gamestart:'
- | grep -v '^:anticheat:'
- | md5sum | awk '{ print $1 }')
- - echo 'expected:' $EXPECT
- - echo ' actual:' $HASH
- - test "$HASH" == "$EXPECT"
- - exit $?
-
- test_sv_unit:
- stage: test
- script:
- - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces
- - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"
- - cd ..
-
- - mkdir maps && wget -O maps/gitlab-ci.bsp https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/_init/_init.bsp
- - make
- - while read line; do
- echo $line;
- if [[ $line == "All tests OK" ]]; then exit 0; fi;
- done < <(${ENGINE} +developer 1 +map gitlab-ci +sv_cmd runtest +exit)
- - exit 1
-
- # NOTE: The generated docs are incomplete - they don't contain code behind SVQC CSQC MENUQC GAMEQC ifdefs.
- # With them added to PREDEFINED, it would take over half an hour to generate the docs and even then
- # they might not be complete. Doxygen doesn't handle #elif and might not understand some QC definitions.
- doxygen: # rename to 'pages' when gitlab.com allows pages to exceed 100MiB
- stage: deploy
- script:
- - cd qcsrc && doxygen
- - mv html ../public
- - for i in {0..0}; do eval $(printf "echo \$id_rsa_%02d\n" $i) >> ~/.ssh/id_rsa_base64; done
- - base64 --decode ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa
- - chmod 600 ~/.ssh/id_rsa
- - echo -e "Host *\n\tStrictHostKeyChecking no\n\tLogLevel ERROR\n" >> ~/.ssh/config
- - git config --global user.name "Gitlab CI"
- - git config --global user.email "<>"
- - git clone --single-branch --depth 1 ${DEPLOY_HOST}:${DEPLOY_REPO} ~/deploy_
- - mkdir ~/deploy && mv ~/deploy_/.git ~/deploy && rm -r ~/deploy_
- - cp -r ../public/* ~/deploy
- - cd ~/deploy && git add -A . && git commit -m "Deploy ${CI_BUILD_REF}" && git push origin gh-pages
- artifacts:
- paths:
- - public
- only:
- - master
+ workflow:\r
+ rules:\r
+ - if: $CI_COMMIT_MESSAGE =~ /Transifex autosync/\r
+ when: never\r
+ - when: always\r
+ \r
+ before_script:\r
+ - ln -s $PWD data/xonotic-data.pk3dir\r
+ \r
+ - git clone --depth=1 --branch=main https://gitlab.com/xonotic/gmqcc.git gmqcc\r
+ - cd gmqcc && make -j $(nproc) && export QCC="$PWD/gmqcc"\r
+ - cd ..\r
+ \r
+ test_compilation_units:\r
+ rules:\r
+ - changes:\r
+ - qcsrc/**/*\r
+ stage: test\r
+ script:\r
+ - ./qcsrc/tools/compilationunits.sh\r
+ \r
+ test_sv_game:\r
+ stage: test\r
+ script:\r
+ - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces\r
+ - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"\r
+ - cd ..\r
+ \r
+ - mkdir -p data/maps\r
+ - wget -O data/stormkeep.pk3 http://beta.xonotic.org/autobuild-bsp/latest/stormkeep.pk3\r
+ - wget -O data/maps/stormkeep.mapinfo https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.mapinfo\r
+ - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints\r
+ - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache\r
+ - make\r
- - EXPECT=570561a503853d1224450fbdfb8b3315\r
++ - EXPECT=ae4d27dd465e976cd5afa35365eea0d7\r
+ - HASH=$(${ENGINE} -noconfig -nohome +timestamps 1 +exec serverbench.cfg\r
+ | tee /dev/stderr\r
+ | sed -e 's,^\[[^]]*\] ,,'\r
+ | grep '^:'\r
+ | grep -v '^:gamestart:'\r
+ | grep -v '^:anticheat:'\r
+ | md5sum | awk '{ print $1 }')\r
+ - echo 'expected:' $EXPECT\r
+ - echo ' actual:' $HASH\r
+ - test "$HASH" == "$EXPECT"\r
+ - exit $?\r
+ \r
+ test_sv_unit:\r
+ stage: test\r
+ script:\r
+ - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces\r
+ - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"\r
+ - cd ..\r
+ \r
+ - mkdir maps && wget -O maps/gitlab-ci.bsp https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/_init/_init.bsp\r
+ - make\r
+ - while read line; do\r
+ echo $line;\r
+ if [[ $line == "All tests OK" ]]; then exit 0; fi;\r
+ done < <(${ENGINE} +developer 1 +map gitlab-ci +sv_cmd runtest +exit)\r
+ - exit 1\r
+ \r
+ # NOTE: The generated docs are incomplete - they don't contain code behind SVQC CSQC MENUQC GAMEQC ifdefs.\r
+ # With them added to PREDEFINED, it would take over half an hour to generate the docs and even then\r
+ # they might not be complete. Doxygen doesn't handle #elif and might not understand some QC definitions.\r
+ doxygen: # rename to 'pages' when gitlab.com allows pages to exceed 100MiB\r
+ before_script:\r
+ - ln -s $PWD data/xonotic-data.pk3dir # is this needed?\r
+ - apt-get update\r
+ - apt-get -y install doxygen graphviz\r
+ stage: deploy\r
+ script:\r
+ - cd qcsrc && doxygen\r
+ - mv html ../public\r
+ - mkdir -p ~/.ssh\r
+ - for i in {0..0}; do eval $(printf "echo \$id_rsa_%02d\n" $i) >> ~/.ssh/id_rsa_base64; done\r
+ - base64 --decode ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa\r
+ - chmod 600 ~/.ssh/id_rsa\r
+ - echo -e "Host *\n\tStrictHostKeyChecking no\n\tLogLevel ERROR\n" >> ~/.ssh/config\r
+ - git config --global user.name "Gitlab CI"\r
+ - git config --global user.email "<>"\r
+ - git clone --single-branch --depth 1 ${DEPLOY_HOST}:${DEPLOY_REPO} ~/deploy_\r
+ - mkdir ~/deploy && mv ~/deploy_/.git ~/deploy && rm -r ~/deploy_\r
+ - cp -r ../public/* ~/deploy\r
+ - cd ~/deploy && git add -A . && git commit -m "Deploy ${CI_BUILD_REF}" && git push origin gh-pages\r
+ artifacts:\r
+ paths:\r
+ - public\r
+ only:\r
+ - master\r
#include "scoreboard.qh"
- #include <client/autocvars.qh>
#include <client/draw.qh>
- #include <client/main.qh>
+ #include <client/hud/panel/chat.qh>
+ #include <client/hud/panel/quickmenu.qh>
#include <client/hud/panel/racetimer.qh>
#include <client/hud/panel/weapons.qh>
- #include "quickmenu.qh"
- #include <common/ent_cs.qh>
#include <common/constants.qh>
- #include <common/net_linked.qh>
+ #include <common/ent_cs.qh>
#include <common/mapinfo.qh>
#include <common/minigames/cl_minigames.qh>
+ #include <common/net_linked.qh>
#include <common/scores.qh>
#include <common/stats.qh>
#include <common/teams.qh>
+ #include <common/items/inventory.qh>
// Scoreboard (#24)
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");
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+)
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_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;
+ bool autocvar_hud_panel_scoreboard_itemstats_filter = true;
+ 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;
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
case "revivals": if (!mode) return CTX(_("SCO^revivals")); else LOG_HELP(strcat("^3", "revivals", " ^7", _("Number of revivals")));
case "rounds": if (!mode) return CTX(_("SCO^rounds won")); else LOG_HELP(strcat("^3", "rounds", " ^7", _("Number of rounds won")));
case "score": if (!mode) return CTX(_("SCO^score")); else LOG_HELP(strcat("^3", "score", " ^7", _("Total score")));
+ case "strafe": if (!mode) return CTX(_("SCO^strafe")); else LOG_HELP(strcat("^3", "strafe", " ^7", _("Strafe efficiency (CTS)")));
case "suicides": if (!mode) return CTX(_("SCO^suicides")); else LOG_HELP(strcat("^3", "suicides", " ^7", _("Number of suicides")));
case "sum": if (!mode) return CTX(_("SCO^sum")); else LOG_HELP(strcat("^3", "sum", " ^7", _("Number of kills minus deaths")));
case "takes": if (!mode) return CTX(_("SCO^takes")); else LOG_HELP(strcat("^3", "takes", " ^7", _("Number of domination points taken (Domination)")));
" +ctf/pickups +ctf/fckills +ctf/returns +ctf/caps +ons/takes +ons/caps" \
" +lms/lives +lms/rank" \
" +kh/kckills +kh/losses +kh/caps" \
-" ?+rc/laps ?+rc/time +rc,cts/fastest" \
+" ?+rc/laps ?+rc/time ?+cts/strafe +rc,cts/fastest" \
" +as/objectives +nb/faults +nb/goals" \
" +ka/pickups +ka/bckills +ka/bctime +ft/revivals" \
" +dom/ticks +dom/takes" \
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;
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));
case SP_DMG: case SP_DMGTAKEN:
return sprintf("%.1f k", pl.(scores(field)) / 1000);
+ case SP_CTS_STRAFE:
+ {
+ float strafe_efficiency = pl.(scores(field)) / 10000;
+ if(strafe_efficiency < -1) return "";
+ sbt_field_rgb = '1 1 1' - (strafe_efficiency > 0 ? '1 0 1' : '0 1 1') * fabs(strafe_efficiency);
+ return sprintf("%.2f%%", strafe_efficiency * 100);
+ }
+
default: case SP_SCORE:
tmp = pl.(scores(field));
f = scores_flags(field);
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
}
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)
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)
{
{
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;
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;
{
return true;
}
- else if (scoreboard_showscores_force)
+ else if (scoreboard_showscores_force || MUTATOR_CALLHOOK(DrawScoreboard_Force))
return true;
return false;
}
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();
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;
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 uninteresting;
+ STATIC_INIT(default_order_items_label)
+ {
+ IL_EACH(default_order_items, true, {
+ if(!(it.instanceOfPowerup
+ || it == ITEM_HealthMega || it == ITEM_HealthBig
+ || it == ITEM_ArmorMega || it == ITEM_ArmorBig
+ ))
+ {
+ it.uninteresting = true;
+ }
+ });
+ }
+
+ 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 (autocvar_hud_panel_scoreboard_itemstats_filter && it.uninteresting)
+ ++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 columnns = max(6, ceil(n / rows));
+
+ float height = 40;
+ float fontsize = height * 1/3;
+ float item_height = height * 2/3;
+
+ 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 / columnns / 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 < columnns; ++i)
+ if ((i % 2) == 0)
+ drawfill(pos + '1 0 0' * item_width * rows * i, '0 1 0' * height * rows + '1 0 0' * item_width * rows, '0 0 0', sbt_highlight_alpha * scoreboard_itemstats_fade_alpha, DRAWFLAG_NORMAL);
+
+ // row highlighting
+ for (int i = 0; i < rows; ++i)
+ drawfill(pos + '0 1 0' * item_height + '0 1 0' * height * i, '1 0 0' * panel_size.x + '0 1 0' * fontsize, 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, !(autocvar_hud_panel_scoreboard_itemstats_filter && it.uninteresting), {
+ 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, '1 0 0' * item_width + '0 1 0' * 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, '1 0 0' * fontsize)) / 2; // center
+ drawstring(tmpos + '1 0 0' * padding + '0 1 0' * item_height, s, '1 1 0' * 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 == columnns - 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) {
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;
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;
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 (!(autocvar_hud_panel_scoreboard_itemstats_filter && it.uninteresting))
+ {
+ 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;
+ }
+
void Scoreboard_Draw()
{
if(!autocvar__hud_configure)
// 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;
if (!scoreboard_fade_alpha)
{
scoreboard_acc_fade_alpha = 0;
+ scoreboard_itemstats_fade_alpha = 0;
return;
}
}
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;
Scoreboard_UpdatePlayerTeams();
+ float initial_pos_y = panel_pos.y;
vector pos = panel_pos;
entity pl, tm;
string str;
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);
if(MUTATOR_CALLHOOK(ShowRankings)) {
string ranktitle = M_ARGV(0, string);
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 += 2 * hud_fontsize.y;
+ if (scoreboard_fade_alpha < 1)
+ scoreboard_bottom = initial_pos_y + (pos.y - initial_pos_y) * 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 - initial_pos_y));
+ else
+ scoreboard_bottom = max(pos.y, scoreboard_bottom - frametime * 10 * (pos.y - initial_pos_y));
+ }
}
GameRules_score_enabled(false);
GameRules_scoring(0, 0, 0, {
if (g_race_qualifying) {
+ field(SP_CTS_STRAFE, "strafe", 0);
field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
} else {
field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
CS(player).movement_y = -M_SQRT1_2 * wishspeed;
}
}
+ player.strafe_efficiency_sum += calculate_strafe_efficiency(player, CS(player).movement);
}
MUTATOR_HOOKFUNCTION(cts, reset_map_global)
Score_NicePrint(NULL);
race_ClearRecords();
- PlayerScore_Sort(race_place, 0, 1, 0);
+ PlayerScore_Sort(race_place, 0, true, false);
FOREACH_CLIENT(true, {
+ it.strafe_efficiency_best = -2;
+ PlayerScore_Set(it, SP_CTS_STRAFE, -20000);
+
if(it.race_place)
{
s = GameRules_scoring_add(it, RACE_FASTEST, 0);
race_PreparePlayer(player);
player.race_checkpoint = -1;
++ player.strafe_efficiency_sum = player.strafe_efficiency_tics = 0;
++ player.strafe_efficiency_best = -2;
++ PlayerScore_Set(player, SP_CTS_STRAFE, -20000);
- if(IS_REAL_CLIENT(player))
- {
- string rr = CTS_RECORD;
-
- msg_entity = player;
- race_send_recordtime(MSG_ONE);
- race_send_speedaward(MSG_ONE);
-
- speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
- speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
- race_send_speedaward_alltimebest(MSG_ONE);
-
- float i;
- int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
- race_send_rankings_cnt(MSG_ONE);
- for (i = 1; i <= m; ++i)
- {
- race_SendRankings(i, 0, 0, MSG_ONE);
- }
-
- player.strafe_efficiency_sum = player.strafe_efficiency_tics = 0;
- player.strafe_efficiency_best = -2;
- PlayerScore_Set(player, SP_CTS_STRAFE, -20000);
- }
+ race_SendAll(player, false);
}
MUTATOR_HOOKFUNCTION(cts, AbortSpeedrun)
frag_target.respawn_flags |= RESPAWN_FORCE;
race_AbandonRaceCheck(frag_target);
+ frag_target.strafe_efficiency_sum = frag_target.strafe_efficiency_tics = 0;
+
if(autocvar_g_cts_removeprojectiles)
{
IL_EACH(g_projectiles, it.owner == frag_target && (it.flags & FL_PROJECTILE),
{
entity player = M_ARGV(0, entity);
- if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
- {
- if (!player.stored_netname)
- player.stored_netname = strzone(uid2name(player.crypto_idfp));
- if(player.stored_netname != player.netname)
- {
- db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
- strcpy(player.stored_netname, player.netname);
- }
- }
-
- if (!IS_OBSERVER(player))
- {
- if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
- {
- speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
- speedaward_holder = player.netname;
- speedaward_uid = player.crypto_idfp;
- speedaward_lastupdate = time;
- }
- if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
- {
- string rr = CTS_RECORD;
- race_send_speedaward(MSG_ALL);
- speedaward_lastsent = speedaward_speed;
- if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
- {
- speedaward_alltimebest = speedaward_speed;
- speedaward_alltimebest_holder = speedaward_holder;
- speedaward_alltimebest_uid = speedaward_uid;
- db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
- db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
- race_send_speedaward_alltimebest(MSG_ALL);
- }
- }
- }
+ race_checkAndWriteName(player);
+ race_SpeedAwardFrame(player);
}
MUTATOR_HOOKFUNCTION(cts, ForbidThrowCurrentWeapon)
MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
{
entity player = M_ARGV(0, entity);
+ float strafe_efficiency_average = player.strafe_efficiency_sum / player.strafe_efficiency_tics;
+
+ if(player.strafe_efficiency_best < strafe_efficiency_average)
+ {
+ player.strafe_efficiency_best = strafe_efficiency_average;
+ PlayerScore_Set(player, SP_CTS_STRAFE, player.strafe_efficiency_best * 10000);
+ }
// useful to prevent cheating by running back to the start line and starting out with more speed
if(autocvar_g_cts_finish_kill_delay)
void cts_Initialize()
{
+ record_type = CTS_RECORD;
cts_ScoreRules();
}