From 75257fbdd20ab2412640d6b74238a5590aff26c8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 2 Aug 2023 18:39:26 +0100 Subject: [PATCH 01/24] Fix instantaneous menu background image slideout on fade wipe If the renderdeltatics is lagged enough, perform no change - a smaller delta should be along shortly. --- src/k_menudraw.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index be39be922..b94665a9f 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -205,15 +205,18 @@ void M_DrawMenuBackground(void) V_DrawFixedPatch(8 * FRACUNIT, -bgText1Scroll + text1loop, FRACUNIT, V_SUBTRACT, text1, NULL); - bgText1Scroll += (MENUBG_TEXTSCROLL*renderdeltatics); - while (bgText1Scroll > text1loop) - bgText1Scroll -= text1loop; - V_DrawFixedPatch(-bgText2Scroll, (BASEVIDHEIGHT-8) * FRACUNIT, FRACUNIT, V_ADD, text2, NULL); V_DrawFixedPatch(-bgText2Scroll + text2loop, (BASEVIDHEIGHT-8) * FRACUNIT, FRACUNIT, V_ADD, text2, NULL); + if (renderdeltatics > 2*FRACUNIT) + return; // wipe hitch... + + bgText1Scroll += (MENUBG_TEXTSCROLL*renderdeltatics); + while (bgText1Scroll > text1loop) + bgText1Scroll -= text1loop; + bgText2Scroll += (MENUBG_TEXTSCROLL*renderdeltatics); while (bgText2Scroll > text2loop) bgText2Scroll -= text2loop; From 380a015e82644b453d17b094ae24a072cf82ef28 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 2 Aug 2023 18:41:54 +0100 Subject: [PATCH 02/24] Increase the amount the menu background has to slide, and slightly increase the speed to compensate Subjective, but means no corner of the image will be poking in over the fade. --- src/k_menudraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b94665a9f..ad92404a2 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -162,7 +162,7 @@ static fixed_t bgImageScroll = 0; static char bgImageName[9]; #define MENUBG_TEXTSCROLL 6 -#define MENUBG_IMAGESCROLL 32 +#define MENUBG_IMAGESCROLL 36 void M_UpdateMenuBGImage(boolean forceReset) { @@ -181,7 +181,7 @@ void M_UpdateMenuBGImage(boolean forceReset) if (forceReset == false && strcmp(bgImageName, oldName)) { - bgImageScroll = (BASEVIDWIDTH / 2)*FRACUNIT; + bgImageScroll = (3 * BASEVIDWIDTH) * (FRACUNIT / 4); } } From d0552381bc8034349b189f9fe7fbb1ffae9c19de Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 2 Aug 2023 18:48:03 +0100 Subject: [PATCH 03/24] Consistent background for cup select/level select/Time Attack submenus --- src/menus/play-local-race-time-attack.c | 44 ++++++++++++------------- src/menus/transient/level-select.c | 7 ++++ 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 701ec94c4..9ae5c5199 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -59,11 +59,11 @@ boolean M_TimeAttackInputs(INT32 ch) // see ta_e menuitem_t PLAY_TimeAttack[] = { - {IT_STRING | IT_SUBMENU, "Replay...", NULL, NULL, {.submenu = &PLAY_TAReplayDef}, 0, 0}, - {IT_STRING | IT_SUBMENU, "Guest...", NULL, NULL, {.submenu = &PLAY_TAReplayGuestDef}, 0, 0}, - {IT_STRING | IT_SUBMENU, "Ghosts...", NULL, NULL, {.submenu = &PLAY_TAGhostsDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Replay...", NULL, "MENUI006", {.submenu = &PLAY_TAReplayDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Guest...", NULL, "MENUI006", {.submenu = &PLAY_TAReplayGuestDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Ghosts...", NULL, "MENUI006", {.submenu = &PLAY_TAGhostsDef}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_CALL, "Start", NULL, NULL, {.routine = M_StartTimeAttack}, 0, 0}, + {IT_STRING | IT_CALL, "Start", NULL, "MENUI006", {.routine = M_StartTimeAttack}, 0, 0}, }; menu_t PLAY_TimeAttackDef = { @@ -98,15 +98,15 @@ typedef enum menuitem_t PLAY_TAReplay[] = { - {IT_STRING | IT_CALL, "Replay Best Time", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, - {IT_STRING | IT_CALL, "Replay Best Lap", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, + {IT_STRING | IT_CALL, "Replay Best Time", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, + {IT_STRING | IT_CALL, "Replay Best Lap", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_CALL, "Replay Last", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, - {IT_STRING | IT_CALL, "Replay Guest", NULL, NULL, {.routine = M_ReplayTimeAttack}, 0, 0}, - {IT_STRING | IT_ARROWS, "Replay Staff", NULL, NULL, {.routine = M_HandleStaffReplay}, 0, 0}, + {IT_STRING | IT_CALL, "Replay Last", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, + {IT_STRING | IT_CALL, "Replay Guest", NULL, "MENUI006", {.routine = M_ReplayTimeAttack}, 0, 0}, + {IT_STRING | IT_ARROWS, "Replay Staff", NULL, "MENUI006", {.routine = M_HandleStaffReplay}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_SUBMENU, "Back", NULL, NULL, {.submenu = &PLAY_TimeAttackDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Back", NULL, "MENUI006", {.submenu = &PLAY_TimeAttackDef}, 0, 0}, }; menu_t PLAY_TAReplayDef = { @@ -140,17 +140,17 @@ typedef enum menuitem_t PLAY_TAReplayGuest[] = { - {IT_HEADERTEXT|IT_HEADER, "Save as guest...", NULL, NULL, {NULL}, 0, 0}, + {IT_HEADERTEXT|IT_HEADER, "Save as guest...", NULL, "MENUI006", {NULL}, 0, 0}, - {IT_STRING | IT_CALL, "Best Time", NULL, NULL, {.routine = M_SetGuestReplay}, 0, 0}, - {IT_STRING | IT_CALL, "Best Lap", NULL, NULL, {.routine = M_SetGuestReplay}, 0, 0}, - {IT_STRING | IT_CALL, "Last Run", NULL, NULL, {.routine = M_SetGuestReplay}, 0, 0}, + {IT_STRING | IT_CALL, "Best Time", NULL, "MENUI006", {.routine = M_SetGuestReplay}, 0, 0}, + {IT_STRING | IT_CALL, "Best Lap", NULL, "MENUI006", {.routine = M_SetGuestReplay}, 0, 0}, + {IT_STRING | IT_CALL, "Last Run", NULL, "MENUI006", {.routine = M_SetGuestReplay}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_CALL, "Delete Guest", NULL, NULL, {.routine = M_SetGuestReplay}, 0, 0}, + {IT_STRING | IT_CALL, "Delete Guest", NULL, "MENUI006", {.routine = M_SetGuestReplay}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_SUBMENU, "Back", NULL, NULL, {.submenu = &PLAY_TimeAttackDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Back", NULL, "MENUI006", {.submenu = &PLAY_TimeAttackDef}, 0, 0}, }; @@ -184,14 +184,14 @@ typedef enum menuitem_t PLAY_TAGhosts[] = { - {IT_STRING | IT_CVAR, "Best Time", NULL, NULL, {.cvar = &cv_ghost_besttime}, 0, 0}, - {IT_STRING | IT_CVAR, "Best Lap", NULL, NULL, {.cvar = &cv_ghost_bestlap}, 0, 0}, - {IT_STRING | IT_CVAR, "Last", NULL, NULL, {.cvar = &cv_ghost_last}, 0, 0}, - {IT_DISABLED, "Guest", NULL, NULL, {.cvar = &cv_ghost_guest}, 0, 0}, - {IT_DISABLED, "Staff", NULL, NULL, {.cvar = &cv_ghost_staff}, 0, 0}, + {IT_STRING | IT_CVAR, "Best Time", NULL, "MENUI006", {.cvar = &cv_ghost_besttime}, 0, 0}, + {IT_STRING | IT_CVAR, "Best Lap", NULL, "MENUI006", {.cvar = &cv_ghost_bestlap}, 0, 0}, + {IT_STRING | IT_CVAR, "Last", NULL, "MENUI006", {.cvar = &cv_ghost_last}, 0, 0}, + {IT_DISABLED, "Guest", NULL, "MENUI006", {.cvar = &cv_ghost_guest}, 0, 0}, + {IT_DISABLED, "Staff", NULL, "MENUI006", {.cvar = &cv_ghost_staff}, 0, 0}, {IT_HEADERTEXT|IT_HEADER, "", NULL, NULL, {NULL}, 0, 0}, - {IT_STRING | IT_SUBMENU, "Back", NULL, NULL, {.submenu = &PLAY_TimeAttackDef}, 0, 0}, + {IT_STRING | IT_SUBMENU, "Back", NULL, "MENUI006", {.submenu = &PLAY_TimeAttackDef}, 0, 0}, }; menu_t PLAY_TAGhostsDef = { diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 13eed9aef..cf5343b98 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -252,6 +252,13 @@ boolean M_LevelListFromGametype(INT16 gt) PLAY_LevelSelectDef.music = \ PLAY_TimeAttackDef.music = \ currentMenu->music; + + if (gamestate == GS_MENU) + { + PLAY_CupSelectDef.menuitems[0].patch = \ + PLAY_LevelSelectDef.menuitems[0].patch = \ + currentMenu->menuitems[itemOn].patch; + } } // Obviously go to Cup Select in gametypes that have cups. From 73a5500b0e0fca7c4e6878c03798cb97f14d161d Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 2 Aug 2023 18:48:22 +0100 Subject: [PATCH 04/24] Full stops for game speed/difficulty descriptions, for consistency --- src/menus/play-local-race-difficulty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/menus/play-local-race-difficulty.c b/src/menus/play-local-race-difficulty.c index d9c00994e..4055cd3b8 100644 --- a/src/menus/play-local-race-difficulty.c +++ b/src/menus/play-local-race-difficulty.c @@ -7,11 +7,11 @@ menuitem_t PLAY_RaceDifficulty[] = { // For GP - {IT_STRING | IT_CVAR, "Difficulty", "Select the game difficulty", + {IT_STRING | IT_CVAR, "Difficulty", "Select the game difficulty.", "MENUI004", {.cvar = &cv_dummygpdifficulty}, 0, 0}, // Match Race - {IT_STRING | IT_CVAR, "Difficulty", "Select the game speed", + {IT_STRING | IT_CVAR, "Difficulty", "Select the game speed.", "MENUI005", {.cvar = &cv_dummykartspeed}, 0, 0}, // DISABLE THAT OPTION OUTSIDE OF MATCH RACE From efe02794d444fc769a04be857ef9b277062aefd0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Aug 2023 14:53:29 +0100 Subject: [PATCH 05/24] (re-)implement pages for the Statistics Menu Was previously a feature of older versions of SRB2, but newer releases have had more compact statistics menus. However, we now have wayyyyy more to track than SRB2 ever did, so this is now actually justified. Currently there are only two pages, and the first page is empty. This will change shortly. --- src/k_menu.h | 8 ++++ src/k_menudraw.c | 86 ++++++++++++++++++++--------------- src/menus/extras-statistics.c | 72 +++++++++++++++++++++++++++-- 3 files changed, 124 insertions(+), 42 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index ab3a26443..1505c8e96 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1259,7 +1259,15 @@ void M_DrawChallenges(void); void M_ChallengesTick(void); boolean M_ChallengesInputs(INT32 ch); +typedef enum +{ + statisticspage_basic = 0, + statisticspage_maps, + statisticspage_max +} statisticspage_t; + extern struct statisticsmenu_s { + statisticspage_t page; INT32 location; INT32 nummaps; INT32 numextramedals; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ad92404a2..67e703dc9 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5997,15 +5997,57 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) static void M_DrawStatsMaps(void) { - INT32 y = 80, i = -1; + INT32 y = 80, i; INT16 mnum; boolean dotopname = true, dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); INT32 location = statisticsmenu.location; + char beststr[256]; + + tic_t besttime = 0; + + INT32 mapsunfinished = 0; + + if (!statisticsmenu.maplist) + { + V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No maps!?"); + return; + } + + for (i = 0; i < nummapheaders; i++) + { + if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))) + continue; + + if (mapheaderinfo[i]->records.time <= 0) + { + mapsunfinished++; + continue; + } + + besttime += mapheaderinfo[i]->records.time; + } + + V_DrawThinString(20, 60, 0, "Combined time records:"); + + sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime)); + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, (mapsunfinished ? V_REDMAP : 0), beststr); + + if (mapsunfinished) + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, V_REDMAP, va("(%d unfinished)", mapsunfinished)); + else + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, 0, "(complete)"); + + V_DrawThinString(32, 70, 0, va("x %d/%d", M_CountMedals(false, false), M_CountMedals(true, false))); + V_DrawSmallMappedPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GOLD, GTC_MENUCACHE)); + if (location) V_DrawCharacter(10, y-(skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow + i = -1; + while ((mnum = statisticsmenu.maplist[++i]) != NEXTMAP_INVALID) { if (location) @@ -6136,12 +6178,8 @@ bottomarrow: void M_DrawStatistics(void) { char beststr[256]; - tic_t besttime = 0; - INT32 i; - INT32 mapsunfinished = 0; - { patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE); V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL); @@ -6213,43 +6251,17 @@ void M_DrawStatistics(void) V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42, 0, beststr); - if (!statisticsmenu.maplist) + switch (statisticsmenu.page) { - V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No maps!?"); - return; - } - - besttime = 0; - - for (i = 0; i < nummapheaders; i++) - { - if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))) - continue; - - if (mapheaderinfo[i]->records.time <= 0) + case statisticspage_maps: { - mapsunfinished++; - continue; + M_DrawStatsMaps(); + break; } - besttime += mapheaderinfo[i]->records.time; + default: + break; } - - V_DrawThinString(20, 60, 0, "Combined time records:"); - - sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime)); - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, (mapsunfinished ? V_REDMAP : 0), beststr); - - if (mapsunfinished) - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, V_REDMAP, va("(%d unfinished)", mapsunfinished)); - else - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, 0, "(complete)"); - - V_DrawThinString(32, 70, 0, va("x %d/%d", M_CountMedals(false, false), M_CountMedals(true, false))); - V_DrawSmallMappedPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GOLD, GTC_MENUCACHE)); - - M_DrawStatsMaps(); } #undef STATSSTEP diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index bc4843b27..787a633db 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -43,14 +43,12 @@ static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headere return true; } -void M_Statistics(INT32 choice) +static void M_StatisticsMaps(void) { cupheader_t *cup; UINT16 i; boolean headerexists; - (void)choice; - statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (nummapheaders+1 + numkartcupheaders), PU_STATIC, NULL); statisticsmenu.nummaps = 0; @@ -88,6 +86,46 @@ void M_Statistics(INT32 choice) { statisticsmenu.maxscroll = 0; } +} + +static void M_StatisticsPageInit(void) +{ + switch (statisticsmenu.page) + { + case statisticspage_maps: + { + M_StatisticsMaps(); + break; + } + + default: + break; + } +} + +static void M_StatisticsPageClear(void) +{ + switch (statisticsmenu.page) + { + case statisticspage_maps: + { + Z_Free(statisticsmenu.maplist); + statisticsmenu.maplist = NULL; + + break; + } + + default: + break; + } +} + +void M_Statistics(INT32 choice) +{ + (void)choice; + + statisticsmenu.page = statisticspage_basic; + M_StatisticsPageInit(); MISC_StatisticsDef.prevMenu = currentMenu; M_SetupNextMenu(&MISC_StatisticsDef, false); @@ -104,12 +142,36 @@ boolean M_StatisticsInputs(INT32 ch) M_GoBack(0); M_SetMenuDelay(pid); - Z_Free(statisticsmenu.maplist); - statisticsmenu.maplist = NULL; + M_StatisticsPageClear(); return true; } + if (menucmd[pid].dpad_lr != 0) + { + M_StatisticsPageClear(); + + statisticsmenu.page += + statisticspage_max + + ( + (menucmd[pid].dpad_lr > 0) + ? 1 + : -1 + ); + + statisticsmenu.page %= statisticspage_max; + + M_StatisticsPageInit(); + + S_StartSound(NULL, sfx_s3k5b); + M_SetMenuDelay(pid); + + return true; + } + + if (statisticsmenu.page != statisticspage_maps) + return true; // temporary + if (M_MenuExtraPressed(pid)) { if (statisticsmenu.location > 0) From 49e3e6b500084867cc80e835bd09fa4a33e816d8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Aug 2023 23:23:59 +0100 Subject: [PATCH 06/24] Instead of calculating relevant medals for every frame, calculate once and store the result --- src/k_menu.h | 2 ++ src/k_menudraw.c | 2 +- src/menus/extras-statistics.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 1505c8e96..32a48bb08 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1270,6 +1270,8 @@ extern struct statisticsmenu_s { statisticspage_t page; INT32 location; INT32 nummaps; + INT32 gotmedals; + INT32 nummedals; INT32 numextramedals; INT32 maxscroll; UINT16 *maplist; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 67e703dc9..7bffe0715 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6038,7 +6038,7 @@ static void M_DrawStatsMaps(void) else V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, 0, "(complete)"); - V_DrawThinString(32, 70, 0, va("x %d/%d", M_CountMedals(false, false), M_CountMedals(true, false))); + V_DrawThinString(30, 70, 0, va("x %d/%d", statisticsmenu.gotmedals, statisticsmenu.nummedals)); V_DrawSmallMappedPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GOLD, GTC_MENUCACHE)); diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index 787a633db..90f1859c6 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -75,7 +75,7 @@ static void M_StatisticsMaps(void) M_StatisticsAddMap(i, NULL, &headerexists); } - if ((i = statisticsmenu.numextramedals = M_CountMedals(true, true)) != 0) + if ((i = statisticsmenu.numextramedals) != 0) i += 2; statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID; From 52b4104f86cedb3892c1454469ba42db403e8649 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Aug 2023 23:25:32 +0100 Subject: [PATCH 07/24] Fix inconsistencies with some maps-related statistics --- src/k_menudraw.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 7bffe0715..015d741f9 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6016,9 +6016,14 @@ static void M_DrawStatsMaps(void) for (i = 0; i < nummapheaders; i++) { + // Check for no visibility if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))) continue; + // No TEST RUN, as that's another exception to Time Attack too + if (!mapheaderinfo[i]->typeoflevel) + continue; + if (mapheaderinfo[i]->records.time <= 0) { mapsunfinished++; @@ -6171,7 +6176,7 @@ static void M_DrawStatsMaps(void) } bottomarrow: if (dobottomarrow) - V_DrawCharacter(10, y-STATSSTEP + (skullAnimCounter/5), + V_DrawCharacter(10, y-10 + (skullAnimCounter/5), '\x1B' | highlightflags, false); // down arrow } From 9ed1471c9527ddadee35cf8bd56a817cd50adcc4 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 00:16:08 +0100 Subject: [PATCH 08/24] Add "Characters & Emgine Classes" page to statistics - Shows wins for every character - Shows heatmap of which stats are your favourite (of the loaded skins) - Adds a header to the top of all statistics pages showing you can scroll left and right - General spacing is adjusted to accomodate --- src/k_menu.h | 2 + src/k_menudraw.c | 179 ++++++++++++++++++++++++++++++---- src/menus/extras-statistics.c | 124 ++++++++++++++++++++--- 3 files changed, 270 insertions(+), 35 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 32a48bb08..d15011665 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1263,6 +1263,7 @@ typedef enum { statisticspage_basic = 0, statisticspage_maps, + statisticspage_chars, statisticspage_max } statisticspage_t; @@ -1273,6 +1274,7 @@ extern struct statisticsmenu_s { INT32 gotmedals; INT32 nummedals; INT32 numextramedals; + UINT32 statgridplayed[9][9]; INT32 maxscroll; UINT16 *maplist; } statisticsmenu; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 015d741f9..250c17b3d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6180,6 +6180,120 @@ bottomarrow: '\x1B' | highlightflags, false); // down arrow } +#undef STATSSTEP +#define STATSSTEP 18 + +static void M_DrawStatsChars(void) +{ + INT32 y = 80, i, j; + INT16 skin; + boolean dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); + INT32 location = statisticsmenu.location; + + if (!statisticsmenu.maplist) + { + V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No chars!?"); + return; + } + + if (location) + V_DrawCharacter(10, y-(skullAnimCounter/5), + '\x1A' | highlightflags, false); // up arrow + + i = -1; + + V_DrawThinString(20, y - 10, highlightflags, "CHARACTER"); + V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 34, y - 10, highlightflags, "WINS"); + + while ((skin = statisticsmenu.maplist[++i]) != NEXTMAP_INVALID) + { + if (location) + { + --location; + continue; + } + + { + UINT8 *colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); + + V_DrawFixedPatch(24*FRACUNIT, y*FRACUNIT, + FRACUNIT, + 0, faceprefix[skin][FACE_RANK], + colormap); + + V_DrawFadeFill(24+16, y, 16, 16, 0, 31, 8); // challengetransparentstrength + + V_DrawFill(24+16+5, y+1, 1, 14, 0); + V_DrawFill(24+16+5+5, y+1, 1, 14, 0); + V_DrawFill(24+16+1, y+5, 14, 1, 0); + V_DrawFill(24+16+1, y+5+5, 14, 1, 0); + + // The following is a partial duplication of R_GetEngineClass + { + INT32 s = (skins[skin].kartspeed - 1)/3; + INT32 w = (skins[skin].kartweight - 1)/3; + + #define LOCKSTAT(stat) \ + if (stat < 0) { stat = 0; } \ + if (stat > 2) { stat = 2; } + LOCKSTAT(s); + LOCKSTAT(w); + #undef LOCKSTAT + + V_DrawFill(24+16 + (s*5), y + (w*5), 6, 6, 0); + } + } + + V_DrawThinString(24+32+2, y+3, 0, skins[skin].realname); + + V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 30, y+3, 0, va("%d", skins[skin].records.wins)); + + y += STATSSTEP; + + if (y >= BASEVIDHEIGHT-STATSSTEP) + goto bottomarrow; + } + +bottomarrow: + if (dobottomarrow) + V_DrawCharacter(10, y-10 + (skullAnimCounter/5), + '\x1B' | highlightflags, false); // down arrow + + UINT32 x = BASEVIDWIDTH - 20 - 90; + y = 88; + + V_DrawCenteredThinString(x + 45, y - 10, highlightflags, "HEATMAP"); + + V_DrawFadeFill(x, y, 91, 91, 0, 31, 8); // challengetransparentstrength + + V_DrawFill(x+30, y+1, 1, 89, 0); + V_DrawFill(x+60, y+1, 1, 89, 0); + V_DrawFill(x+1, y+30, 89, 1, 0); + V_DrawFill(x+1, y+60, 89, 1, 0); + + x++; + y++; + + for (i = 0; i < 9; i++) + { + for (j = 0; j < 9; j++) + { + if (statisticsmenu.statgridplayed[i][j] == 0) + continue; + + V_DrawFill( + x + (i * 10), + y + (j * 10), + 9, + 9, + 31 - ((statisticsmenu.statgridplayed[i][j] - 1) * 32) / FRACUNIT + ); + } + } +} + +#undef STATSSTEP + void M_DrawStatistics(void) { char beststr[256]; @@ -6190,8 +6304,47 @@ void M_DrawStatistics(void) V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL); } + { + const char *pagename = NULL; + INT32 pagenamewidth = 0; + + V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL); + + switch (statisticsmenu.page) + { + case statisticspage_maps: + { + pagename = "LEVELS & MEDALS"; + M_DrawStatsMaps(); + break; + } + + case statisticspage_chars: + { + pagename = "CHARACTERS & ENGINE CLASSES"; + M_DrawStatsChars(); + break; + } + + default: + break; + } + + if (pagename) + { + pagenamewidth = V_ThinStringWidth(pagename, 0); + V_DrawThinString((BASEVIDWIDTH - pagenamewidth)/2, 12, 0, pagename); + } + + V_DrawCharacter((BASEVIDWIDTH - pagenamewidth)/2 - 10 - (skullAnimCounter/5), 12, + '\x1C', false); // left arrow + + V_DrawCharacter((BASEVIDWIDTH + pagenamewidth)/2 + 2 + (skullAnimCounter/5), 12, + '\x1D', false); // right arrow + } + beststr[0] = 0; - V_DrawThinString(20, 22, highlightflags, "Total Play Time:"); + V_DrawThinString(20, 30, highlightflags, "Total Play Time:"); besttime = G_TicsToHours(gamedata->totalplaytime); if (besttime) { @@ -6210,10 +6363,10 @@ void M_DrawStatistics(void) } besttime = G_TicsToSeconds(gamedata->totalplaytime); strcat(beststr, va("%i second%s", besttime, (besttime == 1 ? "" : "s"))); - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 22, 0, beststr); + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 30, 0, beststr); beststr[0] = 0; - V_DrawThinString(20, 32, highlightflags, "Total Rings:"); + V_DrawThinString(20, 40, highlightflags, "Total Rings:"); if (gamedata->totalrings > GDMAX_RINGS) { sprintf(beststr, "%c999,999,999+", '\x82'); @@ -6230,10 +6383,10 @@ void M_DrawStatistics(void) { sprintf(beststr, "%u", gamedata->totalrings); } - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 32, 0, va("%s collected", beststr)); + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 40, 0, va("%s collected", beststr)); beststr[0] = 0; - V_DrawThinString(20, 42, highlightflags, "Total Rounds:"); + V_DrawThinString(20, 50, highlightflags, "Total Rounds:"); strcat(beststr, va("%u Race", gamedata->roundsplayed[GDGT_RACE])); @@ -6254,23 +6407,9 @@ void M_DrawStatistics(void) strcat(beststr, va(", %u Custom", gamedata->roundsplayed[GDGT_CUSTOM])); } - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42, 0, beststr); - - switch (statisticsmenu.page) - { - case statisticspage_maps: - { - M_DrawStatsMaps(); - break; - } - - default: - break; - } + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 50, 0, beststr); } -#undef STATSSTEP - static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime) { if (wrongwarp.ticker < falltime) diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index 90f1859c6..74a93e6b2 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -5,6 +5,7 @@ #include "../z_zone.h" #include "../m_cond.h" // Condition Sets #include "../s_sound.h" +#include "../r_skins.h" struct statisticsmenu_s statisticsmenu; @@ -88,6 +89,97 @@ static void M_StatisticsMaps(void) } } +static void M_StatisticsChars(void) +{ + UINT16 i; + + statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numskins), PU_STATIC, NULL); + statisticsmenu.nummaps = 0; + + UINT32 beststat = 0; + + for (i = 0; i < numskins; i++) + { + if (!R_SkinUsable(-1, i, false)) + continue; + + statisticsmenu.maplist[statisticsmenu.nummaps++] = i; + + if (skins[i].records.wins == 0) + continue; + + // The following is a partial duplication of R_GetEngineClass + { + if (skins[i].flags & SF_IRONMAN) + continue; // does not add to any engine class + + INT32 s = (skins[i].kartspeed - 1); + INT32 w = (skins[i].kartweight - 1); + + #define LOCKSTAT(stat) \ + if (stat < 0) { continue; } \ + if (stat > 8) { continue; } + LOCKSTAT(s); + LOCKSTAT(w); + #undef LOCKSTAT + + if ( + statisticsmenu.statgridplayed[s][w] > skins[i].records.wins + && (UINT32_MAX - statisticsmenu.statgridplayed[s][w]) < skins[i].records.wins + ) + continue; // overflow protection + + statisticsmenu.statgridplayed[s][w] += skins[i].records.wins; + + if (beststat >= statisticsmenu.statgridplayed[s][w]) + continue; + + beststat = statisticsmenu.statgridplayed[s][w]; + } + } + + statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID; + + statisticsmenu.location = 0; + statisticsmenu.maxscroll = statisticsmenu.nummaps - 6; + + if (statisticsmenu.maxscroll < 0) + { + statisticsmenu.maxscroll = 0; + } + + if (beststat != 0) + { + UINT16 j; + UINT8 shif = 0; + + // Done this way to ensure ample precision but also prevent overflow + while (beststat < FRACUNIT) + { + beststat <<= 1; + shif++; + } + + for (i = 0; i < 9; i++) + { + for (j = 0; j < 9; j++) + { + if (statisticsmenu.statgridplayed[i][j] == 0) + continue; + + statisticsmenu.statgridplayed[i][j] = + FixedDiv( + statisticsmenu.statgridplayed[i][j] << shif, + beststat + ); + + if (statisticsmenu.statgridplayed[i][j] == 0) + statisticsmenu.statgridplayed[i][j] = 1; + } + } + } +} + static void M_StatisticsPageInit(void) { switch (statisticsmenu.page) @@ -98,20 +190,9 @@ static void M_StatisticsPageInit(void) break; } - default: - break; - } -} - -static void M_StatisticsPageClear(void) -{ - switch (statisticsmenu.page) - { - case statisticspage_maps: + case statisticspage_chars: { - Z_Free(statisticsmenu.maplist); - statisticsmenu.maplist = NULL; - + M_StatisticsChars(); break; } @@ -120,10 +201,23 @@ static void M_StatisticsPageClear(void) } } +static void M_StatisticsPageClear(void) +{ + if (statisticsmenu.maplist != NULL) + { + Z_Free(statisticsmenu.maplist); + statisticsmenu.maplist = NULL; + } +} + void M_Statistics(INT32 choice) { (void)choice; + statisticsmenu.gotmedals = M_CountMedals(false, false); + statisticsmenu.nummedals = M_CountMedals(true, false); + statisticsmenu.numextramedals = M_CountMedals(true, true); + statisticsmenu.page = statisticspage_basic; M_StatisticsPageInit(); @@ -169,8 +263,8 @@ boolean M_StatisticsInputs(INT32 ch) return true; } - if (statisticsmenu.page != statisticspage_maps) - return true; // temporary + if (statisticsmenu.maplist == NULL) + return true; if (M_MenuExtraPressed(pid)) { From 97889f9ef25cfa2f528110b958ca07aa7e1571c7 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 13:46:36 +0100 Subject: [PATCH 09/24] M_DrawCharacterIconAndEngine Abstracts previously duplicated code between Challenges and Statistics --- src/k_menu.h | 2 ++ src/k_menudraw.c | 94 +++++++++++++++++++----------------------------- 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index d15011665..cc537712a 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1283,6 +1283,8 @@ void M_Statistics(INT32 choice); void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); +void M_DrawCharacterIconAndEngine(INT32 x, INT32 y, UINT8 skin, UINT8 *colormap, boolean dot); + #define MAXWRONGPLAYER MAXSPLITSCREENPLAYERS #define WRONGPLAYEROFFSCREEN 48 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 250c17b3d..fbd2809d5 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5283,6 +5283,41 @@ drawborder: #define challengetransparentstrength 8 +void M_DrawCharacterIconAndEngine(INT32 x, INT32 y, UINT8 skin, UINT8 *colormap, boolean dot) +{ + V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, + FRACUNIT, + 0, faceprefix[skin][FACE_RANK], + colormap); + + if (dot) + { + V_DrawScaledPatch(x, y + 11, 0, W_CachePatchName("ALTSDOT", PU_CACHE)); + } + + V_DrawFadeFill(x+16, y, 16, 16, 0, 31, challengetransparentstrength); + + V_DrawFill(x+16+5, y+1, 1, 14, 0); + V_DrawFill(x+16+5+5, y+1, 1, 14, 0); + V_DrawFill(x+16+1, y+5, 14, 1, 0); + V_DrawFill(x+16+1, y+5+5, 14, 1, 0); + + // The following is a partial duplication of R_GetEngineClass + { + INT32 s = (skins[skin].kartspeed - 1)/3; + INT32 w = (skins[skin].kartweight - 1)/3; + + #define LOCKSTAT(stat) \ + if (stat < 0) { stat = 0; } \ + if (stat > 2) { stat = 2; } + LOCKSTAT(s); + LOCKSTAT(w); + #undef LOCKSTAT + + V_DrawFill(x+16 + (s*5), y + (w*5), 6, 6, 0); + } +} + static void M_DrawChallengePreview(INT32 x, INT32 y) { unlockable_t *ref = NULL; @@ -5349,37 +5384,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y) break; } - V_DrawFixedPatch(4*FRACUNIT, (BASEVIDHEIGHT-(4+16))*FRACUNIT, - FRACUNIT, - 0, faceprefix[i][FACE_RANK], - colormap); - - if (i != skin) - { - V_DrawScaledPatch(4, (11 + BASEVIDHEIGHT-(4+16)), 0, W_CachePatchName("ALTSDOT", PU_CACHE)); - } - - V_DrawFadeFill(4+16, (BASEVIDHEIGHT-(4+16)), 16, 16, 0, 31, challengetransparentstrength); - - V_DrawFill(4+16+5, (BASEVIDHEIGHT-(4+16))+1, 1, 14, 0); - V_DrawFill(4+16+5+5, (BASEVIDHEIGHT-(4+16))+1, 1, 14, 0); - V_DrawFill(4+16+1, (BASEVIDHEIGHT-(4+16))+5, 14, 1, 0); - V_DrawFill(4+16+1, (BASEVIDHEIGHT-(4+16))+5+5, 14, 1, 0); - - // The following is a partial duplication of R_GetEngineClass - { - INT32 s = (skins[skin].kartspeed - 1)/3; - INT32 w = (skins[skin].kartweight - 1)/3; - - #define LOCKSTAT(stat) \ - if (stat < 0) { stat = 0; } \ - if (stat > 2) { stat = 2; } - LOCKSTAT(s); - LOCKSTAT(w); - #undef LOCKSTAT - - V_DrawFill(4+16 + (s*5), (BASEVIDHEIGHT-(4+16)) + (w*5), 6, 6, 0); - } + M_DrawCharacterIconAndEngine(4, BASEVIDHEIGHT-(4+16), i, colormap, (i == skin)); } break; } @@ -6216,32 +6221,7 @@ static void M_DrawStatsChars(void) { UINT8 *colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); - V_DrawFixedPatch(24*FRACUNIT, y*FRACUNIT, - FRACUNIT, - 0, faceprefix[skin][FACE_RANK], - colormap); - - V_DrawFadeFill(24+16, y, 16, 16, 0, 31, 8); // challengetransparentstrength - - V_DrawFill(24+16+5, y+1, 1, 14, 0); - V_DrawFill(24+16+5+5, y+1, 1, 14, 0); - V_DrawFill(24+16+1, y+5, 14, 1, 0); - V_DrawFill(24+16+1, y+5+5, 14, 1, 0); - - // The following is a partial duplication of R_GetEngineClass - { - INT32 s = (skins[skin].kartspeed - 1)/3; - INT32 w = (skins[skin].kartweight - 1)/3; - - #define LOCKSTAT(stat) \ - if (stat < 0) { stat = 0; } \ - if (stat > 2) { stat = 2; } - LOCKSTAT(s); - LOCKSTAT(w); - #undef LOCKSTAT - - V_DrawFill(24+16 + (s*5), y + (w*5), 6, 6, 0); - } + M_DrawCharacterIconAndEngine(24, y, skin, colormap, false); } V_DrawThinString(24+32+2, y+3, 0, skins[skin].realname); From 6bf2159ad2e94d058da3d7f097b53c0b5087d483 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 13:47:48 +0100 Subject: [PATCH 10/24] Now that it's exposed via Statistics, remove temporary CONS_Printf display of skin wins from gamedata load function --- src/g_game.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d4b916f4a..16f0935f8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -5024,8 +5024,6 @@ void G_LoadGameData(void) dummyrecord.wins = READUINT32(save.p); dummyrecord._saveid = i; - CONS_Printf(" (TEMPORARY DISPLAY) skinname is \"%s\", has %u wins\n", skinname, dummyrecord.wins); - tempskinreferences[i].id = MAXSKINS; if (skin != -1) From f02711e2977680a19b9bd43bbe4351b1223f538c Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 14:38:44 +0100 Subject: [PATCH 11/24] M_DrawCupWinData Extract a portion of M_DrawCupSelect for future Statistics usage. --- src/k_menu.h | 1 + src/k_menudraw.c | 200 +++++++++++++++++++++++++---------------------- 2 files changed, 108 insertions(+), 93 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index cc537712a..a6831dad1 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1284,6 +1284,7 @@ void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); void M_DrawCharacterIconAndEngine(INT32 x, INT32 y, UINT8 skin, UINT8 *colormap, boolean dot); +void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean shift); #define MAXWRONGPLAYER MAXSPLITSCREENPLAYERS #define WRONGPLAYEROFFSCREEN 48 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index fbd2809d5..9453e128e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2418,6 +2418,104 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch) } } +void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean shift) +{ + INT32 rankw = 14 + 1 + 12; + if (!shift || (difficulty != KARTSPEED_EASY && gamedata->everseenspecial)) + rankw += 1 + 12; + + rankx += 19 - (rankw / 2); + + patch_t *gradePat = NULL; + UINT8 *colormap = NULL; + + cupwindata_t *windata = &(cup->windata[difficulty]); + + const gp_rank_e grade = windata->best_grade; // (cupgrid.previewanim/TICRATE) % (GRADE_S + 1); -- testing + UINT16 gradecolor = K_GetGradeColor(grade); + + if (gradecolor != SKINCOLOR_NONE) + colormap = R_GetTranslationColormap(TC_DEFAULT, gradecolor, GTC_MENUCACHE); + + switch (grade) + { + case GRADE_E: + gradePat = W_CachePatchName("R_CUPRNE", PU_CACHE); + break; + case GRADE_D: + gradePat = W_CachePatchName("R_CUPRND", PU_CACHE); + break; + case GRADE_C: + gradePat = W_CachePatchName("R_CUPRNC", PU_CACHE); + break; + case GRADE_B: + gradePat = W_CachePatchName("R_CUPRNB", PU_CACHE); + break; + case GRADE_A: + gradePat = W_CachePatchName("R_CUPRNA", PU_CACHE); + break; + case GRADE_S: + gradePat = W_CachePatchName("R_CUPRNS", PU_CACHE); + break; + default: + break; + } + + if (gradePat) + V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, gradePat, colormap); + + rankx += 14 + 1; + + patch_t *charPat = NULL; + + if ((windata->best_skin.unloaded != NULL) + || (windata->best_skin.id > numskins)) + { + colormap = NULL; + + charPat = W_CachePatchName("HUHMAP", PU_CACHE); + } + else + { + UINT8 skin = windata->best_skin.id; + + colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); + + charPat = faceprefix[skin][FACE_MINIMAP]; + } + + if (charPat) + V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap); + + if (difficulty > 0 + && windata->got_emerald == true) + { + rankx += 12 + 1; + + if (cup->emeraldnum == 0) + V_DrawCharacter(rankx+2, ranky+2, '+', false); + else + { + colormap = NULL; + + if (!flash) + { + UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (cup->emeraldnum-1) % 7; + + colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); + } + + const char *emname = va( + "%sMAP%c", + (cup->emeraldnum > 7) ? "SUP" : "EME", + colormap ? '\0' : 'B' + ); + + V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, W_CachePatchName(emname, PU_CACHE), colormap); + } + } +} + void M_DrawCupSelect(void) { UINT8 i, j, temp = 0; @@ -2523,100 +2621,16 @@ void M_DrawCupSelect(void) V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE)); } - if (!windata) - ; - else if (windata->best_placement != 0) + if (windata && windata->best_placement != 0) { - const INT32 rankw = 14 + 12 + 12 + 2; - INT32 rankx = (x + 19) - (rankw / 2); - const INT32 ranky = 8 + (j*100) - (30*menutransition.tics); - - patch_t *gradePat = NULL; - colormap = NULL; - - const gp_rank_e grade = windata->best_grade; // (cupgrid.previewanim/TICRATE) % (GRADE_S + 1); -- testing - UINT16 gradecolor = K_GetGradeColor(grade); - - if (gradecolor != SKINCOLOR_NONE) - colormap = R_GetTranslationColormap(TC_DEFAULT, gradecolor, GTC_MENUCACHE); - - switch (grade) - { - case GRADE_E: - gradePat = W_CachePatchName("R_CUPRNE", PU_CACHE); - break; - case GRADE_D: - gradePat = W_CachePatchName("R_CUPRND", PU_CACHE); - break; - case GRADE_C: - gradePat = W_CachePatchName("R_CUPRNC", PU_CACHE); - break; - case GRADE_B: - gradePat = W_CachePatchName("R_CUPRNB", PU_CACHE); - break; - case GRADE_A: - gradePat = W_CachePatchName("R_CUPRNA", PU_CACHE); - break; - case GRADE_S: - gradePat = W_CachePatchName("R_CUPRNS", PU_CACHE); - break; - default: - break; - } - - if (gradePat) - V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, gradePat, colormap); - - rankx += 14 + 1; - - patch_t *charPat = NULL; - - if ((windata->best_skin.unloaded != NULL) - || (windata->best_skin.id > numskins)) - { - colormap = NULL; - - charPat = W_CachePatchName("HUHMAP", PU_CACHE); - } - else - { - UINT8 skin = windata->best_skin.id; - - colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); - - charPat = faceprefix[skin][FACE_MINIMAP]; - } - - if (charPat) - V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap); - - if (cv_dummygpdifficulty.value > 0 - && windata->got_emerald == true) - { - rankx += 12 + 1; - - if (templevelsearch.cup->emeraldnum == 0) - V_DrawCharacter(rankx+2, ranky+2, '+', false); - else - { - colormap = NULL; - - if (!(cupgrid.previewanim & 1)) - { - UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (templevelsearch.cup->emeraldnum-1) % 7; - - colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); - } - - const char *emname = va( - "%sMAP%c", - (templevelsearch.cup->emeraldnum > 7) ? "SUP" : "EME", - colormap ? '\0' : 'B' - ); - - V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, W_CachePatchName(emname, PU_CACHE), colormap); - } - } + M_DrawCupWinData( + x, + 8 + (j*100) - (30*menutransition.tics), + templevelsearch.cup, + cv_dummygpdifficulty.value, + (cupgrid.previewanim & 1), + false + ); } } } From d4049bb9a0169f6a40e7ec3485245c08f298342a Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 16:16:12 +0100 Subject: [PATCH 12/24] Saner list end handling for M_DrawStatsChars --- src/k_menudraw.c | 2 +- src/menus/extras-statistics.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 9453e128e..d5e336709 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6224,7 +6224,7 @@ static void M_DrawStatsChars(void) V_DrawThinString(20, y - 10, highlightflags, "CHARACTER"); V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 34, y - 10, highlightflags, "WINS"); - while ((skin = statisticsmenu.maplist[++i]) != NEXTMAP_INVALID) + while ((skin = statisticsmenu.maplist[++i]) < numskins) { if (location) { diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index 74a93e6b2..bc2cbd5b8 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -138,7 +138,7 @@ static void M_StatisticsChars(void) } } - statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID; + statisticsmenu.maplist[statisticsmenu.nummaps] = MAXSKINS; statisticsmenu.location = 0; statisticsmenu.maxscroll = statisticsmenu.nummaps - 6; From 648a97aaf3833c92b2853e0b6a17096593055eed Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 16:17:05 +0100 Subject: [PATCH 13/24] Grand Prix page for statistics screen Shows windata for all unlocked difficulties, or dotted dash lines if no windata is available --- src/k_menu.h | 1 + src/k_menudraw.c | 108 ++++++++++++++++++++++++++++++++++ src/menus/extras-statistics.c | 32 ++++++++++ 3 files changed, 141 insertions(+) diff --git a/src/k_menu.h b/src/k_menu.h index a6831dad1..379e0e6a4 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1262,6 +1262,7 @@ boolean M_ChallengesInputs(INT32 ch); typedef enum { statisticspage_basic = 0, + statisticspage_gp, statisticspage_maps, statisticspage_chars, statisticspage_max diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d5e336709..e408fe60e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6286,6 +6286,104 @@ bottomarrow: } } +#undef STATSSTEP +#define STATSSTEP 21 + +static void M_DrawStatsGP(void) +{ + INT32 y = 80, i, x, j, endj; + INT16 id; + boolean dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); + INT32 location = statisticsmenu.location; + + if (!statisticsmenu.maplist) + { + V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No cups!?"); + return; + } + + if (location) + V_DrawCharacter(10, y-(skullAnimCounter/5), + '\x1A' | highlightflags, false); // up arrow + + const INT32 width = 44; + + endj = KARTSPEED_NORMAL; + if (M_SecretUnlocked(SECRET_HARDSPEED, true)) + { + endj = M_SecretUnlocked(SECRET_MASTERMODE, true) + ? KARTGP_MASTER + : KARTSPEED_HARD; + } + + x = BASEVIDWIDTH - 20 - width; + for (j = endj; j >= KARTSPEED_EASY; j--, x -= width) + { + V_DrawCenteredThinString(x + 19, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); + } + + i = -1; + + V_DrawThinString(20, y - 10, highlightflags, "CUP"); + + cupheader_t *cup = kartcupheaders; + + while ((id = statisticsmenu.maplist[++i]) < numkartcupheaders) + { + if (location) + { + --location; + continue; + } + + // If we have ANY sort of sorting other than instantiation, this won't work + while (cup && cup->id != id) + { + cup = cup->next; + } + + if (!cup) + { + goto bottomarrow; + } + + V_DrawFill(24, y, 21, 20, 31); + + V_DrawScaledPatch(24-1, y-1, 0, W_CachePatchName(cup->icon, PU_CACHE)); + V_DrawScaledPatch(24-1, y-1, 0, W_CachePatchName("CUPBOX", PU_CACHE)); + + V_DrawThinString(24+23+2, y + 6, 0, cup->name); + + x = BASEVIDWIDTH - 20 - width; + for (j = endj; j >= KARTSPEED_EASY; j--, x -= width) + { + if (cup->windata[j].best_placement == 0) + { + V_DrawCenteredThinString( + x + 19, y + 7, + V_GRAYMAP, + j == KARTSPEED_EASY + ? "- - - -" + : "- - - - - -" + ); + continue; + } + + M_DrawCupWinData(x, y + 6, cup, j, false, true); + } + + y += STATSSTEP; + + if (y >= BASEVIDHEIGHT-STATSSTEP) + goto bottomarrow; + } + +bottomarrow: + if (dobottomarrow) + V_DrawCharacter(10, y-10 + (skullAnimCounter/5), + '\x1B' | highlightflags, false); // down arrow +} + #undef STATSSTEP void M_DrawStatistics(void) @@ -6306,6 +6404,16 @@ void M_DrawStatistics(void) switch (statisticsmenu.page) { + + case statisticspage_gp: + { + pagename = gamedata->everseenspecial + ? "GRAND PRIX & EMERALDS" + : "GRAND PRIX"; + M_DrawStatsGP(); + break; + } + case statisticspage_maps: { pagename = "LEVELS & MEDALS"; diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index bc2cbd5b8..0e16fcad3 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -180,6 +180,32 @@ static void M_StatisticsChars(void) } } +static void M_StatisticsGP(void) +{ + statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numkartcupheaders), PU_STATIC, NULL); + statisticsmenu.nummaps = 0; + + cupheader_t *cup; + + for (cup = kartcupheaders; cup; cup = cup->next) + { + if (M_CupLocked(cup)) + continue; + + statisticsmenu.maplist[statisticsmenu.nummaps++] = cup->id; + } + + statisticsmenu.maplist[statisticsmenu.nummaps] = UINT16_MAX; + + statisticsmenu.location = 0; + statisticsmenu.maxscroll = statisticsmenu.nummaps - 5; + + if (statisticsmenu.maxscroll < 0) + { + statisticsmenu.maxscroll = 0; + } +} + static void M_StatisticsPageInit(void) { switch (statisticsmenu.page) @@ -195,6 +221,12 @@ static void M_StatisticsPageInit(void) M_StatisticsChars(); break; } + + case statisticspage_gp: + { + M_StatisticsGP(); + break; + } default: break; From 71bbe3f28a427c03880cc15bf3e27b1e872d800c Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 7 Aug 2023 18:22:07 +0100 Subject: [PATCH 14/24] Minor aesthetic/alignment tweaks to all three implemented statistics pages while waiting for chicken to defrost --- src/k_menudraw.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index e408fe60e..447c5988a 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6195,7 +6195,7 @@ static void M_DrawStatsMaps(void) } bottomarrow: if (dobottomarrow) - V_DrawCharacter(10, y-10 + (skullAnimCounter/5), + V_DrawCharacter(10, BASEVIDHEIGHT-20 + (skullAnimCounter/5), '\x1B' | highlightflags, false); // down arrow } @@ -6250,7 +6250,7 @@ static void M_DrawStatsChars(void) bottomarrow: if (dobottomarrow) - V_DrawCharacter(10, y-10 + (skullAnimCounter/5), + V_DrawCharacter(10, BASEVIDHEIGHT-20 + (skullAnimCounter/5), '\x1B' | highlightflags, false); // down arrow UINT32 x = BASEVIDWIDTH - 20 - 90; @@ -6347,12 +6347,12 @@ static void M_DrawStatsGP(void) goto bottomarrow; } - V_DrawFill(24, y, 21, 20, 31); + V_DrawFill(24, y+1, 21, 20, 31); - V_DrawScaledPatch(24-1, y-1, 0, W_CachePatchName(cup->icon, PU_CACHE)); - V_DrawScaledPatch(24-1, y-1, 0, W_CachePatchName("CUPBOX", PU_CACHE)); + V_DrawScaledPatch(24-1, y, 0, W_CachePatchName(cup->icon, PU_CACHE)); + V_DrawScaledPatch(24-1, y, 0, W_CachePatchName("CUPBOX", PU_CACHE)); - V_DrawThinString(24+23+2, y + 6, 0, cup->name); + V_DrawThinString(24+23+2, y + 7, 0, cup->name); x = BASEVIDWIDTH - 20 - width; for (j = endj; j >= KARTSPEED_EASY; j--, x -= width) @@ -6360,16 +6360,16 @@ static void M_DrawStatsGP(void) if (cup->windata[j].best_placement == 0) { V_DrawCenteredThinString( - x + 19, y + 7, + x + 19, y + 8, V_GRAYMAP, - j == KARTSPEED_EASY - ? "- - - -" - : "- - - - - -" + (j != KARTSPEED_EASY && gamedata->everseenspecial) + ? "-- -- --" + : "-- --" ); continue; } - M_DrawCupWinData(x, y + 6, cup, j, false, true); + M_DrawCupWinData(x, y + 7, cup, j, false, true); } y += STATSSTEP; @@ -6380,7 +6380,7 @@ static void M_DrawStatsGP(void) bottomarrow: if (dobottomarrow) - V_DrawCharacter(10, y-10 + (skullAnimCounter/5), + V_DrawCharacter(10, BASEVIDHEIGHT-20 + (skullAnimCounter/5), '\x1B' | highlightflags, false); // down arrow } From 8b22e7f691f9cd3f3b6fa9b2915d89e9d9571fcd Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 8 Aug 2023 00:14:55 +0100 Subject: [PATCH 15/24] No entries means no entries --- src/k_menudraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 447c5988a..4e333aee4 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6209,7 +6209,7 @@ static void M_DrawStatsChars(void) boolean dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); INT32 location = statisticsmenu.location; - if (!statisticsmenu.maplist) + if (!statisticsmenu.maplist || !statisticsmenu.nummaps) { V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No chars!?"); return; @@ -6296,7 +6296,7 @@ static void M_DrawStatsGP(void) boolean dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); INT32 location = statisticsmenu.location; - if (!statisticsmenu.maplist) + if (!statisticsmenu.maplist || !statisticsmenu.nummaps) { V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No cups!?"); return; From 92b8ef33f63ff21daa10093ef19228ffca376153 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 8 Aug 2023 00:21:26 +0100 Subject: [PATCH 16/24] Imrpoved Grand Prix Statistics screen - Show placement with position-modified monitor mini-icon - Reworked alignment AGAIN - Dots instead of dashes for empty spots on the GP statistics - Now also applies for a missing emerald/prize - Shaded glass background behind the icons for readability --- src/k_menu.h | 2 +- src/k_menudraw.c | 129 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 379e0e6a4..9dc2bed95 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1285,7 +1285,7 @@ void M_DrawStatistics(void); boolean M_StatisticsInputs(INT32 ch); void M_DrawCharacterIconAndEngine(INT32 x, INT32 y, UINT8 skin, UINT8 *colormap, boolean dot); -void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean shift); +fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean statsmode); #define MAXWRONGPLAYER MAXSPLITSCREENPLAYERS #define WRONGPLAYEROFFSCREEN 48 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 4e333aee4..937588540 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2418,20 +2418,84 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch) } } -void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean shift) +fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficulty, boolean flash, boolean statsmode) { - INT32 rankw = 14 + 1 + 12; - if (!shift || (difficulty != KARTSPEED_EASY && gamedata->everseenspecial)) - rankw += 1 + 12; + INT32 rankw = 14 + 1 + 12 + 1 + 12; + + if (!cup) + return 0; + + boolean noemerald = (!gamedata->everseenspecial || difficulty == KARTSPEED_EASY); + + if (statsmode) + { + rankw += 10 + 1; + + if (noemerald) + { + rankw -= (12 + 1); + rankx += 7; // vibes-based maths, as tyron puts it + } + } rankx += 19 - (rankw / 2); - patch_t *gradePat = NULL; + cupwindata_t *windata = &(cup->windata[difficulty]); + if (windata->best_placement == 0) + { + if (statsmode) + { + V_DrawCharacter((10-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); + rankx += 10 + 1; + V_DrawCharacter((14-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); + rankx += 14 + 1; + V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); + + if (!noemerald) + { + rankx += 12 + 1; + V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); + } + } + return rankw; + } + UINT8 *colormap = NULL; - cupwindata_t *windata = &(cup->windata[difficulty]); + if (statsmode) + { + patch_t *monPat = W_CachePatchName(va("CUPMON%c%c", '0' + cup->monitor, 'C'), PU_CACHE); + UINT16 moncolor = SKINCOLOR_NONE; + + switch (windata->best_placement) + { + case 1: + moncolor = SKINCOLOR_GOLD; + break; + case 2: + moncolor = SKINCOLOR_SILVER; + break; + case 3: + moncolor = SKINCOLOR_BRONZE; + break; + default: + moncolor = SKINCOLOR_BEIGE; + break; + } + + if (moncolor != SKINCOLOR_NONE) + colormap = R_GetTranslationColormap(TC_RAINBOW, moncolor, GTC_MENUCACHE); + + if (monPat) + V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, monPat, colormap); + + rankx += 10 + 1; + + colormap = NULL; + } const gp_rank_e grade = windata->best_grade; // (cupgrid.previewanim/TICRATE) % (GRADE_S + 1); -- testing + patch_t *gradePat = NULL; UINT16 gradecolor = K_GetGradeColor(grade); if (gradecolor != SKINCOLOR_NONE) @@ -2487,11 +2551,12 @@ void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficul if (charPat) V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap); - if (difficulty > 0 - && windata->got_emerald == true) - { - rankx += 12 + 1; + rankx += 12 + 1; + if (noemerald) + ; + else if (windata->got_emerald == true) + { if (cup->emeraldnum == 0) V_DrawCharacter(rankx+2, ranky+2, '+', false); else @@ -2514,6 +2579,12 @@ void M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 difficul V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, W_CachePatchName(emname, PU_CACHE), colormap); } } + else if (statsmode) + { + V_DrawCharacter((12-4)/2 + rankx, ranky, '.' | V_GRAYMAP, false); + } + + return rankw; } void M_DrawCupSelect(void) @@ -6306,7 +6377,7 @@ static void M_DrawStatsGP(void) V_DrawCharacter(10, y-(skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow - const INT32 width = 44; + const INT32 width = 53; endj = KARTSPEED_NORMAL; if (M_SecretUnlocked(SECRET_HARDSPEED, true)) @@ -6316,10 +6387,22 @@ static void M_DrawStatsGP(void) : KARTSPEED_HARD; } - x = BASEVIDWIDTH - 20 - width; + const INT32 h = (21 * min(5, statisticsmenu.nummaps)) - 1; + + x = 7 + BASEVIDWIDTH - 20 - width; for (j = endj; j >= KARTSPEED_EASY; j--, x -= width) { - V_DrawCenteredThinString(x + 19, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); + if (j == KARTSPEED_EASY || !gamedata->everseenspecial) + { + V_DrawFadeFill(x + 6, y + 1, width - (12 + 1), h, 0, 31, 5 + j); + V_DrawCenteredThinString(x + 19 + 7, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); + x += (12 + 1); + } + else + { + V_DrawFadeFill(x - 7, y + 1, width, h, 0, 31, 5 + j); + V_DrawCenteredThinString(x + 19, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); + } } i = -1; @@ -6352,24 +6435,12 @@ static void M_DrawStatsGP(void) V_DrawScaledPatch(24-1, y, 0, W_CachePatchName(cup->icon, PU_CACHE)); V_DrawScaledPatch(24-1, y, 0, W_CachePatchName("CUPBOX", PU_CACHE)); - V_DrawThinString(24+23+2, y + 7, 0, cup->name); + V_DrawThinString(24+21+2, y + 7, 0, cup->name); - x = BASEVIDWIDTH - 20 - width; - for (j = endj; j >= KARTSPEED_EASY; j--, x -= width) + x = 7 + BASEVIDWIDTH - 20 - width; + for (j = endj; j >= KARTSPEED_EASY; j--) { - if (cup->windata[j].best_placement == 0) - { - V_DrawCenteredThinString( - x + 19, y + 8, - V_GRAYMAP, - (j != KARTSPEED_EASY && gamedata->everseenspecial) - ? "-- -- --" - : "-- --" - ); - continue; - } - - M_DrawCupWinData(x, y + 7, cup, j, false, true); + x -= (M_DrawCupWinData(x, y + 5, cup, j, false, true) + 2); } y += STATSSTEP; From b669f8484f904c177e202ff3534b46715f25bfa3 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 8 Aug 2023 12:01:41 +0100 Subject: [PATCH 17/24] Realname for Cups Permits prefixing them like maps AND giving them spaces instead of underscores, fixing the "RECYCLE_A" issue. --- src/deh_soc.c | 5 +++++ src/dehacked.c | 9 +++++++++ src/doomstat.h | 2 ++ src/g_game.c | 16 ++++++++++++++-- src/k_menudraw.c | 6 +++--- src/m_cond.c | 2 +- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index fed01aa6d..276700a9f 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3496,6 +3496,11 @@ void readcupheader(MYFILE *f, cupheader_t *cup) else cup->monitor = (word2[0] - 'A') + 10; } + else if (fastcmp(word, "REALNAME")) + { + deh_strlcpy(cup->realname, word2, + sizeof(cup->realname), va("%s Cup: realname", cup->name)); + } else if (fastcmp(word, "ICON")) { deh_strlcpy(cup->icon, word2, diff --git a/src/dehacked.c b/src/dehacked.c index f6ac70fe1..c63ab376b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -495,6 +495,15 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) sizeof(cup->name), va("Cup header %s: name", word2)); cup->namehash = hash; + char *start = strchr(word2, '_'); + if (start) + start++; + else + start = word2; + + deh_strlcpy(cup->realname, start, + sizeof(cup->realname), va("%s Cup: realname (default)", cup->name)); + // Check to see if we have any custom cup record data that we could substitute in. unloaded_cupheader_t *unloadedcup, *unloadedprev = NULL; for (unloadedcup = unloadedcupheaders; unloadedcup; unloadedprev = unloadedcup, unloadedcup = unloadedcup->next) diff --git a/src/doomstat.h b/src/doomstat.h index e6e1bc190..f962aa8af 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -396,6 +396,8 @@ struct cupheader_t char name[MAXCUPNAME]; ///< Cup title UINT32 namehash; ///< Cup title hash + char realname[MAXCUPNAME]; ///< Cup nomme de gurre + char icon[9]; ///< Name of the icon patch char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage diff --git a/src/g_game.c b/src/g_game.c index 16f0935f8..873ac0cf6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4742,7 +4742,7 @@ void G_LoadGameSettings(void) } #define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual -#define GD_VERSIONMINOR 4 // Change every format update +#define GD_VERSIONMINOR 5 // Change every format update typedef enum { @@ -5127,7 +5127,19 @@ void G_LoadGameData(void) cupwindata_t dummywindata[4]; // Find the relevant cup. - READSTRINGL(save.p, cupname, sizeof(cupname)); + if (versionMinor < 5) + { + // Before this version cups were called things like RING. + // Now that example cup would be called RR_RING instead. + cupname[0] = cupname[1] = 'R'; + cupname[2] = '_'; + READSTRINGL(save.p, (cupname + 3), sizeof(cupname) - 3); + } + else + { + READSTRINGL(save.p, cupname, sizeof(cupname)); + } + UINT32 hash = quickncasehash(cupname, MAXCUPNAME); for (cup = kartcupheaders; cup; cup = cup->next) { diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 937588540..268db5e5b 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2397,7 +2397,7 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch) boolean unlocked = (M_GetFirstLevelInList(&temp, levelsearch) != NEXTMAP_INVALID); UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE); patch_t *icon = W_CachePatchName(levelsearch->cup->icon, PU_CACHE); - const char *str = (unlocked ? va("%s Cup", levelsearch->cup->name) : "???"); + const char *str = (unlocked ? va("%s Cup", levelsearch->cup->realname) : "???"); INT16 offset = V_LSTitleLowStringWidth(str, 0) / 2; V_DrawLSTitleLowString(BASEVIDWIDTH/2 - offset, y+6, 0, str); @@ -6165,7 +6165,7 @@ static void M_DrawStatsMaps(void) const char *str; if (mapheaderinfo[mnum]->cup) - str = va("%s CUP", mapheaderinfo[mnum]->cup->name); + str = va("%s CUP", mapheaderinfo[mnum]->cup->realname); else str = "LOST AND FOUND"; @@ -6435,7 +6435,7 @@ static void M_DrawStatsGP(void) V_DrawScaledPatch(24-1, y, 0, W_CachePatchName(cup->icon, PU_CACHE)); V_DrawScaledPatch(24-1, y, 0, W_CachePatchName("CUPBOX", PU_CACHE)); - V_DrawThinString(24+21+2, y + 7, 0, cup->name); + V_DrawThinString(24+21+2, y + 7, 0, cup->realname); x = 7 + BASEVIDWIDTH - 20 - width; for (j = endj; j >= KARTSPEED_EASY; j--) diff --git a/src/m_cond.c b/src/m_cond.c index 828845823..22c9e7db9 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1432,7 +1432,7 @@ static const char *M_GetConditionString(condition_t *cn) continue; return va("%s%s %s CUP", completetype, orbetter, - (M_CupLocked(cup) ? "???" : cup->name) + (M_CupLocked(cup) ? "???" : cup->realname) ); } return va("INVALID CUP CONDITION \"%d:%d\"", cn->type, cn->requirement); From 8d7c9dd6ce986551bd2d59b676e33d4fe6264141 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 8 Aug 2023 12:38:03 +0100 Subject: [PATCH 18/24] Menu titles for level headers For the tutorials. Replaces the no longer visible subtitle, since it's roughly analagous in purpose. --- src/deh_soc.c | 6 +++--- src/doomstat.h | 2 +- src/k_menudraw.c | 32 ++++++++++++++++++++++++-------- src/lua_maplib.c | 4 ++-- src/p_setup.c | 2 +- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 276700a9f..c44b158d0 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1041,10 +1041,10 @@ void readlevelheader(MYFILE *f, char * name) continue; } - if (fastcmp(word, "SUBTITLE")) + if (fastcmp(word, "MENUTITLE")) { - deh_strlcpy(mapheaderinfo[num]->subttl, word2, - sizeof(mapheaderinfo[num]->subttl), va("Level header %d: subtitle", num)); + deh_strlcpy(mapheaderinfo[num]->menuttl, word2, + sizeof(mapheaderinfo[num]->menuttl), va("Level header %d: menutitle", num)); continue; } diff --git a/src/doomstat.h b/src/doomstat.h index f962aa8af..dcb29be47 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -466,7 +466,7 @@ struct mapheader_t // Titlecard information char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) - char subttl[33]; ///< Subtitle for level + char menuttl[22]; ///< Menu title for level char zonttl[22]; ///< "ZONE" replacement name UINT8 actnum; ///< Act number or 0 for none. diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 268db5e5b..0e18dd799 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2744,16 +2744,22 @@ void M_DrawCupSelect(void) static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map) { char word1[22]; - char word2[22]; + char word2[22 + 2]; // actnum UINT8 word1len = 0; UINT8 word2len = 0; INT16 x2 = x; UINT8 i; - if (!mapheaderinfo[map] || !mapheaderinfo[map]->lvlttl[0]) + if (!mapheaderinfo[map] + || ( + !mapheaderinfo[map]->menuttl[0] + && !mapheaderinfo[map]->lvlttl[0] + ) + ) return; - if (mapheaderinfo[map]->zonttl[0]) + if (!mapheaderinfo[map]->menuttl[0] + && mapheaderinfo[map]->zonttl[0]) { boolean one = true; boolean two = true; @@ -2784,12 +2790,17 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map) { boolean donewithone = false; + char *ttlsource = + mapheaderinfo[map]->menuttl[0] + ? mapheaderinfo[map]->menuttl + : mapheaderinfo[map]->lvlttl; + for (i = 0; i < 22; i++) { - if (!mapheaderinfo[map]->lvlttl[i]) + if (!ttlsource[i]) break; - if (mapheaderinfo[map]->lvlttl[i] == ' ') + if (ttlsource[i] == ' ') { if (!donewithone) { @@ -2800,18 +2811,18 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map) if (donewithone) { - word2[word2len] = mapheaderinfo[map]->lvlttl[i]; + word2[word2len] = ttlsource[i]; word2len++; } else { - word1[word1len] = mapheaderinfo[map]->lvlttl[i]; + word1[word1len] = ttlsource[i]; word1len++; } } } - if (mapheaderinfo[map]->actnum) + if (!mapheaderinfo[map]->menuttl[0] && mapheaderinfo[map]->actnum) { word2[word2len] = ' '; word2len++; @@ -6187,6 +6198,11 @@ static void M_DrawStatsMaps(void) M_DrawMapMedals(mnum+1, 291, y); + if (mapheaderinfo[mnum]->menuttl[0]) + { + V_DrawThinString(24, y, V_FORCEUPPERCASE, mapheaderinfo[mnum]->menuttl); + } + else { char *title = G_BuildMapTitle(mnum+1); V_DrawThinString(24, y, V_FORCEUPPERCASE, title); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index c9ae8fca0..b7926fcca 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2487,8 +2487,8 @@ static int mapheaderinfo_get(lua_State *L) const char *field = luaL_checkstring(L, 2); if (fastcmp(field,"lvlttl")) lua_pushstring(L, header->lvlttl); - else if (fastcmp(field,"subttl")) - lua_pushstring(L, header->subttl); + else if (fastcmp(field,"menuttl")) + lua_pushstring(L, header->menuttl); else if (fastcmp(field,"zonttl")) lua_pushstring(L, header->zonttl); else if (fastcmp(field,"actnum")) diff --git a/src/p_setup.c b/src/p_setup.c index a886e1e93..ac1edeca0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -406,7 +406,7 @@ void P_DeleteHeaderFollowers(UINT16 i) static void P_ClearSingleMapHeaderInfo(INT16 num) { mapheaderinfo[num]->lvlttl[0] = '\0'; - mapheaderinfo[num]->subttl[0] = '\0'; + mapheaderinfo[num]->menuttl[0] = '\0'; mapheaderinfo[num]->zonttl[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; From 92ce6734163d3c000bd11fe88c87269101716bca Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 9 Aug 2023 22:42:31 +0100 Subject: [PATCH 19/24] K_drawKartTimestamp: Don't `va()` a constant string --- src/k_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 77ef7ab9b..9e74ce0f8 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1793,7 +1793,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U } if (mode && !drawtime) - V_DrawTimerString(TX, TY+3, splitflags, va("--'--\"--")); + V_DrawTimerString(TX, TY+3, splitflags, "--'--\"--"); else { // minutes time 00 __ __ From bce9a2c1468f18d6a39789ca561d52da65979d3b Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 9 Aug 2023 22:44:56 +0100 Subject: [PATCH 20/24] Change the location of the "No [something!?" message to be where a header usually is --- src/k_menudraw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 0e18dd799..b13027bc8 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6111,7 +6111,7 @@ static void M_DrawStatsMaps(void) if (!statisticsmenu.maplist) { - V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No maps!?"); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 70, 0, "No maps!?"); return; } @@ -6298,7 +6298,7 @@ static void M_DrawStatsChars(void) if (!statisticsmenu.maplist || !statisticsmenu.nummaps) { - V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No chars!?"); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 70, 0, "No chars!?"); return; } @@ -6385,7 +6385,7 @@ static void M_DrawStatsGP(void) if (!statisticsmenu.maplist || !statisticsmenu.nummaps) { - V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No cups!?"); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 70, 0, "No cups!?"); return; } From 567e3863a3a0e6c510c13a02081c7886bbf50249 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 9 Aug 2023 22:45:31 +0100 Subject: [PATCH 21/24] GP stats: Make columns alternate in darkness, rather than gradient --- src/k_menudraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index b13027bc8..93b7473b9 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6410,13 +6410,13 @@ static void M_DrawStatsGP(void) { if (j == KARTSPEED_EASY || !gamedata->everseenspecial) { - V_DrawFadeFill(x + 6, y + 1, width - (12 + 1), h, 0, 31, 5 + j); + V_DrawFadeFill(x + 6, y + 1, width - (12 + 1), h, 0, 31, 6 + (j & 1)*2); V_DrawCenteredThinString(x + 19 + 7, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); x += (12 + 1); } else { - V_DrawFadeFill(x - 7, y + 1, width, h, 0, 31, 5 + j); + V_DrawFadeFill(x - 7, y + 1, width, h, 0, 31, 6 + (j & 1)*2); V_DrawCenteredThinString(x + 19, y - 10, highlightflags|V_FORCEUPPERCASE, gpdifficulty_cons_t[j].strvalue); } } From 6015a96a84983cd863161dc9807b0e9e69d5d55b Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 9 Aug 2023 23:19:46 +0100 Subject: [PATCH 22/24] General cleanup to Map Statistics screen - One extra row, to match the position of the headers on other pages - Add "time" column if Time Attack for relevant gametypes is unlocked - Seperate row header from Lost and Found for tutorial mode maps - Add background lines to each row to increase parsability --- src/k_menudraw.c | 124 +++++++++++++++++++++++----------- src/menus/extras-statistics.c | 25 ++++--- 2 files changed, 101 insertions(+), 48 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 93b7473b9..d18affab1 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -6098,58 +6098,70 @@ static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y) static void M_DrawStatsMaps(void) { - INT32 y = 80, i; + INT32 y = 70, i; INT16 mnum; boolean dotopname = true, dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll); INT32 location = statisticsmenu.location; - char beststr[256]; - tic_t besttime = 0; - INT32 mapsunfinished = 0; - if (!statisticsmenu.maplist) { V_DrawCenteredThinString(BASEVIDWIDTH/2, 70, 0, "No maps!?"); return; } - for (i = 0; i < nummapheaders; i++) - { - // Check for no visibility - if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))) - continue; + INT32 mapsunfinished = 0; - // No TEST RUN, as that's another exception to Time Attack too - if (!mapheaderinfo[i]->typeoflevel) - continue; - - if (mapheaderinfo[i]->records.time <= 0) - { - mapsunfinished++; - continue; - } - - besttime += mapheaderinfo[i]->records.time; - } - - V_DrawThinString(20, 60, 0, "Combined time records:"); - - sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime)); - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, (mapsunfinished ? V_REDMAP : 0), beststr); - - if (mapsunfinished) - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, V_REDMAP, va("(%d unfinished)", mapsunfinished)); - else - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, 0, "(complete)"); - - V_DrawThinString(30, 70, 0, va("x %d/%d", statisticsmenu.gotmedals, statisticsmenu.nummedals)); - V_DrawSmallMappedPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_CACHE), + V_DrawThinString(30, 60, 0, va("x %d/%d", statisticsmenu.gotmedals, statisticsmenu.nummedals)); + V_DrawSmallMappedPatch(20, 60, 0, W_CachePatchName("GOTITA", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GOLD, GTC_MENUCACHE)); + INT32 medalspos = BASEVIDWIDTH - 20; + + boolean timeattack[3]; + timeattack[0] = M_SecretUnlocked(SECRET_TIMEATTACK, true); + timeattack[1] = M_SecretUnlocked(SECRET_PRISONBREAK, true); + timeattack[2] = M_SecretUnlocked(SECRET_SPECIALATTACK, true); + + if (timeattack[0] || timeattack[1] || timeattack[2]) + { + medalspos -= 64; + + for (i = 0; i < nummapheaders; i++) + { + // Check for no visibility + if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))) + continue; + + // Has to be accessible via time attack + if (!(mapheaderinfo[i]->typeoflevel & (TOL_RACE|TOL_BATTLE|TOL_SPECIAL|TOL_VERSUS))) + continue; + + if (mapheaderinfo[i]->records.time <= 0) + { + mapsunfinished++; + continue; + } + + besttime += mapheaderinfo[i]->records.time; + } + + V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, 0, + va( + "Combined time: %c%i:%02i:%02i.%02i (%s)", + (mapsunfinished ? '\x85' : '\x80'), + G_TicsToHours(besttime), + G_TicsToMinutes(besttime, false), + G_TicsToSeconds(besttime), + G_TicsToCentiseconds(besttime), + (mapsunfinished ? "incomplete" : "complete") + ) + ); + } + if (location) - V_DrawCharacter(10, y-(skullAnimCounter/5), + V_DrawCharacter(10, 80-(skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow i = -1; @@ -6175,7 +6187,9 @@ static void M_DrawStatsMaps(void) { const char *str; - if (mapheaderinfo[mnum]->cup) + if (mapheaderinfo[mnum]->typeoflevel & TOL_TUTORIAL) + str = "TUTORIAL MODE"; + else if (mapheaderinfo[mnum]->cup) str = va("%s CUP", mapheaderinfo[mnum]->cup->realname); else str = "LOST AND FOUND"; @@ -6185,7 +6199,11 @@ static void M_DrawStatsMaps(void) if (dotopname) { - V_DrawRightAlignedThinString(BASEVIDWIDTH-20, y, highlightflags, "MEDALS"); + V_DrawRightAlignedThinString(medalspos, y, highlightflags, "MEDALS"); + + if (timeattack[0] || timeattack[1] || timeattack[2]) + V_DrawRightAlignedThinString((BASEVIDWIDTH-20), y, highlightflags, "TIME"); + dotopname = false; } @@ -6196,7 +6214,35 @@ static void M_DrawStatsMaps(void) continue; } - M_DrawMapMedals(mnum+1, 291, y); + V_DrawFadeFill(24, y + 5, (BASEVIDWIDTH - 24) - 24, 3, 0, 31, 8 - (i & 1)*2); + + if (!(mapheaderinfo[mnum]->menuflags & LF2_NOTIMEATTACK) + && ( + (timeattack[0] && (mapheaderinfo[mnum]->typeoflevel & TOL_RACE)) + || (timeattack[1] && (mapheaderinfo[mnum]->typeoflevel & TOL_BATTLE)) + || (timeattack[2] && (mapheaderinfo[mnum]->typeoflevel & (TOL_SPECIAL|TOL_VERSUS))) + ) + ) + { + besttime = mapheaderinfo[mnum]->records.time; + + if (besttime) + { + V_DrawRightAlignedString((BASEVIDWIDTH-24), y+1, 0, + va("%02d'%02d\"%02d", + G_TicsToMinutes(besttime, true), + G_TicsToSeconds(besttime), + G_TicsToCentiseconds(besttime) + ) + ); + } + else + { + V_DrawRightAlignedString((BASEVIDWIDTH-24), y+1, V_GRAYMAP, "--'--\"--"); + } + } + + M_DrawMapMedals(mnum+1, medalspos - 8, y); if (mapheaderinfo[mnum]->menuttl[0]) { diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index 0e16fcad3..a90b97670 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -9,7 +9,7 @@ struct statisticsmenu_s statisticsmenu; -static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headerexists) +static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headerexists, boolean tutorial) { if (!mapheaderinfo[map]) return false; @@ -17,12 +17,11 @@ static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headere if (mapheaderinfo[map]->cup != cup) return false; - // Check for no visibility - if (mapheaderinfo[map]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU)) + if (((mapheaderinfo[map]->typeoflevel & TOL_TUTORIAL) == TOL_TUTORIAL) != tutorial) return false; - // No TEST RUN, as that's another exception to Time Attack too - if (!mapheaderinfo[map]->typeoflevel) + // Check for no visibility + if (mapheaderinfo[map]->menuflags & (LF2_HIDEINSTATS|LF2_HIDEINMENU)) return false; // Check for completion @@ -53,6 +52,7 @@ static void M_StatisticsMaps(void) statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (nummapheaders+1 + numkartcupheaders), PU_STATIC, NULL); statisticsmenu.nummaps = 0; + // Cups for (cup = kartcupheaders; cup; cup = cup->next) { headerexists = false; @@ -65,22 +65,29 @@ static void M_StatisticsMaps(void) if (cup->cachedlevels[i] >= nummapheaders) continue; - M_StatisticsAddMap(cup->cachedlevels[i], cup, &headerexists); + M_StatisticsAddMap(cup->cachedlevels[i], cup, &headerexists, false); } } + // Lost and Found headerexists = false; - for (i = 0; i < nummapheaders; i++) { - M_StatisticsAddMap(i, NULL, &headerexists); + M_StatisticsAddMap(i, NULL, &headerexists, false); + } + + // Tutorial + headerexists = false; + for (i = 0; i < nummapheaders; i++) + { + M_StatisticsAddMap(i, NULL, &headerexists, true); } if ((i = statisticsmenu.numextramedals) != 0) i += 2; statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID; - statisticsmenu.maxscroll = (statisticsmenu.nummaps + i) - 11; + statisticsmenu.maxscroll = (statisticsmenu.nummaps + i) - 12; statisticsmenu.location = 0; if (statisticsmenu.maxscroll < 0) From 19e73f4fe36ac1ea5f0c75ec0548d415ccfeab40 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 9 Aug 2023 23:27:36 +0100 Subject: [PATCH 23/24] Final statistics cleanup - Characters is default page because it's Dr Eggman's game - Keep page when exiting menu and returning - Remove/comment out the overview page, since the overview is currently visible on all pages --- src/k_menu.h | 4 ++-- src/menus/extras-statistics.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 9dc2bed95..70f6b79c3 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1261,10 +1261,10 @@ boolean M_ChallengesInputs(INT32 ch); typedef enum { - statisticspage_basic = 0, + //statisticspage_overview = 0, + statisticspage_chars = 0, statisticspage_gp, statisticspage_maps, - statisticspage_chars, statisticspage_max } statisticspage_t; diff --git a/src/menus/extras-statistics.c b/src/menus/extras-statistics.c index a90b97670..7e774315e 100644 --- a/src/menus/extras-statistics.c +++ b/src/menus/extras-statistics.c @@ -257,7 +257,6 @@ void M_Statistics(INT32 choice) statisticsmenu.nummedals = M_CountMedals(true, false); statisticsmenu.numextramedals = M_CountMedals(true, true); - statisticsmenu.page = statisticspage_basic; M_StatisticsPageInit(); MISC_StatisticsDef.prevMenu = currentMenu; From 9a35a39f5d03f43a66b5823839c54502c735868a Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 10 Aug 2023 00:27:15 +0100 Subject: [PATCH 24/24] Challenges Chao Key usage: Eggman numbers to REALLY drive home that you have to hold the button, and that you can release it early --- src/k_hud.c | 2 +- src/k_hud.h | 2 ++ src/k_menudraw.c | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 9e74ce0f8..20da0419c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -162,7 +162,7 @@ static patch_t *kp_localtag[4][2]; static patch_t *kp_talk; static patch_t *kp_typdot; -static patch_t *kp_eggnum[6]; +patch_t *kp_eggnum[6]; static patch_t *kp_flameshieldmeter[FLAMESHIELD_MAX][2]; static patch_t *kp_flameshieldmeter_bg[FLAMESHIELD_MAX][2]; diff --git a/src/k_hud.h b/src/k_hud.h index 498a6295f..041243d5b 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -75,6 +75,8 @@ extern patch_t *kp_button_down[2]; extern patch_t *kp_button_right[2]; extern patch_t *kp_button_left[2]; +extern patch_t *kp_eggnum[6]; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_menudraw.c b/src/k_menudraw.c index d18affab1..b789a97f4 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -5988,6 +5988,10 @@ challengedesc: keyholdrotation = 360 * ((challengesmenu.chaokeyhold - CHAOHOLD_BEGIN)) * (FRACUNIT/(CHAOHOLD_MAX - (CHAOHOLD_BEGIN + CHAOHOLD_END))); + + INT32 time = 3 - (keyholdrotation - 1) / (90 * FRACUNIT); + if (time <= 5 && time >= 0) + V_DrawScaledPatch(selectx + 2, selecty - 2, 0, kp_eggnum[time]); } else {