From a0cf5a6a07c5570eb2069df79630d12c0436d1f5 Mon Sep 17 00:00:00 2001 From: Des - Date: Mon, 2 Sep 2024 16:33:12 +0000 Subject: [PATCH] Add optional split times in infomessage hud, and print_cptimes command to display the stored splits --- qcsrc/client/command/cl_cmd.qc | 57 ++++++++++++----- qcsrc/client/hud/panel/infomessages.qc | 33 ++++++++++ qcsrc/client/hud/panel/racetimer.qc | 89 +++++++++++++++++++------- qcsrc/client/hud/panel/racetimer.qh | 3 +- qcsrc/client/main.qc | 24 ------- qcsrc/client/main.qh | 2 + xonotic-client.cfg | 1 + 7 files changed, 144 insertions(+), 65 deletions(-) diff --git a/qcsrc/client/command/cl_cmd.qc b/qcsrc/client/command/cl_cmd.qc index 45f15d3a1..2cbc02568 100644 --- a/qcsrc/client/command/cl_cmd.qc +++ b/qcsrc/client/command/cl_cmd.qc @@ -427,26 +427,50 @@ void LocalCommand_sendcvar(int request, int argc) } } +void LocalCommand_print_cptimes(int request) +{ + switch(request) + { + case CMD_REQUEST_COMMAND: + { + LOG_HELP(_("Checkpoint times:")); + for (int i = 0; i <= 255; ++i) + { + if (race_checkpoint_splits[i]) + LOG_HELP(race_checkpoint_splits[i]); + } + return; + } + default: + case CMD_REQUEST_USAGE: + { + LOG_HELP("Usage:^3 cl_cmd print_cptimes"); + LOG_HELP(" No arguments required, will show current or last run checkpoint times."); + return; + } + } +} + /* use this when creating a new command, making sure to place it in alphabetical order... also, ** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION! void LocalCommand_(int request) { - switch(request) - { - case CMD_REQUEST_COMMAND: - { - - return; - } - - default: - case CMD_REQUEST_USAGE: - { - LOG_HELP("Usage:^3 cl_cmd "); - LOG_HELP(" No arguments required."); - return; - } - } + switch(request) + { + case CMD_REQUEST_COMMAND: + { + + return; + } + + default: + case CMD_REQUEST_USAGE: + { + LOG_HELP("Usage:^3 cl_cmd "); + LOG_HELP(" No arguments required."); + return; + } + } } */ @@ -464,6 +488,7 @@ CLIENT_COMMAND(handlevote, "System to handle selecting a vote or option") { Loca CLIENT_COMMAND(hud, "Commands regarding/controlling the HUD system") { LocalCommand_hud(request, arguments); } CLIENT_COMMAND(localprint, "Create your own centerprint sent to yourself") { LocalCommand_localprint(request, arguments); } CLIENT_COMMAND(mv_download, "Retrieve mapshot picture from the server") { LocalCommand_mv_download(request, arguments); } +CLIENT_COMMAND(print_cptimes, "Print the stored checkpoint times for current or last run") { LocalCommand_print_cptimes(request); } CLIENT_COMMAND(sendcvar, "Send a cvar to the server (like cl_weaponpriority)") { LocalCommand_sendcvar(request, arguments); } void LocalCommand_macro_help() diff --git a/qcsrc/client/hud/panel/infomessages.qc b/qcsrc/client/hud/panel/infomessages.qc index 2774d6498..5866271ef 100644 --- a/qcsrc/client/hud/panel/infomessages.qc +++ b/qcsrc/client/hud/panel/infomessages.qc @@ -1,4 +1,6 @@ #include "infomessages.qh" +#include "racetimer.qh" // for race_checkpoint_splits +#include // for ISGAMETYPE(RACE) #include #include @@ -228,6 +230,37 @@ void HUD_InfoMessages() InfoMessage(s); } } + if(autocvar_cl_race_checkpoint_splits_hud && !spectatee_status) { + int lines[6]; + int ln = 5; + // show up to race_nextcheckpoint (not including) or everything + // if you are before start (0 or 254) + // (except race_laptime != 0 for race, means next is + // start+finish so don't show previous lap finish) + int i; + if (race_checkpoint != 0 && race_checkpoint != 254) + { // middle of run/race + i = race_checkpoint; + } + else if (ISGAMETYPE(RACE) && race_nextcheckpoint == 0) + { // before start, but on race, so don't keep old finish visible + i = 253; + } + else + { // before start, not on race (cts), keep old run cps visible + i = 255; + } + for (; ln >= 0 && i >= 0; --i) + { + if (race_checkpoint_splits[i]) + { + lines[ln] = i; + --ln; + } + } + for (int j = 0; j < 6; ++j) + InfoMessage(race_checkpoint_splits[lines[j]]); + } } else { diff --git a/qcsrc/client/hud/panel/racetimer.qc b/qcsrc/client/hud/panel/racetimer.qc index 072e6a0d1..4a76dbbd5 100644 --- a/qcsrc/client/hud/panel/racetimer.qc +++ b/qcsrc/client/hud/panel/racetimer.qc @@ -3,6 +3,12 @@ #include #include +// used for caching the string after passing through a checkpoint +float racetimer_lastcheckpoint; +string racetimer_checkpoint_comparison; +string racetimer_checkpoint_time; +bool racetimer_have_stored_splits; + // Race timer (#8) void HUD_RaceTimer_Export(int fh) @@ -96,6 +102,41 @@ string MakeRaceString(int cp, float mytime, float theirtime, float othertime, fl return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(ColorTranslateRGB(theirname), col, lapstr))); } +void ClearRaceSplits() { + bool once = true; + racetimer_lastcheckpoint = 0; + for (int i = 0; i <= 255; ++i) + { + if(race_checkpoint_splits[i] + && autocvar_cl_race_checkpoint_splits_console) + { + if(once) + { + LOG_HELP(_("Checkpoint times:")); + once = false; + } + LOG_HELP(race_checkpoint_splits[i]); + } + strfree(race_checkpoint_splits[i]); + } + racetimer_have_stored_splits = false; +} + +void StoreRaceSplits(float race_checkpoint, string forcetime, string s) { + // store checkpoint splits string for later printing + if (!entcs_IsSpectating(player_localnum)) + { + // 0 or 255 go to 255 as finish, strcpy does the free if needed + strcpy(race_checkpoint_splits[race_checkpoint ? race_checkpoint : 255], (forcetime != "") ? sprintf("%s %s", forcetime, s) : s); + } + + // cache + racetimer_lastcheckpoint = race_checkpoint; + strcpy(racetimer_checkpoint_comparison, s); + strcpy(racetimer_checkpoint_time, forcetime); + racetimer_have_stored_splits = true; +} + void HUD_RaceTimer () { if(!autocvar__hud_configure) @@ -164,36 +205,35 @@ void HUD_RaceTimer () a = bound(0, 2 - (time - race_checkpointtime), 1); s = ""; forcetime = ""; - if(a > 0) // just hit a checkpoint? + if(a > 0) // display a frozen split for the just reached checkpoint { - if(race_checkpoint != 254) + if(race_checkpoint != 254 && race_time != 0) { - if(race_time && race_previousbesttime) - s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, ((race_mypreviousbesttime) ? TIME_DECODE(race_time) - TIME_DECODE(race_mypreviousbesttime) : 0), 0, race_previousbestname); + if (race_checkpoint == racetimer_lastcheckpoint) + { + // use cached strings + s = racetimer_checkpoint_comparison; + forcetime = racetimer_checkpoint_time; + } else - s = MakeRaceString(race_checkpoint, 0, -1, 0, 0, race_previousbestname); - if(race_time) - forcetime = TIME_ENCODED_TOSTRING(race_time, false); - - // store checkpoint splits string for later printing - // check if we advanced to next cp - if (!entcs_IsSpectating(player_localnum) && race_checkpoint_splits_previous != race_checkpoint) { - // are we somehow overwriting something? how? - if (race_checkpoint_splits[race_checkpoint_splits_previous+1]) - { - LOG_WARNF("race_checkpoint_splits: overwriting #%f %s\n", - race_checkpoint_splits_previous+1, - race_checkpoint_splits[race_checkpoint_splits_previous+1]); - strfree(race_checkpoint_splits[race_checkpoint_splits_previous+1]); - } - - strcpy(race_checkpoint_splits[race_checkpoint_splits_previous+1], sprintf("%s %s", forcetime, s)); + // build checkpoint split strings + if(race_time && race_previousbesttime) + s = MakeRaceString(race_checkpoint, TIME_DECODE(race_time) - TIME_DECODE(race_previousbesttime), 0, ((race_mypreviousbesttime) ? TIME_DECODE(race_time) - TIME_DECODE(race_mypreviousbesttime) : 0), 0, race_previousbestname); + else + s = MakeRaceString(race_checkpoint, 0, -1, 0, 0, race_previousbestname); + if(race_time) + forcetime = TIME_ENCODED_TOSTRING(race_time, false); - // don't use ++ in case that checkpoints have jumps like 10th to 20th - race_checkpoint_splits_previous = race_checkpoint; + StoreRaceSplits(race_checkpoint, forcetime, s); } } + else + { + // clean cp splits on start + if(racetimer_have_stored_splits && race_time == 0) + ClearRaceSplits(); + } } else { @@ -249,6 +289,9 @@ void HUD_RaceTimer () } else { + if(racetimer_have_stored_splits && (race_time == 0 || time < STAT(GAMESTARTTIME))) + ClearRaceSplits(); + if(race_mycheckpointtime) { a = bound(0, 2 - (time - race_mycheckpointtime), 1); diff --git a/qcsrc/client/hud/panel/racetimer.qh b/qcsrc/client/hud/panel/racetimer.qh index 2efcd0815..d213584df 100644 --- a/qcsrc/client/hud/panel/racetimer.qh +++ b/qcsrc/client/hud/panel/racetimer.qh @@ -9,8 +9,7 @@ float race_checkpoint; float race_time; float race_laptime; float race_checkpointtime; -string race_checkpoint_splits[255]; -int race_checkpoint_splits_previous = 0; +string race_checkpoint_splits[256]; float race_previousbesttime; float race_mypreviousbesttime; string race_previousbestname; diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 954691779..9cf0185ed 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -1197,30 +1197,6 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew) race_penaltyaccumulator = 0; race_laptime = time; // valid } - - // show checkpoint splits after a run - // specs can switch players for confusing splits, deny service - // if hit 255 finish line or if finish line is 0 or if restarted - if (!entcs_IsSpectating(player_localnum) - && (race_checkpoint == 255 - || race_checkpoint < race_checkpoint_splits_previous)) - { - LOG_HELP(_("Checkpoint times:")); - for (int i = 0; i < 255; ++i) - { - // does this index have a split? - if (race_checkpoint_splits[i]) - { - // print it if enabled and free it - if (autocvar_cl_race_checkpoint_splits_console) - LOG_HELP(race_checkpoint_splits[i]); - strfree(race_checkpoint_splits[i]); - } - } - - // allow registering 0th cp in case we start at 254 start line - race_checkpoint_splits_previous = 0; - } break; case RACE_NET_CHECKPOINT_CLEAR: diff --git a/qcsrc/client/main.qh b/qcsrc/client/main.qh index e7972edc4..8b96b0833 100644 --- a/qcsrc/client/main.qh +++ b/qcsrc/client/main.qh @@ -22,8 +22,10 @@ bool autocvar_developer_csqcentities; // or the release after it to support the old-stable release // this can't be done now as players would lack these from their configs then bool autocvar_cl_race_checkpoint_splits_console; +bool autocvar_cl_race_checkpoint_splits_hud; #else AUTOCVAR_SAVE(cl_race_checkpoint_splits_console, bool, 1, "Print checkpoint splits to console"); +AUTOCVAR_SAVE(cl_race_checkpoint_splits_hud, bool, 1, "Show race checkpoint splits on HUD in infomessages"); #endif bool autocvar_cl_race_cptimes_onlyself; // TODO: move to race gamemode bool autocvar_cl_race_cptimes_showself = false; diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 4f36583a7..f61cb22ca 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -712,6 +712,7 @@ seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disabl seta cl_race_cptimes_showself 1 "Always show your own times as well as the current best on checkpoints in Race/CTS" seta cl_race_cptimes_onlyself 0 "Only show your own times on checkpoints in Race/CTS. Can be forced on by the server via g_race_cptimes_onlyself" seta cl_race_checkpoint_splits_console 1 "Print checkpoint splits to console" +seta cl_race_checkpoint_splits_hud 1 "Show race checkpoint splits on HUD in infomessages" seta cl_cts_noautoswitch 0 "Prevent forced switching to new weapons in CTS" -- 2.39.2