From 99bf1c10e84db3527570e0b42b1b517aeedb5d0a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 00:55:34 +0000 Subject: [PATCH 01/37] staffbrief_t - Demos are VERY large and should not be cached for every map in the game all at once. - Instead, store a small amount of data related to staff ghosts for later reference. - best time (for use in Medals) - best lap (maybe use for Medals too) - player name (for use in Time Attack menu) --- src/doomstat.h | 12 ++++++++++++ src/g_demo.c | 28 ++++++++++++++++++---------- src/g_demo.h | 2 +- src/p_setup.c | 42 +++++++++++++++++++++++++++++++++++++----- src/typedef.h | 1 + 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 39b5a73da..fb62266a2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -360,6 +360,14 @@ extern cupheader_t *kartcupheaders; // Start of cup linked list extern UINT16 numkartcupheaders; #define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata +#define MAXSTAFF 3 + +struct staffbrief_t +{ + char name[16]; + INT32 time; + INT32 lap; +}; /** Map header information. */ @@ -374,6 +382,10 @@ struct mapheader_t void *encoreLump; ///< Lump data for the Encore Mode remap. void *tweakLump; ///< Lump data for the palette tweak remap. + // Staff Ghost information + UINT8 ghostCount; ///< Count of valid staff ghosts + staffbrief_t *ghostBrief[MAXSTAFF]; ///< Mallocated array of names for each staff ghost + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. recorddata_t *mainrecord; ///< Stores best time attack data diff --git a/src/g_demo.c b/src/g_demo.c index 286a4e965..17a8e4865 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3711,14 +3711,17 @@ void G_FreeGhosts(void) } // A simplified version of G_AddGhost... -void G_UpdateStaffGhostName(lumpnum_t l) +staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer) { - UINT8 *buffer,*p; + UINT8 *p = buffer; UINT16 ghostversion; UINT8 flags; INT32 i; + staffbrief_t temp; + staffbrief_t *ret = NULL; - buffer = p = W_CacheLumpNum(l, PU_CACHE); + temp.name[0] = '\0'; + temp.time = temp.lap = UINT32_MAX; // read demo header if (memcmp(p, DEMOHEADER, 12)) @@ -3766,9 +3769,9 @@ void G_UpdateStaffGhostName(lumpnum_t l) G_SkipDemoSkins(&p); if (flags & ATTACKING_TIME) - p += 4; + temp.time = READUINT32(p); if (flags & ATTACKING_LAP) - p += 4; + temp.lap = READUINT32(p); for (i = 0; i < PRNUMCLASS; i++) { @@ -3781,7 +3784,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) ghostversion = READUINT16(p); while (ghostversion--) { - p += 2; + SKIPSTRING(p); SKIPSTRING(p); p++; // stealth } @@ -3789,13 +3792,18 @@ void G_UpdateStaffGhostName(lumpnum_t l) // Assert first player is in and then read name if (READUINT8(p) != 0) goto fail; - M_Memcpy(dummystaffname, p,16); - dummystaffname[16] = '\0'; + if (READUINT8(p) & (DEMO_SPECTATOR|DEMO_BOT)) + goto fail; + + M_Memcpy(temp.name, p, 16); + + ret = Z_Malloc(sizeof(staffbrief_t), PU_STATIC, NULL); + if (ret) + M_Memcpy(ret, &temp, sizeof(staffbrief_t)); // Ok, no longer any reason to care, bye fail: - Z_Free(buffer); - return; + return ret; } // diff --git a/src/g_demo.h b/src/g_demo.h index a8c3f573c..d99b7a3ad 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -185,7 +185,7 @@ void G_DeferedPlayDemo(const char *demo); void G_DoPlayDemo(char *defdemoname); void G_TimeDemo(const char *name); void G_AddGhost(char *defdemoname); -void G_UpdateStaffGhostName(lumpnum_t l); +staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer); void G_FreeGhosts(void); void G_DoneLevelLoad(void); diff --git a/src/p_setup.c b/src/p_setup.c index e10f18a29..8381034a2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -471,6 +471,7 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; + mapheaderinfo[i]->ghostCount = 0; mapheaderinfo[i]->cup = NULL; mapheaderinfo[i]->mainrecord = NULL; mapheaderinfo[i]->flickies = NULL; @@ -8018,11 +8019,13 @@ INT16 wadnamemap = 0; // gamemap based UINT8 P_InitMapData(boolean existingmapheaders) { UINT8 ret = 0; - INT32 i; + INT32 i, j; lumpnum_t maplump; virtres_t *virtmap; - virtlump_t *minimap, *thumbnailPic; + virtlump_t *minimap, *thumbnailPic, *ghost; char *name; + char buffer[9]; + sprintf(buffer, "GHOST_x"); for (i = 0; i < nummapheaders; ++i) { @@ -8034,7 +8037,6 @@ UINT8 P_InitMapData(boolean existingmapheaders) if (maplump != LUMPERROR || mapheaderinfo[i]->lumpnum != LUMPERROR) { cupheader_t *cup = kartcupheaders; - INT32 j; while (cup) { @@ -8116,16 +8118,46 @@ UINT8 P_InitMapData(boolean existingmapheaders) } // Now apply the new ones! - if (thumbnailPic) + if (thumbnailPic != NULL) { mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC); } - if (minimap) + if (minimap != NULL) { mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC); } + // Staff ghosts. + // The trouble with staff ghosts is that they're too large to cache. + // So we store extra information about them, and load later. + while (mapheaderinfo[i]->ghostCount > 0) + { + mapheaderinfo[i]->ghostCount--; + + Z_Free(mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]); + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] = NULL; + } + + while (mapheaderinfo[i]->ghostCount < MAXSTAFF) + { + buffer[6] = '1' + mapheaderinfo[i]->ghostCount; + + ghost = vres_Find(virtmap, buffer); + if (ghost == NULL) + break; + + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] = G_GetStaffGhostBrief(ghost->data); + if (mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount] == NULL) + break; + /*CONS_Printf("name is %s, time is %d, lap is %d\n", + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->name, + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->time/TICRATE, + mapheaderinfo[i]->ghostBrief[mapheaderinfo[i]->ghostCount]->lap/TICRATE);*/ + + mapheaderinfo[i]->ghostCount++; + } + vres_Free(virtmap); } } diff --git a/src/typedef.h b/src/typedef.h index f33ee2f3b..a38b018a0 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -113,6 +113,7 @@ TYPEDEF (textprompt_t); TYPEDEF (mappoint_t); TYPEDEF (customoption_t); TYPEDEF (gametype_t); +TYPEDEF (staffbrief_t); TYPEDEF (mapheader_t); TYPEDEF (tolinfo_t); TYPEDEF (cupheader_t); From f378dfe3f65df5bf8f9e56658cf5f5ce79559777 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 13:53:26 +0000 Subject: [PATCH 02/37] ACS Environment::loadModule: Free vres after generation Discovered (temporary) memory leak while writing the following commit --- src/acs/environment.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index c56f82d87..ad593e74b 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -198,6 +198,8 @@ void Environment::loadModule(ACSVM::Module *module) { CONS_Printf("No BEHAVIOR lump found.\n"); } + + vres_Free(vRes); } else { From 1efc5883e0925038aa51a0d778d8aa3bdb0dc85b Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 18:16:18 +0000 Subject: [PATCH 03/37] G_DoPlayDemo: Remove memory leak in pdemoname --- src/g_demo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_demo.c b/src/g_demo.c index 17a8e4865..ddf1e243f 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2987,6 +2987,7 @@ void G_DoPlayDemo(char *defdemoname) { snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); gameaction = ga_nothing; M_StartMessage(msg, NULL, MM_NOTHING); return; From 29ddf06f1e5ae7504444a36bf7c46ad2c6c815d0 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 18:18:43 +0000 Subject: [PATCH 04/37] G_DoPlayDemo: Add support for replays stored inside map vres --- src/g_demo.c | 68 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index ddf1e243f..6dbedc76b 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2996,18 +2996,68 @@ void G_DoPlayDemo(char *defdemoname) // load demo resource from WAD else { - if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + if (n == defdemoname) { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } + // Raw lump. + if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } - P_SaveBufferFromLump(&demobuf, l); + P_SaveBufferFromLump(&demobuf, l); + } + else + { + // vres GHOST_%u + virtres_t *vRes; + virtlump_t *vLump; + UINT16 mapnum; + size_t step = 0; + + step = 0; + while (defdemoname+step < n-1) + { + mapname[step] = defdemoname[step]; + step++; + } + mapname[step] = '\0'; + + mapnum = G_MapNumber(mapname); + if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum); + vLump = vres_Find(vRes, pdemoname); + + if (vLump == NULL) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + P_SaveBufferAlloc(&demobuf, vLump->size); + memcpy(demobuf.buffer, vLump->data, vLump->size); + + vres_Free(vRes); + } #if defined(SKIPERRORS) && !defined(DEVELOP) - skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... + skiperrors = true; // RR: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif } } From 96297aad1ca8dc179914256d8a0aedc2b9c8c2aa Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 18:23:59 +0000 Subject: [PATCH 05/37] Title demos: Add support for game loading vRes staff ghosts as title demos --- src/f_finale.c | 48 ++++++++++++------------------------------------ src/g_game.c | 14 ++++---------- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index dd053b558..946b749ee 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2194,25 +2194,20 @@ void F_TitleScreenTicker(boolean run) return; } -#ifdef STAFFGHOSTS // is it time? if (!(--demoIdleLeft)) { - //static boolean use_netreplay = false; - - char dname[9]; - char *dname2 = dname; - lumpnum_t l; - const char *mapname; + char dname[MAXMAPLUMPNAME+1+8+1]; + UINT16 mapnum; UINT8 numstaff; + static boolean use_netreplay = false; - //@TODO uncomment this when this goes into vanilla - /*if ((use_netreplay = !use_netreplay))*/ + if ((use_netreplay = !use_netreplay)) { - numstaff = 1; - while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) + lumpnum_t l = LUMPERROR; + numstaff = 0; + while (numstaff < 99 && (l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) numstaff++; - numstaff--; if (numstaff) { @@ -2225,42 +2220,23 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - if ((l = W_CheckNumForName("MAP01S01")) == LUMPERROR) // gotta have ONE + mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); + if (mapnum == 0) // gotta have ONE { - F_StartIntro(); return; } - mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1); - - numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) - numstaff++; - - numstaff = M_RandomKey(numstaff)+1; + numstaff = M_RandomKey(mapheaderinfo[mapnum]->ghostCount)+1; // Setup demo name - dname2 = Z_StrDup(va("%sS%02u", mapname, numstaff)); - - /*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now - { - CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname); - F_StartIntro(); - return; - }*/ + sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff); loadreplay: demo.title = demo.fromtitle = true; demo.ignorefiles = true; demo.loadfiles = false; - G_DoPlayDemo(dname2); - - if (dname2 != dname) - { - Z_Free(dname2); - } + G_DoPlayDemo(dname); } -#endif //#ifdef STAFFGHOSTS } void F_TitleDemoTicker(void) diff --git a/src/g_game.c b/src/g_game.c index 972f449e1..425b38ed2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3441,6 +3441,10 @@ tryagain: || (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad continue; //isokmap = false; + if (pprevmap == -2 // title demo hack + && mapheaderinfo[ix]->ghostCount == 0) + continue; + if (!ignorebuffer) { if (extbufsize > 0) @@ -3475,16 +3479,6 @@ tryagain: continue; } -#ifdef STAFFGHOSTS - if (pprevmap == -2) // title demo hack - { - lumpnum_t l; - // TODO: Use map header to determine lump name - if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) - continue; - } -#endif //#ifdef STAFFGHOSTS - okmaps[numokmaps++] = ix; } From 3ca1c554c495c79fec08c74b97858ff0994f34fa Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 10:44:47 +0000 Subject: [PATCH 06/37] M_HandleMenuInput: Pass a choice of 2 to IT_CVAR/IT_ARROWS routines - Permits IT_ARROWS routines to distinguish between a rightward input and an A-button input. - Only M_ChangeCvar needed to change to accomodate this - every other example of IT_ARROWS already acommodates this --- src/k_menufunc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 7fd1adc61..6e9116cf2 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -143,7 +143,7 @@ static void M_ChangeCvar(INT32 choice) return; } - choice = (choice<<1) - 1; + choice = (choice == 0 ? -1 : 1); if (((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_SLIDER) || ((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) @@ -939,7 +939,7 @@ static void M_HandleMenuInput(void) { case IT_CVAR: case IT_ARROWS: - routine(1); // right arrow + routine(2); // usually right arrow break; case IT_CALL: routine(itemOn); From a2fadd2ff468562163de282d77e32555bd021c05 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 11:06:28 +0000 Subject: [PATCH 07/37] M_ChangeCvar: Split out core of function into M_ChangeCvarDirect, to prevent future code duplication --- src/k_menu.h | 2 +- src/k_menufunc.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index de53864b1..9b1a383f7 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -576,7 +576,7 @@ boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt); boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt); boolean M_ChangeStringCvar(INT32 choice); - +void M_ChangeCvarDirect(INT32 choice, consvar_t *cv); boolean M_NextOpt(void); boolean M_PrevOpt(void); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 6e9116cf2..177b30442 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -132,10 +132,8 @@ static void Dummystaff_OnChange(void) // BASIC MENU HANDLING // ========================================================================= -static void M_ChangeCvar(INT32 choice) +void M_ChangeCvarDirect(INT32 choice, consvar_t *cv) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; - // Backspace sets values to default value if (choice == -1) { @@ -170,6 +168,11 @@ static void M_ChangeCvar(INT32 choice) } } +static void M_ChangeCvar(INT32 choice) +{ + M_ChangeCvarDirect(choice, currentMenu->menuitems[itemOn].itemaction.cvar); +} + boolean M_NextOpt(void) { INT16 oldItemOn = itemOn; // prevent infinite loop From 6dd32deecbb65aaaf34da702a3d85dcea0aacc60 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 11:06:57 +0000 Subject: [PATCH 08/37] M_HandleStaffReplay, M_DrawTimeAttack: Re-support selecting staff replays from the menu --- src/k_menu.h | 1 - src/k_menudraw.c | 56 ++++++++++++++++++++----- src/k_menufunc.c | 42 ++++--------------- src/menus/play-local-race-time-attack.c | 28 ++++++++----- 4 files changed, 70 insertions(+), 57 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 9b1a383f7..b1b699fbc 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -469,7 +469,6 @@ void Moviemode_option_Onchange(void); extern menu_t *currentMenu; extern menu_t *restoreMenu; -extern char dummystaffname[22]; extern consvar_t cv_dummystaff; extern INT16 itemOn; // menu item skull is on, Hack by Tails 09-18-2002 diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 20c51b412..92197d18d 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2240,7 +2240,6 @@ void M_DrawTimeAttack(void) INT32 w; patch_t *minimap = NULL; UINT8 i; - consvar_t *cv; M_DrawLevelSelectBlock(0, 2, map, true, false); @@ -2303,19 +2302,56 @@ void M_DrawTimeAttack(void) opty += 10; // Cvar specific handling - - if (currentMenu->menuitems[i].status & IT_CVAR) { - cv = currentMenu->menuitems[i].itemaction.cvar; + const char *str = NULL; + INT32 optflags = f; + boolean drawarrows = (i == itemOn); - w = V_StringWidth(cv->string, 0); - V_DrawString(leftedge, opty, f, cv->string); - if (i == itemOn) + if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) { - V_DrawCharacter(leftedge - 10 - (skullAnimCounter/5), opty, '\x1C' | f, false); // left arrow - V_DrawCharacter(leftedge + w + 2+ (skullAnimCounter/5), opty, '\x1D' | f, false); // right arrow + // Currently assumes M_HandleStaffReplay + if (mapheaderinfo[levellist.choosemap]->ghostCount <= 1) + drawarrows = false; + + optflags |= V_ALLOWLOWERCASE; + if (mapheaderinfo[levellist.choosemap] == NULL) + str = "Invalid map"; + else if (cv_dummystaff.value > mapheaderinfo[levellist.choosemap]->ghostCount) + str = va("%u - Invalid ID", cv_dummystaff.value+1); + else if (mapheaderinfo[levellist.choosemap]->ghostBrief[cv_dummystaff.value] == NULL) + str = va("%u - Invalid brief", cv_dummystaff.value+1); + else + { + const char *th = "th"; + if (cv_dummystaff.value+1 == 1) + th = "st"; + else if (cv_dummystaff.value+1 == 2) + th = "nd"; + else if (cv_dummystaff.value+1 == 3) + th = "rd"; + str = va("%u%s - %s", + cv_dummystaff.value+1, + th, + mapheaderinfo[levellist.choosemap]->ghostBrief[cv_dummystaff.value]->name + ); + } + } + else if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_CVAR) + { + str = currentMenu->menuitems[i].itemaction.cvar->string; + } + + if (str) + { + w = V_StringWidth(str, optflags); + V_DrawString(leftedge+12, opty, optflags, str); + if (drawarrows) + { + V_DrawCharacter(leftedge+12 - 10 - (skullAnimCounter/5), opty, '\x1C' | f, false); // left arrow + V_DrawCharacter(leftedge+12 + w + 2+ (skullAnimCounter/5), opty, '\x1D' | f, false); // right arrow + } + opty += 10; } - opty += 10; } break; diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 177b30442..53cb6745a 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -37,8 +37,6 @@ boolean fromlevelselect = false; menu_t *currentMenu = &MAIN_ProfilesDef; menu_t *restoreMenu = NULL; -char dummystaffname[22]; - INT16 itemOn = 0; // menu item skull is on, Hack by Tails 09-18-2002 INT16 skullAnimCounter = 8; // skull animation counter struct menutransition_s menutransition; // Menu transition properties @@ -77,7 +75,7 @@ consvar_t cv_tutorialprompt = CVAR_INIT ("tutorialprompt", "On", CV_SAVE, CV_OnO static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; -static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {MAXSTAFF-1, "MAX"}, {0, NULL}}; static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL); //static cv_dummyspectate = CVAR_INITconsvar_t ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL); @@ -92,39 +90,15 @@ consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, static void Dummystaff_OnChange(void) { -#ifdef STAFFGHOSTS - lumpnum_t l; + if (mapheaderinfo[levellist.choosemap] == NULL || mapheaderinfo[levellist.choosemap]->ghostCount <= 0) + return; - dummystaffname[0] = '\0'; - - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) + dummystaff_cons_t[1].value = mapheaderinfo[levellist.choosemap]->ghostCount-1; + if (cv_dummystaff.value > dummystaff_cons_t[1].value) { CV_StealthSetValue(&cv_dummystaff, 0); return; } - else - { - char *temp = dummystaffname; - UINT8 numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR) - numstaff++; - - if (cv_dummystaff.value < 1) - CV_StealthSetValue(&cv_dummystaff, numstaff); - else if (cv_dummystaff.value > numstaff) - CV_StealthSetValue(&cv_dummystaff, 1); - - if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR) - return; // shouldn't happen but might as well check... - - G_UpdateStaffGhostName(l); - - while (*temp) - temp++; - - sprintf(temp, " - %d", cv_dummystaff.value); - } -#endif //#ifdef STAFFGHOSTS } @@ -968,19 +942,17 @@ static void M_HandleMenuInput(void) if (routine && ((currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_ARROWS || (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR)) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; + /*consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; // Make these CVar options? if (cv == &cv_chooseskin || cv == &cv_dummystaff - /* || cv == &cv_nextmap || cv == &cv_newgametype - */ ) { return; - } + }*/ S_StartSound(NULL, sfx_s3k5b); diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 244b720b2..9443379f1 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -56,7 +56,7 @@ menuitem_t PLAY_TAReplay[] = {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_CALL, "Replay Staff", NULL, NULL, {.routine = M_HandleStaffReplay}, 0, 0}, + {IT_STRING | IT_ARROWS, "Replay Staff", NULL, NULL, {.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}, @@ -197,8 +197,6 @@ void M_PrepareTimeAttack(INT32 choice) if (!gpath) return; - CV_StealthSetValue(&cv_dummystaff, 0); - active = false; PLAY_TimeAttack[ta_guest].status = IT_DISABLED; PLAY_TimeAttack[ta_replay].status = IT_DISABLED; @@ -257,16 +255,13 @@ void M_PrepareTimeAttack(INT32 choice) PLAY_TAReplay[tareplay_staff].status = PLAY_TAGhosts[taghost_staff].status = IT_DISABLED; -#ifdef STAFFGHOSTS - CV_SetValue(&cv_dummystaff, 1); - if (cv_dummystaff.value) + if (mapheaderinfo[levellist.choosemap]->ghostCount > 0) { - PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_KEYHANDLER; + PLAY_TAReplay[tareplay_staff].status = IT_STRING|IT_ARROWS; PLAY_TAGhosts[taghost_staff].status = IT_STRING|IT_CVAR; - CV_StealthSetValue(&cv_dummystaff, 1); + CV_SetValue(&cv_dummystaff, 0); active |= 1|4; } -#endif //#ifdef STAFFGHOSTS if (active & 1) PLAY_TimeAttack[ta_replay].status = IT_STRING|IT_SUBMENU; @@ -287,8 +282,19 @@ void M_PrepareTimeAttack(INT32 choice) void M_HandleStaffReplay(INT32 choice) { - // @TODO: - (void) choice; + if (choice == 2) + { + restoreMenu = &PLAY_TimeAttackDef; + + M_ClearMenus(true); + demo.loadfiles = false; + demo.ignorefiles = true; // Just assume that record attack replays have the files needed + + G_DoPlayDemo(va("%s/GHOST_%u", mapheaderinfo[levellist.choosemap]->lumpname, cv_dummystaff.value+1)); + return; + } + + M_ChangeCvarDirect(choice, &cv_dummystaff); } void M_ReplayTimeAttack(INT32 choice) From 3e0ba74003d3be449da7d716196b58d165c98248 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 11:07:29 +0000 Subject: [PATCH 09/37] P_PlaybackSetViews: Support C-button reset to 1p view --- src/menus/transient/pause-replay.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index 037889f4f..dd0c6588b 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -210,7 +210,14 @@ void M_PlaybackSetViews(INT32 choice) } else if (r_splitscreen) { - r_splitscreen--; + if (choice == 0) + { + r_splitscreen--; + } + else + { + r_splitscreen = 0; + } R_ExecuteSetViewSize(); } } From 59f9609160f7f6ea3746bdf705b6ce65c8d7b744 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 15:46:15 +0000 Subject: [PATCH 10/37] G_AddGhost, G_LoadRecordGhosts: Re-add support for loading staff ghosts. - UINT8 *buffer for AddGhost must now be allocated and filled externally. - Introduce P_TryAddExternalGhost helper function for existing external ghosts. - Call vRes_Free(curmapvirt) later, and NULL to make incorrect usage immediately obvious. --- src/g_demo.c | 74 ++++++++++++--------------------------------------- src/g_demo.h | 2 +- src/p_setup.c | 59 +++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 76 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 6dbedc76b..0fe7df053 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3030,7 +3030,7 @@ void G_DoPlayDemo(char *defdemoname) mapnum = G_MapNumber(mapname); if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR) { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname); + snprintf(msg, 1024, M_GetText("Failed to read virtlump '%s (couldn't find map %s)'.\n"), defdemoname, mapname); CONS_Alert(CONS_ERROR, "%s", msg); Z_Free(pdemoname); gameaction = ga_nothing; @@ -3043,7 +3043,7 @@ void G_DoPlayDemo(char *defdemoname) if (vLump == NULL) { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname); + snprintf(msg, 1024, M_GetText("Failed to read virtlump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname); CONS_Alert(CONS_ERROR, "%s", msg); Z_Free(pdemoname); gameaction = ga_nothing; @@ -3480,14 +3480,13 @@ void G_DoPlayDemo(char *defdemoname) demo.deferstart = true; } -void G_AddGhost(char *defdemoname) +void G_AddGhost(UINT8 *buffer, char *defdemoname) { INT32 i; - lumpnum_t l; - char name[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; + char name[17], color[MAXCOLORNAME+1], md5[16]; demoghost *gh; UINT8 flags; - UINT8 *buffer,*p; + UINT8 *p; mapthing_t *mthing; UINT16 count, ghostversion; skin_t *ghskin = &skins[0]; @@ -3497,41 +3496,12 @@ void G_AddGhost(char *defdemoname) name[16] = '\0'; color[16] = '\0'; - n = defdemoname+strlen(defdemoname); - while (*n != '/' && *n != '\\' && n != defdemoname) - n--; - if (n != defdemoname) - n++; - pdemoname = ZZ_Alloc(strlen(n)+1); - strcpy(pdemoname,n); - - // Internal if no extension, external if one exists - if (FIL_CheckExtension(defdemoname)) - { - //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - p = buffer; - } - // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) - { - CONS_Alert(CONS_ERROR, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - Z_Free(pdemoname); - return; - } - else // it's an internal demo - buffer = p = W_CacheLumpNum(l, PU_LEVEL); + p = buffer; // read demo header if (memcmp(p, DEMOHEADER, 12)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Not a SRB2 replay.\n"), defdemoname); Z_Free(buffer); return; } p += 12; // DEMOHEADER @@ -3546,8 +3516,7 @@ void G_AddGhost(char *defdemoname) break; // too old, cannot support. default: - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), defdemoname); Z_Free(buffer); return; } @@ -3558,16 +3527,14 @@ void G_AddGhost(char *defdemoname) for (gh = ghosts; gh; gh = gh->next) if (!memcmp(md5, gh->checksum, 16)) // another ghost in the game already has this checksum? { // Don't add another one, then! - CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", pdemoname); - Z_Free(pdemoname); + CONS_Debug(DBG_SETUP, "Rejecting duplicate ghost %s (MD5 was matched)\n", defdemoname); Z_Free(buffer); return; } if (memcmp(p, "PLAY", 4)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), defdemoname); Z_Free(buffer); return; } p += 4; // "PLAY" @@ -3579,16 +3546,14 @@ void G_AddGhost(char *defdemoname) flags = READUINT8(p); if (!(flags & DF_GHOST)) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), defdemoname); Z_Free(buffer); return; } if (flags & DF_LUAVARS) // can't be arsed to add support for grinding away ported lua material { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), defdemoname); Z_Free(buffer); return; } @@ -3600,8 +3565,7 @@ void G_AddGhost(char *defdemoname) skinlist = G_LoadDemoSkins(&p, &worknumskins, true); if (!skinlist) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data has invalid skin list, cannot continue.\n"), pdemoname); - Z_Free(pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data has invalid skin list, cannot continue.\n"), defdemoname); Z_Free(buffer); return; } @@ -3629,9 +3593,8 @@ void G_AddGhost(char *defdemoname) if (*p == DEMOMARKER) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3642,9 +3605,8 @@ void G_AddGhost(char *defdemoname) i = READUINT8(p); if ((i & (DEMO_SPECTATOR|DEMO_BOT)) != 0) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3675,9 +3637,8 @@ void G_AddGhost(char *defdemoname) if (READUINT8(p) != 0xFF) { - CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), pdemoname); + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), defdemoname); Z_Free(skinlist); - Z_Free(pdemoname); Z_Free(buffer); return; } @@ -3744,8 +3705,7 @@ void G_AddGhost(char *defdemoname) } gh->oldmo.color = gh->mo->color; - CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); - Z_Free(pdemoname); + CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, defdemoname); } // Clean up all ghosts diff --git a/src/g_demo.h b/src/g_demo.h index d99b7a3ad..446ae7bab 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -184,7 +184,7 @@ extern demoghost *ghosts; void G_DeferedPlayDemo(const char *demo); void G_DoPlayDemo(char *defdemoname); void G_TimeDemo(const char *name); -void G_AddGhost(char *defdemoname); +void G_AddGhost(UINT8 *buffer, char *defdemoname); staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer); void G_FreeGhosts(void); void G_DoneLevelLoad(void); diff --git a/src/p_setup.c b/src/p_setup.c index 8381034a2..70c386a7a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6908,8 +6908,6 @@ static boolean P_LoadMapFromFile(void) spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); P_MakeMapMD5(curmapvirt, &mapmd5); - - vres_Free(curmapvirt); return true; } @@ -7138,6 +7136,23 @@ static void P_ResetSpawnpoints(void) skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; } +static void P_TryAddExternalGhost(char *defdemoname) +{ + UINT8 *buffer = NULL; + + if (FIL_FileExists(defdemoname)) + { + if (FIL_ReadFileTag(defdemoname, &buffer, PU_LEVEL)) + { + G_AddGhost(buffer, defdemoname); + } + else + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), defdemoname); + } + } +} + static void P_LoadRecordGhosts(void) { // see also /menus/play-local-race-time-attack.c's M_PrepareTimeAttack @@ -7156,8 +7171,7 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); } } } @@ -7172,8 +7186,7 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); } } } @@ -7186,29 +7199,35 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_last.value == 1 && players[consoleplayer].skin != i) continue; - if (FIL_FileExists(va("%s-%s-last.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); + P_TryAddExternalGhost(va("%s-%s-last.lmp", gpath, skins[i].name)); } } // Guest ghost - if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) - G_AddGhost(va("%s-guest.lmp", gpath)); + if (cv_ghost_guest.value) + P_TryAddExternalGhost(va("%s-guest.lmp", gpath)); -#ifdef STAFFGHOSTS // Staff Attack ghosts if (cv_ghost_staff.value) { - lumpnum_t l; - UINT8 j = 1; - // TODO: Use vres for lumps - while (j <= 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) + char *defdemoname; + virtlump_t *vLump; + UINT8 *buffer = NULL; + + for (i = mapheaderinfo[gamemap-1]->ghostCount; i > 0; i--) { - G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j)); - j++; + defdemoname = va("GHOST_%u", i); + vLump = vres_Find(curmapvirt, defdemoname); + if (vLump == NULL) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read virtlump '%s'.\n"), defdemoname); + continue; + } + buffer = Z_Malloc(vLump->size, PU_LEVEL, NULL); + memcpy(buffer, vLump->data, vLump->size); + G_AddGhost(buffer, defdemoname); } } -#endif //#ifdef STAFFGHOSTS Z_Free(gpath); } @@ -7802,6 +7821,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (!fromnetsave) P_InitGametype(); + // Now safe to free. + vres_Free(curmapvirt); + curmapvirt = NULL; + if (!reloadinggamestate) { P_InitCamera(); From 84a98475ff33882dfb53c5c8e27e108f99f8f2e7 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 17:07:24 +0000 Subject: [PATCH 11/37] Command_ExitGame_f: Return to title if restoreMenu is NULL --- src/d_netcmd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2522ed4f4..1fa1a9ea8 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5784,8 +5784,15 @@ void Command_ExitGame_f(void) if (!modeattacking) { - D_ClearState(); - M_StartControlPanel(); + if (restoreMenu == NULL) + { + D_StartTitle(); + } + else + { + D_ClearState(); + M_StartControlPanel(); + } } } From e67fea3b8433897f4ba4c016c755c532ed7f7ff8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 17:11:46 +0000 Subject: [PATCH 12/37] s_sound.c - Add exceptions for demo.rewinding and demo.title to all new music setter functions introduced with 2.2 merge --- src/s_sound.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/s_sound.c b/src/s_sound.c index aedcaee15..e146e5dd6 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1761,6 +1761,10 @@ UINT32 S_GetMusicLoopPoint(void) boolean S_SetMusicPosition(UINT32 position) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + return I_SetSongPosition(position); } @@ -1962,7 +1966,13 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) UINT32 newpos = 0; boolean mapmuschanged = false; musicstack_t *result; - musicstack_t *entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL); + musicstack_t *entry; + + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + + entry = Z_Calloc(sizeof (*result), PU_MUSIC, NULL); if (status) result = S_GetMusicStackEntry(status, fromfirst, -1); @@ -2387,6 +2397,10 @@ void S_StopFadingMusic(void) boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 ms) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + if (source_volume < 0) return I_FadeSong(target_volume, ms, NULL); else @@ -2395,6 +2409,10 @@ boolean S_FadeMusicFromVolume(UINT8 target_volume, INT16 source_volume, UINT32 m boolean S_FadeOutStopMusic(UINT32 ms) { + if (demo.rewinding // Don't mess with music while rewinding! + || demo.title) // SRB2Kart: Demos don't interrupt title screen music + return false; + return I_FadeSong(0, ms, &S_StopMusic); } From c6dde482455f1af1db49796ccc41d5da77051b1b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 17:13:07 +0000 Subject: [PATCH 13/37] g_demo.c, M_EndModeAttackRun, D_ClearState - Unset demo.title in one specific place Fixes returning from title demo to titlescreen --- src/d_main.c | 6 ++++-- src/g_demo.c | 11 ----------- src/menus/transient/pause-replay.c | 4 +--- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6f1c0f6a3..589108d75 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -952,7 +952,7 @@ void D_ClearState(void) memset(displayplayers, 0, sizeof(displayplayers)); memset(g_localplayers, 0, sizeof g_localplayers); consoleplayer = 0; - //demosequence = -1; + demo.title = false; G_SetGametype(GT_RACE); // SRB2kart paused = false; @@ -975,7 +975,9 @@ void D_ClearState(void) // void D_StartTitle(void) { - S_StopMusic(); + if (!demo.title) + S_StopMusic(); + D_ClearState(); F_StartTitleScreen(); M_ClearMenus(false); diff --git a/src/g_demo.c b/src/g_demo.c index 0fe7df053..e95daa2b5 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3073,7 +3073,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } demobuf.p += 12; // DEMOHEADER @@ -3093,7 +3092,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3111,7 +3109,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } demobuf.p += 4; // "PLAY" @@ -3131,7 +3128,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } G_SetGametype(i); @@ -3189,7 +3185,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } } @@ -3204,7 +3199,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3240,7 +3234,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3258,7 +3251,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -3313,7 +3305,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } } @@ -3331,7 +3322,6 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(pdemoname); Z_Free(demobuf.buffer); demo.playback = false; - demo.title = false; return; } @@ -4028,7 +4018,6 @@ void G_StopDemo(void) Z_Free(demobuf.buffer); demobuf.buffer = NULL; demo.playback = false; - demo.title = false; demo.timing = false; singletics = false; diff --git a/src/menus/transient/pause-replay.c b/src/menus/transient/pause-replay.c index dd0c6588b..5a7c45826 100644 --- a/src/menus/transient/pause-replay.c +++ b/src/menus/transient/pause-replay.c @@ -50,15 +50,13 @@ menu_t PAUSE_PlaybackMenuDef = { void M_EndModeAttackRun(void) { - boolean dotitle = demo.title; - G_CheckDemoStatus(); // Cancel recording Command_ExitGame_f(); // Clear a bunch of state modeattacking = ATTACKING_NONE; // Kept until now because of Command_ExitGame_f - if (dotitle) + if (demo.title == true) { D_StartTitle(); } From 604ac1101b4f40d19b4e2aab0e23bd0baf178d9c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 17:14:06 +0000 Subject: [PATCH 14/37] demovars_s: Remove unused fromtitle property Was superseded by demo.title --- src/f_finale.c | 2 +- src/g_demo.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 946b749ee..37a50cb3a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2232,7 +2232,7 @@ void F_TitleScreenTicker(boolean run) sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff); loadreplay: - demo.title = demo.fromtitle = true; + demo.title = true; demo.ignorefiles = true; demo.loadfiles = false; G_DoPlayDemo(dname); diff --git a/src/g_demo.h b/src/g_demo.h index 446ae7bab..4b4195e2d 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -47,7 +47,6 @@ struct demovars_s { boolean rewinding; // Rewind in progress boolean loadfiles, ignorefiles; // Demo file loading options - boolean fromtitle; // SRB2Kart: Don't stop the music boolean inreplayhut; // Go back to replayhut after demos boolean quitafterplaying; // quit after playing a demo from cmdline boolean deferstart; // don't start playing demo right away From 4446b1ed9ea73cd6ad7fb56652c554c6c2f7f43b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 18:04:18 +0000 Subject: [PATCH 15/37] K_drawKartHUD: Draw a special mini version of RR's title logo instead of that of SRB2Kart's --- src/k_hud.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index a527c87e3..0a1b262f4 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5063,17 +5063,17 @@ void K_drawKartHUD(void) { if (demo.title) // Draw title logo instead in demo.titles { - INT32 x = BASEVIDWIDTH - 32, y = 128, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; + INT32 x = BASEVIDWIDTH - 8, y = BASEVIDHEIGHT-8, snapflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SLIDEIN; + patch_t *pat = W_CachePatchName((cv_alttitle.value ? "MTSJUMPR1" : "MTSBUMPR1"), PU_CACHE); if (r_splitscreen == 3) { - x = BASEVIDWIDTH/2 + 10; - y = BASEVIDHEIGHT/2 - 30; + x = BASEVIDWIDTH/2; + y = BASEVIDHEIGHT/2; snapflags = 0; } - V_DrawTinyScaledPatch(x-54, y, snapflags|V_SLIDEIN, W_CachePatchName("TTKBANNR", PU_CACHE)); - V_DrawTinyScaledPatch(x-54, y+25, snapflags|V_SLIDEIN, W_CachePatchName("TTKART", PU_CACHE)); + V_DrawScaledPatch(x-(SHORT(pat->width)), y-(SHORT(pat->height)), snapflags, pat); } else { From 3bfd4be29e91a426b36cdbd40992aa65004ffdbf Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 18:04:56 +0000 Subject: [PATCH 16/37] AltTitle_OnChange: Actually correctly set cv_alttitle instead of cv_itemfinder if modified when unlocked --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1fa1a9ea8..8ca9286d1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4894,7 +4894,7 @@ void AltTitle_OnChange(void) if (!M_SecretUnlocked(SECRET_ALTTITLE, true)) { CONS_Printf(M_GetText("You haven't earned this yet.\n")); - CV_StealthSetValue(&cv_itemfinder, 0); + CV_StealthSetValue(&cv_alttitle, 0); return; } } From f1e925553d1c1acf25281ad734aa15c53babc911 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 20:33:19 +0000 Subject: [PATCH 17/37] M_CompletionEmblems: Fix check for ET_MAP --- src/m_cond.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cond.c b/src/m_cond.c index d93ff8d55..b941ea65c 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -998,7 +998,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa { INT32 checkLevel; - if (emblemlocations[i].type < ET_TIME || gamedata->collected[i]) + if (emblemlocations[i].type != ET_MAP || gamedata->collected[i]) continue; checkLevel = M_EmblemMapNum(&emblemlocations[i]); From 75ffdf06cda92c2a52e508b84bb22be39db4691c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 20:38:15 +0000 Subject: [PATCH 18/37] reademblemdata: Change defaults for part-provided Medal definitions --- src/deh_soc.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 853c7f182..4a5a6a5fd 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2185,19 +2185,13 @@ void reademblemdata(MYFILE *f, INT32 num) } while (!myfeof(f)); // Default sprite and color definitions for lazy people like me - if (!emblemlocations[num-1].sprite) switch (emblemlocations[num-1].type) + if (!emblemlocations[num-1].sprite) { - case ET_TIME: - emblemlocations[num-1].sprite = 'B'; break; - default: - emblemlocations[num-1].sprite = 'A'; break; + emblemlocations[num-1].sprite = 'A'; } - if (!emblemlocations[num-1].color) switch (emblemlocations[num-1].type) + if (!emblemlocations[num-1].color) { - case ET_TIME: //case ET_NTIME: - emblemlocations[num-1].color = SKINCOLOR_GREY; break; - default: - emblemlocations[num-1].color = SKINCOLOR_GOLD; break; + emblemlocations[num-1].color = SKINCOLOR_GOLD; } Z_Free(s); From ed07a74fb4aaaf8fb2420ff5a4638112bc8d76dc Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 21:01:49 +0000 Subject: [PATCH 19/37] staffbrief_t: Change datatype of stored times to tic_t --- src/doomstat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index fb62266a2..9a5b2f893 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -365,8 +365,8 @@ extern UINT16 numkartcupheaders; struct staffbrief_t { char name[16]; - INT32 time; - INT32 lap; + tic_t time; + tic_t lap; }; /** Map header information. From 2d54acae30208f7bb0e4619d3bb70d7f2cf2a384 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 22:16:33 +0000 Subject: [PATCH 20/37] M_DrawTimeAttack: Fix Medal drawing for timestamp K_drawKartTimestamp uses gamemap index instead of mapheaderinfo index --- src/k_menudraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 92197d18d..c64636abe 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2275,7 +2275,7 @@ void M_DrawTimeAttack(void) } V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(timerec, 162+t, timeheight+6, map, 1); + K_drawKartTimestamp(timerec, 162+t, timeheight+6, map+1, 1); } else opty = 80; From 42969d8d15a683053fc2b8090b0d6bf5900b257c Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 4 Feb 2023 22:17:47 +0000 Subject: [PATCH 21/37] M_CheckLevelEmblems: Support tagging ET_TIME emblems An ET_TIME emblem with a nonzero tag is directly bound to a staff ghost's finish time. This will make late development medal implementation signifcantly easier. --- src/k_hud.c | 20 +++++++++++++++----- src/m_cond.c | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 0a1b262f4..86b9cc82a 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1578,6 +1578,15 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI goto bademblem; } + if (emblem->tag > 0) + { + if (emblem->tag > mapheaderinfo[emblemmap-1]->ghostCount + || mapheaderinfo[emblemmap-1]->ghostBrief[emblem->tag-1] == NULL) + goto bademblem; + + timetoreach = mapheaderinfo[emblemmap-1]->ghostBrief[emblem->tag-1]->time; + } + snprintf(targettext, 9, "%i'%02i\"%02i", G_TicsToMinutes(timetoreach, false), G_TicsToSeconds(timetoreach), @@ -1605,9 +1614,10 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI goto bademblem; } - V_DrawRightAlignedString(workx, worky, splitflags|V_6WIDTHSPACE, targettext); - workx -= 67; - V_DrawSmallScaledPatch(workx + 4, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); + workx -= V_ThinStringWidth(targettext, splitflags|V_6WIDTHSPACE); + V_DrawThinString(workx, worky, splitflags|V_6WIDTHSPACE, targettext); + workx -= 11; + V_DrawSmallScaledPatch(workx, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); break; @@ -1619,8 +1629,8 @@ bademblem: splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS; while (curemb--) { - workx -= 12; - V_DrawSmallMappedPatch(workx + 4, worky, splitflags, emblempic[curemb], emblemcol[curemb]); + workx -= 11; + V_DrawSmallMappedPatch(workx, worky, splitflags, emblempic[curemb], emblemcol[curemb]); } } } diff --git a/src/m_cond.c b/src/m_cond.c index b941ea65c..4f0a9126a 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -949,6 +949,7 @@ UINT8 M_CheckLevelEmblems(void) { INT32 i; INT32 valToReach; + INT16 tag; INT16 levelnum; UINT8 res; UINT8 somethingUnlocked = 0; @@ -968,11 +969,23 @@ UINT8 M_CheckLevelEmblems(void) levelnum = checkLevel; valToReach = emblemlocations[i].var; + tag = emblemlocations[i].tag; switch (emblemlocations[i].type) { case ET_TIME: // Requires time on map <= x - res = (G_GetBestTime(levelnum) <= (unsigned)valToReach); + if (tag > 0) + { + if (tag > mapheaderinfo[checkLevel]->ghostCount + || mapheaderinfo[checkLevel]->ghostBrief[tag-1] == NULL) + continue; + + res = (G_GetBestTime(levelnum) <= mapheaderinfo[checkLevel]->ghostBrief[tag-1]->time); + } + else + { + res = (G_GetBestTime(levelnum) <= (unsigned)valToReach); + } break; default: // unreachable but shuts the compiler up. continue; From 2207115424640534588bd61dbb501d5462ab1ce0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 00:21:08 +0000 Subject: [PATCH 22/37] Time Attack: Update Medals on player exit, not on intermission - M_UpdateRecordReplays: Split out M_UpdateRecords - P_DoPlayerExit: Call M_UpdateRecords in modeattacking --- src/g_game.c | 52 ++++++++++++++++++++++++++++++++-------------------- src/g_game.h | 2 ++ src/p_user.c | 3 +++ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 425b38ed2..700f76f92 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -496,30 +496,26 @@ tic_t G_GetBestLap(INT16 map) */ // -// G_UpdateRecordReplays +// G_UpdateRecords // -// Update replay files/data, etc. for Record Attack +// Update time attack records // -static void G_UpdateRecordReplays(void) +void G_UpdateRecords(void) { - char *gpath; - char lastdemo[256], bestdemo[256]; UINT8 earnedEmblems; // Record new best time if (!mapheaderinfo[gamemap-1]->mainrecord) G_AllocMainRecordData(gamemap-1); - if (players[consoleplayer].pflags & PF_NOCONTEST) - { - players[consoleplayer].realtime = UINT32_MAX; - } - if (modeattacking & ATTACKING_TIME) { - if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time)) - && (players[consoleplayer].realtime < UINT32_MAX)) // DNF - mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime; + tic_t time = players[consoleplayer].realtime; + if (players[consoleplayer].pflags & PF_NOCONTEST) + time = UINT32_MAX; + if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (time < mapheaderinfo[gamemap-1]->mainrecord->time)) + && (time < UINT32_MAX)) // DNF + mapheaderinfo[gamemap-1]->mainrecord->time = time; } else { @@ -536,6 +532,29 @@ static void G_UpdateRecordReplays(void) mapheaderinfo[gamemap-1]->mainrecord->lap = 0; } + // Check emblems when level data is updated + if ((earnedEmblems = M_CheckLevelEmblems())) + CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + + M_UpdateUnlockablesAndExtraEmblems(true); + G_SaveGameData(); +} + +// +// G_UpdateRecordReplays +// +// Update replay files/data, etc. for Record Attack +// +static void G_UpdateRecordReplays(void) +{ + char *gpath; + char lastdemo[256], bestdemo[256]; + + if (players[consoleplayer].pflags & PF_NOCONTEST) + { + players[consoleplayer].realtime = UINT32_MAX; + } + // Save demo! bestdemo[255] = '\0'; lastdemo[255] = '\0'; @@ -590,13 +609,6 @@ static void G_UpdateRecordReplays(void) Z_Free(gpath); } - - // Check emblems when level data is updated - if ((earnedEmblems = M_CheckLevelEmblems())) - CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); - - M_UpdateUnlockablesAndExtraEmblems(true); - G_SaveGameData(); } // for consistency among messages: this modifies the game and removes savemoddata. diff --git a/src/g_game.h b/src/g_game.h index de60bee49..c2f1c5830 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,6 +201,8 @@ void G_UseContinue(void); void G_AfterIntermission(void); void G_EndGame(void); // moved from y_inter.c/h and renamed +void G_UpdateRecords(void); + void G_Ticker(boolean run); boolean G_Responder(event_t *ev); diff --git a/src/p_user.c b/src/p_user.c index f3c7c49c9..078f6e5ad 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1367,6 +1367,9 @@ void P_DoPlayerExit(player_t *player) } } + if (modeattacking) + G_UpdateRecords(); + player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation if (player == &players[consoleplayer]) From ac2255572a2ed1d9d85b6fa2a08b268cb4e62a84 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 00:35:22 +0000 Subject: [PATCH 23/37] K_drawKartTimestamp: Do not update visible emblems on level completion unless you got more than one on completion TODO: this code relies heavily on static variables. It has always done so, but the extent to which they're currently employed is worth a fresh look --- src/k_hud.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 86b9cc82a..e44d8ddd6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1471,6 +1471,9 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 + static UINT8 prevmode = UINT8_MAX; + static emblem_t *maxemblem = NULL; + tic_t worktime; INT32 jitter = 0; @@ -1510,6 +1513,10 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI } } + if (mode != prevmode) + maxemblem = NULL; + prevmode = mode; + V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide)); TX += 33; @@ -1558,10 +1565,13 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI UINT8 *emblemcol[3] = {NULL, NULL, NULL}; emblem_t *emblem = M_GetLevelEmblems(emblemmap); + while (emblem) { char targettext[9]; + emblem_t *nextemblem = M_GetLevelEmblems(-1); + switch (emblem->type) { case ET_TIME: @@ -1573,11 +1583,20 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI { emblempic[curemb] = W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE); emblemcol[curemb] = R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE); - if (++curemb == 3) - break; - goto bademblem; + curemb++; + + if (emblem == maxemblem + && nextemblem != NULL + && nextemblem->type == emblem->type + && gamedata->collected[(nextemblem-emblemlocations)]) + maxemblem = NULL; + + if (emblem != maxemblem) + goto bademblem; } + maxemblem = emblem; + if (emblem->tag > 0) { if (emblem->tag > mapheaderinfo[emblemmap-1]->ghostCount @@ -1616,13 +1635,19 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI workx -= V_ThinStringWidth(targettext, splitflags|V_6WIDTHSPACE); V_DrawThinString(workx, worky, splitflags|V_6WIDTHSPACE, targettext); - workx -= 11; - V_DrawSmallScaledPatch(workx, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); + + if (emblem != maxemblem || !gamedata->collected[(emblem-emblemlocations)]) + { + emblempic[curemb] = W_CachePatchName("NEEDIT", PU_CACHE); + curemb++; + } break; bademblem: - emblem = M_GetLevelEmblems(-1); + if (emblem == maxemblem || curemb == 3) + break; + emblem = nextemblem; } if (!mode) From e874b5ba182555c53ef90e1354d7a1881d490c15 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 13:33:31 +0000 Subject: [PATCH 24/37] G_DoLoadLevel: do not apply profile if demo is played from titlescreen --- src/d_clisrv.c | 2 +- src/g_game.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 53ed80968..f53d1f35a 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2066,7 +2066,7 @@ static void CL_ConnectToServer(void) CONS_Printf(M_GetText("Contacting the server...\n")); } - if (cv_currprofile.value == -1) + if (cv_currprofile.value == -1 && !demo.playback) { PR_ApplyProfilePretend(cv_ttlprofilen.value, 0); for (i = 1; i < cv_splitplayers.value; i++) diff --git a/src/g_game.c b/src/g_game.c index 700f76f92..6b46afcd8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1351,7 +1351,7 @@ void G_DoLoadLevel(boolean resetplayer) if (wipegamestate == GS_LEVEL) wipegamestate = -1; // force a wipe - if (cv_currprofile.value == -1) + if (cv_currprofile.value == -1 && !demo.playback) { PR_ApplyProfilePretend(cv_ttlprofilen.value, 0); for (i = 1; i < cv_splitplayers.value; i++) From de526a788998e604cd510eab9922f7f889b82629 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 13:35:15 +0000 Subject: [PATCH 25/37] D_ClearState: Prevent opportunities for double-wipes --- src/d_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_main.c b/src/d_main.c index 589108d75..38c16bc39 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -968,6 +968,7 @@ void D_ClearState(void) tutorialmode = false; G_SetGamestate(GS_NULL); + wipegamestate = GS_NULL; } // From 63fbdcfbc06beb9095b382d87a983a1374de1f08 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 14:09:30 +0000 Subject: [PATCH 26/37] M_StartControlPanel: Do not activate if map change is pending Prevents restoreMenu being burned when pressing start during long GP/Match Race fade. --- src/k_menufunc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 53cb6745a..eb0add401 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -443,7 +443,7 @@ void M_StartControlPanel(void) } // intro might call this repeatedly - if (menuactive && gamestate != GS_NULL) + if (mapchangepending || (menuactive && gamestate != GS_NULL)) { CON_ToggleOff(); // move away console return; From 4522ba3b4dbbbe9d9ad70ae0e36e815baa4dbff1 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 16:13:16 +0000 Subject: [PATCH 27/37] stickermedalinfo, UpdateTimeStickerMedals: A centralised struct for Medal info attached to the time sticker. - K_drawKartTimestamp: Significantly less messy, no longer dependent on static variables, and no longer iterates over M_GetLevelEmblems every rendered frame(!!) - TODO: Still handles playing sound in the drawer - K_PrepareTimeAttack: Initial generation of a struct of emblems/text is handled on the menu - G_UpdateRecords: Updated in-game if you unlock the next medal there This commit was amended to centralise the new material in g_game.c and reduce the number of header additions required. --- src/g_game.c | 90 +++++++++++++++- src/g_game.h | 12 +++ src/k_hud.c | 133 +++++++----------------- src/k_hud.h | 2 +- src/k_menudraw.c | 4 +- src/menus/play-local-race-time-attack.c | 5 + 6 files changed, 144 insertions(+), 102 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 6b46afcd8..709018aed 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -465,11 +465,6 @@ void G_ClearRecords(void) Z_Free(mapheaderinfo[i]->mainrecord); mapheaderinfo[i]->mainrecord = NULL; } - /*if (nightsrecords[i]) - { - Z_Free(nightsrecords[i]); - nightsrecords[i] = NULL; - }*/ } } @@ -495,6 +490,84 @@ tic_t G_GetBestLap(INT16 map) } */ +struct stickermedalinfo stickermedalinfo; + +void G_UpdateTimeStickerMedals(UINT16 map) +{ + emblem_t *emblem = M_GetLevelEmblems(map+1); + boolean gonnadrawtime = false; + + stickermedalinfo.visiblecount = 0; + stickermedalinfo.targettext[0] = '\0'; + stickermedalinfo.emblems[0] = stickermedalinfo.regenemblem = NULL; + stickermedalinfo.timetoreach = UINT32_MAX; + stickermedalinfo.canplaysound = true; + + while (emblem != NULL) + { + UINT8 i = 0; + + switch (emblem->type) + { + case ET_TIME: + { + break; + } + default: + goto bademblem; + } + + if (!gamedata->collected[(emblem-emblemlocations)] && gonnadrawtime) + break; + + // Simpler than having two checks + if (stickermedalinfo.visiblecount == MAXMEDALVISIBLECOUNT) + stickermedalinfo.visiblecount--; + + // Shuffle along, so [0] is the "main focus" + for (i = stickermedalinfo.visiblecount; i > 0; i--) + { + stickermedalinfo.emblems[i] = stickermedalinfo.emblems[i-1]; + } + stickermedalinfo.emblems[0] = emblem; + stickermedalinfo.visiblecount++; + + if (!gamedata->collected[(emblem-emblemlocations)] || Playing()) + gonnadrawtime = true; + +bademblem: + emblem = M_GetLevelEmblems(-1); + } + + if (stickermedalinfo.visiblecount > 0) + { + if (emblem != NULL && emblem != stickermedalinfo.emblems[0]) + { + // Regenerate the entire array if this is unlocked + stickermedalinfo.regenemblem = emblem; + } + emblem = stickermedalinfo.emblems[0]; + + if (gonnadrawtime) + { + stickermedalinfo.timetoreach = emblem->var; + if (emblem->tag > 0) + { + if (emblem->tag > mapheaderinfo[map]->ghostCount + || mapheaderinfo[map]->ghostBrief[emblem->tag-1] == NULL) + goto bademblem; + + stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; + } + + snprintf(stickermedalinfo.targettext, 9, "%i'%02i\"%02i", + G_TicsToMinutes(stickermedalinfo.timetoreach, false), + G_TicsToSeconds(stickermedalinfo.timetoreach), + G_TicsToCentiseconds(stickermedalinfo.timetoreach)); + } + } +} + // // G_UpdateRecords // @@ -534,7 +607,14 @@ void G_UpdateRecords(void) // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems())) + { CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + if (stickermedalinfo.regenemblem != NULL + && gamedata->collected[(stickermedalinfo.regenemblem-emblemlocations)]) + { + G_UpdateTimeStickerMedals(gamemap-1); + } + } M_UpdateUnlockablesAndExtraEmblems(true); G_SaveGameData(); diff --git a/src/g_game.h b/src/g_game.h index c2f1c5830..1782a6b30 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -201,6 +201,18 @@ void G_UseContinue(void); void G_AfterIntermission(void); void G_EndGame(void); // moved from y_inter.c/h and renamed +#define MAXMEDALVISIBLECOUNT 3 +extern struct stickermedalinfo +{ + UINT8 visiblecount; + boolean canplaysound; + tic_t timetoreach; + emblem_t *emblems[MAXMEDALVISIBLECOUNT]; + emblem_t *regenemblem; + char targettext[9]; +} stickermedalinfo; + +void G_UpdateTimeStickerMedals(UINT16 map); void G_UpdateRecords(void); void G_Ticker(boolean run); diff --git a/src/k_hud.c b/src/k_hud.c index e44d8ddd6..d48730b12 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1466,14 +1466,11 @@ static void K_drawKartItem(void) } } -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) { // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 - static UINT8 prevmode = UINT8_MAX; - static emblem_t *maxemblem = NULL; - tic_t worktime; INT32 jitter = 0; @@ -1513,10 +1510,6 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI } } - if (mode != prevmode) - maxemblem = NULL; - prevmode = mode; - V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide)); TX += 33; @@ -1557,105 +1550,57 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI V_DrawKartString(TX+84, TY+3-jitter, splitflags, va("%d", worktime%10)); } - if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time! + // Medal data! + if ((modeattacking || (mode == 1)) + && !demo.playback + && stickermedalinfo.visiblecount > 0) { INT32 workx = TX + 96, worky = TY+18; - SINT8 curemb = 0; - patch_t *emblempic[3] = {NULL, NULL, NULL}; - UINT8 *emblemcol[3] = {NULL, NULL, NULL}; + UINT8 i = stickermedalinfo.visiblecount; - emblem_t *emblem = M_GetLevelEmblems(emblemmap); - - while (emblem) + if (stickermedalinfo.targettext[0] != '\0') { - char targettext[9]; - - emblem_t *nextemblem = M_GetLevelEmblems(-1); - - switch (emblem->type) + if (!mode) { - case ET_TIME: + if (stplyr->realtime > stickermedalinfo.timetoreach) + { + splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; + if (stickermedalinfo.canplaysound) { - static boolean canplaysound = true; - tic_t timetoreach = emblem->var; - - if (gamedata->collected[(emblem-emblemlocations)]) - { - emblempic[curemb] = W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE); - emblemcol[curemb] = R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE); - curemb++; - - if (emblem == maxemblem - && nextemblem != NULL - && nextemblem->type == emblem->type - && gamedata->collected[(nextemblem-emblemlocations)]) - maxemblem = NULL; - - if (emblem != maxemblem) - goto bademblem; - } - - maxemblem = emblem; - - if (emblem->tag > 0) - { - if (emblem->tag > mapheaderinfo[emblemmap-1]->ghostCount - || mapheaderinfo[emblemmap-1]->ghostBrief[emblem->tag-1] == NULL) - goto bademblem; - - timetoreach = mapheaderinfo[emblemmap-1]->ghostBrief[emblem->tag-1]->time; - } - - snprintf(targettext, 9, "%i'%02i\"%02i", - G_TicsToMinutes(timetoreach, false), - G_TicsToSeconds(timetoreach), - G_TicsToCentiseconds(timetoreach)); - - if (!mode) - { - if (stplyr->realtime > timetoreach) - { - splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; - if (canplaysound) - { - S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks - canplaysound = false; - } - } - else if (!canplaysound) - canplaysound = true; - } - - targettext[8] = 0; + S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks + stickermedalinfo.canplaysound = false; } - break; - default: - goto bademblem; + } } - workx -= V_ThinStringWidth(targettext, splitflags|V_6WIDTHSPACE); - V_DrawThinString(workx, worky, splitflags|V_6WIDTHSPACE, targettext); - - if (emblem != maxemblem || !gamedata->collected[(emblem-emblemlocations)]) - { - emblempic[curemb] = W_CachePatchName("NEEDIT", PU_CACHE); - curemb++; - } - - break; - -bademblem: - if (emblem == maxemblem || curemb == 3) - break; - emblem = nextemblem; + workx -= V_ThinStringWidth(stickermedalinfo.targettext, splitflags|V_6WIDTHSPACE); + V_DrawThinString(workx, worky, splitflags|V_6WIDTHSPACE, stickermedalinfo.targettext); } + workx -= (6 + (i*5)); + if (!mode) splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS; - while (curemb--) + while (i > 0) { - workx -= 11; - V_DrawSmallMappedPatch(workx, worky, splitflags, emblempic[curemb], emblemcol[curemb]); + i--; + + if (gamedata->collected[(stickermedalinfo.emblems[i]-emblemlocations)]) + { + V_DrawSmallMappedPatch(workx, worky, splitflags, + W_CachePatchName(M_GetEmblemPatch(stickermedalinfo.emblems[i], false), PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(stickermedalinfo.emblems[i]), GTC_CACHE) + ); + } + else + { + V_DrawSmallMappedPatch(workx, worky, splitflags, + W_CachePatchName("NEEDIT", PU_CACHE), + NULL + ); + } + + workx += 6; } } } @@ -5089,7 +5034,7 @@ void K_drawKartHUD(void) { // Draw the timestamp if (LUA_HudEnabled(hud_time)) - K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, 0); + K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, 0); islonesome = K_drawKartPositionFaces(); } diff --git a/src/k_hud.h b/src/k_hud.h index 7960c0aba..982cc76f5 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -40,7 +40,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny); void K_LoadKartHUDGraphics(void); void K_drawKartHUD(void); void K_drawKartFreePlay(void); -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode); void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); void K_DrawMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, UINT16 map, UINT8 *colormap); void K_DrawLikeMapThumbnail(INT32 x, INT32 y, INT32 width, UINT32 flags, patch_t *patch, UINT8 *colormap); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c64636abe..0963909b7 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2266,7 +2266,7 @@ void M_DrawTimeAttack(void) && (mapheaderinfo[map]->numlaps != 1)) { V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2); + K_drawKartTimestamp(laprec, 162+t, timeheight+6, 2); timeheight += 30; } else @@ -2275,7 +2275,7 @@ void M_DrawTimeAttack(void) } V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(timerec, 162+t, timeheight+6, map+1, 1); + K_drawKartTimestamp(timerec, 162+t, timeheight+6, 1); } else opty = 80; diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index 9443379f1..b64fd2715 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -178,6 +178,7 @@ void M_PrepareTimeAttack(INT32 choice) { (void) choice; + // Gametype guess if (levellist.guessgt != MAXGAMETYPES) { levellist.newgametype = levellist.guessgt; @@ -189,6 +190,10 @@ void M_PrepareTimeAttack(INT32 choice) } } + // Time-sticker Medals + G_UpdateTimeStickerMedals(levellist.choosemap); + + // Menu options { // see also p_setup.c's P_LoadRecordGhosts char *gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(levellist.choosemap+1))); From 9c95d2d975c67478fdb4ceae7e19e620ca1cfe84 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 18:02:21 +0000 Subject: [PATCH 28/37] G_UpdateTimeStickerMedals: Use a memset to initialise the struct, rather than relying on manual pick-outs --- src/g_game.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 709018aed..90b45a2f1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -497,11 +497,8 @@ void G_UpdateTimeStickerMedals(UINT16 map) emblem_t *emblem = M_GetLevelEmblems(map+1); boolean gonnadrawtime = false; - stickermedalinfo.visiblecount = 0; - stickermedalinfo.targettext[0] = '\0'; - stickermedalinfo.emblems[0] = stickermedalinfo.regenemblem = NULL; + memset(&stickermedalinfo, 0, sizeof(stickermedalinfo)); stickermedalinfo.timetoreach = UINT32_MAX; - stickermedalinfo.canplaysound = true; while (emblem != NULL) { From eb16f9d5a90b5e80e56a7fa05eaf095fff0626dc Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 18:17:39 +0000 Subject: [PATCH 29/37] G_TickTimeStickerMedals: Move the failed-record sound handling out of K_drawKartTimestamp --- src/g_game.c | 16 ++++++++++++++++ src/g_game.h | 3 ++- src/k_hud.c | 7 +------ src/p_tick.c | 3 +++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 90b45a2f1..e483d8c77 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -565,6 +565,22 @@ bademblem: } } +void G_TickTimeStickerMedals(void) +{ + if (players[consoleplayer].realtime > stickermedalinfo.timetoreach) + { + if (stickermedalinfo.norecord == false) + { + S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks + stickermedalinfo.norecord = true; + } + } + else + { + stickermedalinfo.norecord = false; + } +} + // // G_UpdateRecords // diff --git a/src/g_game.h b/src/g_game.h index 1782a6b30..648aab278 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -205,7 +205,7 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed extern struct stickermedalinfo { UINT8 visiblecount; - boolean canplaysound; + boolean norecord; tic_t timetoreach; emblem_t *emblems[MAXMEDALVISIBLECOUNT]; emblem_t *regenemblem; @@ -213,6 +213,7 @@ extern struct stickermedalinfo } stickermedalinfo; void G_UpdateTimeStickerMedals(UINT16 map); +void G_TickTimeStickerMedals(void); void G_UpdateRecords(void); void G_Ticker(boolean run); diff --git a/src/k_hud.c b/src/k_hud.c index d48730b12..3c7272725 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1562,14 +1562,9 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) { if (!mode) { - if (stplyr->realtime > stickermedalinfo.timetoreach) + if (stickermedalinfo.norecord == true) { splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; - if (stickermedalinfo.canplaysound) - { - S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks - stickermedalinfo.canplaysound = false; - } } } diff --git a/src/p_tick.c b/src/p_tick.c index b3576424d..d113a15f9 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -766,7 +766,10 @@ void P_Ticker(boolean run) } if (modeattacking) + { G_GhostTicker(); + G_TickTimeStickerMedals(); + } if (mapreset > 1 && --mapreset <= 1 From 55b7d2105107ac5f5eb28255a04707669b81b3f9 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 18:43:59 +0000 Subject: [PATCH 30/37] G_TickTimeStickerMedals, G_UpdateRecords, K_drawTimestamp: Jitter HUD on both Medal-earning success and general failure to reach desired time --- src/g_game.c | 7 +++++++ src/g_game.h | 1 + src/k_hud.c | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index e483d8c77..b6509688a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -567,12 +567,16 @@ bademblem: void G_TickTimeStickerMedals(void) { + if (stickermedalinfo.jitter) + stickermedalinfo.jitter--; + if (players[consoleplayer].realtime > stickermedalinfo.timetoreach) { if (stickermedalinfo.norecord == false) { S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks stickermedalinfo.norecord = true; + stickermedalinfo.jitter = 4; } } else @@ -622,11 +626,14 @@ void G_UpdateRecords(void) if ((earnedEmblems = M_CheckLevelEmblems())) { CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + if (stickermedalinfo.regenemblem != NULL && gamedata->collected[(stickermedalinfo.regenemblem-emblemlocations)]) { G_UpdateTimeStickerMedals(gamemap-1); } + + stickermedalinfo.jitter = 4*earnedEmblems; } M_UpdateUnlockablesAndExtraEmblems(true); diff --git a/src/g_game.h b/src/g_game.h index 648aab278..df8f0833a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -205,6 +205,7 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed extern struct stickermedalinfo { UINT8 visiblecount; + UINT8 jitter; boolean norecord; tic_t timetoreach; emblem_t *emblems[MAXMEDALVISIBLECOUNT]; diff --git a/src/k_hud.c b/src/k_hud.c index 3c7272725..86aee3c3e 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1562,6 +1562,15 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) { if (!mode) { + if (stickermedalinfo.jitter) + { + jitter = stickermedalinfo.jitter+3; + if (jitter & 2) + workx += jitter/4; + else + workx -= jitter/4; + } + if (stickermedalinfo.norecord == true) { splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF; From eab22e73a6a42715e77360c66a9d1c5cc4b62908 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 18:45:02 +0000 Subject: [PATCH 31/37] G_UpdateRecords: Play Medal-get sound on successful ET_TIME Medal get --- src/g_game.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_game.c b/src/g_game.c index b6509688a..67ef0fe27 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -634,6 +634,7 @@ void G_UpdateRecords(void) } stickermedalinfo.jitter = 4*earnedEmblems; + S_StartSound(NULL, sfx_ncitem); } M_UpdateUnlockablesAndExtraEmblems(true); From e7b63a5fad29a95cef4254180e78885ca7231372 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 19:17:07 +0000 Subject: [PATCH 32/37] G_UpdateTimeStickerMedals, M_StartTimeAttack: If you've beaten all game-provided times, show your personal best record on the in-level HUD instead. --- src/g_game.c | 22 +++++++++++++++------- src/g_game.h | 2 +- src/menus/play-local-race-time-attack.c | 4 +++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 67ef0fe27..960166b70 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -492,7 +492,7 @@ tic_t G_GetBestLap(INT16 map) struct stickermedalinfo stickermedalinfo; -void G_UpdateTimeStickerMedals(UINT16 map) +void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord) { emblem_t *emblem = M_GetLevelEmblems(map+1); boolean gonnadrawtime = false; @@ -556,13 +556,21 @@ bademblem: stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; } - - snprintf(stickermedalinfo.targettext, 9, "%i'%02i\"%02i", - G_TicsToMinutes(stickermedalinfo.timetoreach, false), - G_TicsToSeconds(stickermedalinfo.timetoreach), - G_TicsToCentiseconds(stickermedalinfo.timetoreach)); } } + + if (!gonnadrawtime && showownrecord) + { + stickermedalinfo.timetoreach = G_GetBestTime(map); + } + + if (stickermedalinfo.timetoreach != UINT32_MAX) + { + snprintf(stickermedalinfo.targettext, 9, "%i'%02i\"%02i", + G_TicsToMinutes(stickermedalinfo.timetoreach, false), + G_TicsToSeconds(stickermedalinfo.timetoreach), + G_TicsToCentiseconds(stickermedalinfo.timetoreach)); + } } void G_TickTimeStickerMedals(void) @@ -630,7 +638,7 @@ void G_UpdateRecords(void) if (stickermedalinfo.regenemblem != NULL && gamedata->collected[(stickermedalinfo.regenemblem-emblemlocations)]) { - G_UpdateTimeStickerMedals(gamemap-1); + G_UpdateTimeStickerMedals(gamemap-1, false); } stickermedalinfo.jitter = 4*earnedEmblems; diff --git a/src/g_game.h b/src/g_game.h index df8f0833a..856df5e13 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -213,7 +213,7 @@ extern struct stickermedalinfo char targettext[9]; } stickermedalinfo; -void G_UpdateTimeStickerMedals(UINT16 map); +void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord); void G_TickTimeStickerMedals(void); void G_UpdateRecords(void); diff --git a/src/menus/play-local-race-time-attack.c b/src/menus/play-local-race-time-attack.c index b64fd2715..054681792 100644 --- a/src/menus/play-local-race-time-attack.c +++ b/src/menus/play-local-race-time-attack.c @@ -191,7 +191,7 @@ void M_PrepareTimeAttack(INT32 choice) } // Time-sticker Medals - G_UpdateTimeStickerMedals(levellist.choosemap); + G_UpdateTimeStickerMedals(levellist.choosemap, false); // Menu options { @@ -468,4 +468,6 @@ void M_StartTimeAttack(INT32 choice) M_ClearMenus(true); D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_dummygpencore.value == 1), 1, 1, false, false); + + G_UpdateTimeStickerMedals(levellist.choosemap, true); } From d1c7a90a7c2773982a232bb854007dd827714089 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 19:25:23 +0000 Subject: [PATCH 33/37] G_UpdateTimeStickerMedals: Put an actual message on the sticker where an invalid medal ghost tag is handled Fixes a function reshuffling error that would have put control flow back in a loop with invalid properties --- src/g_game.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 960166b70..2687a5048 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -552,9 +552,11 @@ bademblem: { if (emblem->tag > mapheaderinfo[map]->ghostCount || mapheaderinfo[map]->ghostBrief[emblem->tag-1] == NULL) - goto bademblem; - - stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; + snprintf(stickermedalinfo.targettext, 9, "Invalid ghost tag"); + else if (mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time == UINT32_MAX) + snprintf(stickermedalinfo.targettext, 9, "Ghost DNF"); + else + stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; } } } From 1df3da837911a5277ea6f1232484be607573f9f8 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 19:26:18 +0000 Subject: [PATCH 34/37] G_TickTimeStickerMedals: Do not call in demo.playback --- src/p_tick.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index d113a15f9..7973f7972 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -768,7 +768,8 @@ void P_Ticker(boolean run) if (modeattacking) { G_GhostTicker(); - G_TickTimeStickerMedals(); + if (!demo.playback) + G_TickTimeStickerMedals(); } if (mapreset > 1 From 31dcb3346e3fa4c54f15b5358c0f6e071d52c20b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 5 Feb 2023 19:48:12 +0000 Subject: [PATCH 35/37] K_drawKartTimestamp: Still draw your best record even if the map has no ET_TIME medals --- src/k_hud.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 86aee3c3e..951c2456b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1552,8 +1552,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, UINT8 mode) // Medal data! if ((modeattacking || (mode == 1)) - && !demo.playback - && stickermedalinfo.visiblecount > 0) + && !demo.playback) { INT32 workx = TX + 96, worky = TY+18; UINT8 i = stickermedalinfo.visiblecount; From 75ee5d1c0b8b0cf2685f89749a158d16ea197979 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 6 Feb 2023 00:00:12 +0000 Subject: [PATCH 36/37] G_UpdateTimeStickerMedals: Fixes for issues with invalid ghost-Medal combinations. - Only set timetoreach from Medal's var in valid cases - Shorter invalid phrases to fit in 9-long buffer --- src/g_game.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 2687a5048..e614a360a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -547,17 +547,18 @@ bademblem: if (gonnadrawtime) { - stickermedalinfo.timetoreach = emblem->var; if (emblem->tag > 0) { if (emblem->tag > mapheaderinfo[map]->ghostCount || mapheaderinfo[map]->ghostBrief[emblem->tag-1] == NULL) - snprintf(stickermedalinfo.targettext, 9, "Invalid ghost tag"); + snprintf(stickermedalinfo.targettext, 9, "Invalid"); else if (mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time == UINT32_MAX) - snprintf(stickermedalinfo.targettext, 9, "Ghost DNF"); + snprintf(stickermedalinfo.targettext, 9, "DNF"); else stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time; } + else + stickermedalinfo.timetoreach = emblem->var; } } From dc5f6eb991bae1a72d8196afc4d3852b05e071d6 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 6 Feb 2023 22:38:32 +0000 Subject: [PATCH 37/37] G_UpdateRecords: Remove console print on RA Medal get as per textual request (UI now communicates this) --- src/g_game.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e614a360a..0e723c9dd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -636,8 +636,6 @@ void G_UpdateRecords(void) // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems())) { - CONS_Printf(M_GetText("\x82" "Earned %hu medal%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); - if (stickermedalinfo.regenemblem != NULL && gamedata->collected[(stickermedalinfo.regenemblem-emblemlocations)]) {