From e8523b69f0646038541e8bab23d178601b670487 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 1 Mar 2024 23:22:28 +0000 Subject: [PATCH 1/2] Sealed Star re-ordering (resolves #606) - If emerald not yet collected on that cup, pick the first uncollected emerald, then get the cup's CUPCACHE_SPECIAL with that ID to pick the stage - Already collected emeralds retain their swappage across gamedata saves - Returns to normal order if you get all 7 OR Special Mode is unlocked (chao key? debug? password in modded games? sky's the limit) - Pops up a Message from the Stars telling you the gems have been returned to their natural place - Add-ons will always use their dedicated sealed star, since it's unordered material If it weren't so last minute I could have a better solution for GP Backups, but right now what I've gone for is it always trusts whatever G_GPCupIntoRoundQueue does AS LONG AS THE COURSE ISN'T THE ONE YOU'RE RELOADING INTO. If it IS, then it checks to see if it's exactly what's been saved, and complains (with the generic error message, unfortunately) if it isn't. --- src/g_game.c | 69 +++++++++++++++++++++++++++---- src/g_gamedata.cpp | 42 ++++++++++++++++++- src/g_gamedata.h | 15 ++++++- src/k_menu.h | 4 ++ src/k_menudraw.c | 76 +++++++++++++++++++++++++++++------ src/k_menufunc.c | 34 ++++++++++++++++ src/k_podium.cpp | 75 +++++++++++++++++++++++++++------- src/m_cheat.c | 2 + src/m_cond.c | 3 ++ src/m_cond.h | 7 +++- src/menus/extras-challenges.c | 17 ++++++-- src/p_saveg.c | 8 ++++ src/p_user.c | 24 ++++++++++- 13 files changed, 333 insertions(+), 43 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index aa60e5b1d..5c889ccc3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3932,15 +3932,68 @@ void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencor // At the end of the Cup is a Rank-restricted treat. // So we append it to the end of the roundqueue. // (as long as it exists, of course!) - cupLevelNum = cup->cachedlevels[CUPCACHE_SPECIAL]; - if (cupLevelNum < nummapheaders) { - G_MapIntoRoundQueue( - cupLevelNum, - G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel), - setencore, // if this isn't correct, Got_Mapcmd will fix it - true // Rank-restricted! - ); + // Of course, this last minute game design tweak + // has to make things a little complicated. We + // basically just make sure they're dispensed + // at the intended difficulty sequence until + // you've got them all, at which point they + // become their intended order permanently. + // ~toast 010324 + cupheader_t *emeraldcup = NULL; + + if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found + || cup->id >= basenumkartcupheaders // custom content + || M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order + { + // Standard order. + emeraldcup = cup; + } + else + { + // Determine order from sealedswaps. + for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++) + { + if (gamedata->sealedswaps[i] != grandprixinfo.cup) + continue; + + // Repeat visit, grab the same ID. + break; + } + + // If there's pending stars, get them from the associated cup order. + if (i < GDMAX_SEALEDSWAPS) + { + emeraldcup = kartcupheaders; + while (emeraldcup) + { + if (emeraldcup->id >= basenumkartcupheaders) + { + emeraldcup = NULL; + break; + } + + if (emeraldcup->emeraldnum == i+1) + break; + + emeraldcup = emeraldcup->next; + } + } + } + + if (emeraldcup) + { + cupLevelNum = emeraldcup->cachedlevels[CUPCACHE_SPECIAL]; + if (cupLevelNum < nummapheaders) + { + G_MapIntoRoundQueue( + cupLevelNum, + G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel), + setencore, // if this isn't correct, Got_Mapcmd will fix it + true // Rank-restricted! + ); + } + } } if (roundqueue.size == 0) diff --git a/src/g_gamedata.cpp b/src/g_gamedata.cpp index 105f997ad..d522ce7ab 100644 --- a/src/g_gamedata.cpp +++ b/src/g_gamedata.cpp @@ -64,6 +64,7 @@ void srb2::save_ng_gamedata() ng.milestones.majorkeyskipattempted = gamedata->majorkeyskipattempted; ng.milestones.finishedtutorialchallenge = gamedata->finishedtutorialchallenge; ng.milestones.enteredtutorialchallenge = gamedata->enteredtutorialchallenge; + ng.milestones.sealedswapalerted = gamedata->sealedswapalerted; ng.milestones.gonerlevel = gamedata->gonerlevel; ng.prisons.thisprisoneggpickup = gamedata->thisprisoneggpickup; ng.prisons.prisoneggstothispickup = gamedata->prisoneggstothispickup; @@ -176,7 +177,7 @@ void srb2::save_ng_gamedata() } for (auto cup = kartcupheaders; cup; cup = cup->next) { - if (cup->windata[0].best_placement == 0) + if (cup->windata[0].best_placement == 0 && cup->windata[1].got_emerald == false) { continue; } @@ -229,6 +230,17 @@ void srb2::save_ng_gamedata() ng.cups[cupdata.name] = std::move(cupdata); } + for (int i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++) + { + srb2::GamedataSealedSwapJson sealedswap {}; + + cupheader_t* cup = gamedata->sealedswaps[i]; + + sealedswap.name = std::string(cup->name); + + ng.sealedswaps.emplace_back(std::move(sealedswap)); + } + std::string gamedataname_s {gamedatafilename}; fs::path savepath {fmt::format("{}/{}", srb2home, gamedataname_s)}; fs::path tmpsavepath {fmt::format("{}/{}.tmp", srb2home, gamedataname_s)}; @@ -418,6 +430,7 @@ void srb2::load_ng_gamedata() gamedata->majorkeyskipattempted = js.milestones.majorkeyskipattempted; gamedata->finishedtutorialchallenge = js.milestones.finishedtutorialchallenge; gamedata->enteredtutorialchallenge = js.milestones.enteredtutorialchallenge; + gamedata->sealedswapalerted = js.milestones.sealedswapalerted; gamedata->gonerlevel = js.milestones.gonerlevel; gamedata->thisprisoneggpickup = js.prisons.thisprisoneggpickup; gamedata->prisoneggstothispickup = js.prisons.prisoneggstothispickup; @@ -720,6 +733,33 @@ void srb2::load_ng_gamedata() } } + size_t sealedswaps_size = js.sealedswaps.size(); + for (size_t i = 0; i < std::min((size_t)GDMAX_SEALEDSWAPS, sealedswaps_size); i++) + { + cupheader_t* cup = nullptr; + + // Find BASE cups only + for (cup = kartcupheaders; cup; cup = cup->next) + { + if (cup->id >= basenumkartcupheaders) + { + cup = NULL; + break; + } + + std::string cupname = std::string(cup->name); + if (cupname == js.sealedswaps[i].name) + { + break; + } + } + + if (cup) + { + gamedata->sealedswaps[i] = cup; + } + } + M_FinaliseGameData(); } diff --git a/src/g_gamedata.h b/src/g_gamedata.h index d476f2e46..f479da427 100644 --- a/src/g_gamedata.h +++ b/src/g_gamedata.h @@ -70,6 +70,7 @@ struct GamedataMilestonesJson final bool majorkeyskipattempted; bool finishedtutorialchallenge; bool enteredtutorialchallenge; + bool sealedswapalerted; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( GamedataMilestonesJson, @@ -81,7 +82,8 @@ struct GamedataMilestonesJson final chaokeytutorial, majorkeyskipattempted, finishedtutorialchallenge, - enteredtutorialchallenge + enteredtutorialchallenge, + sealedswapalerted ) }; @@ -184,6 +186,13 @@ struct GamedataCupJson final NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataCupJson, name, records) }; +struct GamedataSealedSwapJson final +{ + std::string name; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSealedSwapJson, name) +}; + struct GamedataJson final { GamedataPlaytimeJson playtime; @@ -203,6 +212,7 @@ struct GamedataJson final std::unordered_map maps; std::vector spraycans; std::unordered_map cups; + std::vector sealedswaps; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT( GamedataJson, @@ -222,7 +232,8 @@ struct GamedataJson final skins, maps, spraycans, - cups + cups, + sealedswaps ) }; diff --git a/src/k_menu.h b/src/k_menu.h index d84d97414..049559ce4 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -680,6 +680,8 @@ void M_Init(void); void M_PlayMenuJam(void); +boolean M_ConsiderSealedSwapAlert(void); + void M_OpenVirtualKeyboard(boolean gamepad); void M_MenuTypingInput(INT32 key); @@ -1347,6 +1349,8 @@ extern struct challengesmenu_s { boolean chaokeyadd, keywasadded; UINT8 chaokeyhold; + boolean considersealedswapalert; + boolean requestflip; UINT16 unlockcount[CMC_MAX]; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index bb9205fe2..0929e714e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2823,6 +2823,57 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi rankx += 19 - (rankw / 2); cupwindata_t *windata = &(cup->windata[difficulty]); + UINT8 emeraldnum = UINT8_MAX; + + if (!noemerald) + { + if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found + || cup->id >= basenumkartcupheaders // custom content + || M_SecretUnlocked(SECRET_SPECIALATTACK, true)) // true order + { + // Standard order. + if (windata->got_emerald == true) + { + emeraldnum = cup->emeraldnum; + } + } + else + { + // Determine order from sealedswaps. + UINT8 i; + for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++) + { + if (gamedata->sealedswaps[i] != cup) + continue; + + break; + } + + // If there's pending stars, get them from the associated cup order. + if (i < GDMAX_SEALEDSWAPS) + { + cupheader_t *emeraldcup = kartcupheaders; + while (emeraldcup) + { + if (emeraldcup->id >= basenumkartcupheaders) + { + emeraldcup = NULL; + break; + } + + if (emeraldcup->emeraldnum == i+1) + { + if (emeraldcup->windata[difficulty].got_emerald == true) + emeraldnum = i+1; + break; + } + + emeraldcup = emeraldcup->next; + } + } + } + } + if (windata->best_placement == 0) { if (statsmode) @@ -2832,14 +2883,13 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi 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; + else + { + rankx += 14 + 1; + } + + goto windataemeraldmaybe; } UINT8 *colormap = NULL; @@ -2934,13 +2984,15 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi if (charPat) V_DrawFixedPatch((rankx)*FRACUNIT, (ranky)*FRACUNIT, FRACUNIT, 0, charPat, colormap); +windataemeraldmaybe: + rankx += 12 + 1; if (noemerald) ; - else if (windata->got_emerald == true) + else if (emeraldnum != UINT8_MAX) { - if (cup->emeraldnum == 0) + if (emeraldnum == 0) V_DrawCharacter(rankx+2, ranky+2, '+', false); else { @@ -2948,14 +3000,14 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi if (!flash) { - UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (cup->emeraldnum-1) % 7; + UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (emeraldnum-1) % 7; colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE); } const char *emname = va( "%sMAP%c", - (cup->emeraldnum > 7) ? "SUP" : "EME", + (emeraldnum > 7) ? "SUP" : "EME", colormap ? '\0' : 'B' ); @@ -3116,7 +3168,7 @@ void M_DrawCupSelect(void) y += 44; //(8 + 100) - (20 + 44) } - if (windata && windata->best_placement != 0) + if (windata) { M_DrawCupWinData( x, diff --git a/src/k_menufunc.c b/src/k_menufunc.c index efb78969d..7833da1e3 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -560,6 +560,35 @@ void M_PlayMenuJam(void) #undef IsCurrentlyPlaying +boolean M_ConsiderSealedSwapAlert(void) +{ + if (gamedata->sealedswapalerted == true) + return false; + + if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found + || M_SecretUnlocked(SECRET_SPECIALATTACK, true)) // true order + { + gamedata->sealedswapalerted = true; + + // Don't make a message if no Sealed Stars have yet been found. + if (gamedata->everseenspecial == false) + return false; + + M_StartMessage( + "Message from the Stars", + "As if called by fate, the Emeralds you've\n" + "collected return to their rightful places...\n" + "\n" + "The Sealed Stars are now ordered via Cups!\n", + NULL, MM_NOTHING, NULL, NULL + ); + + return true; + } + + return false; +} + void M_ValidateRestoreMenu(void) { if (restoreMenu == NULL || restoreMenu == &MAIN_GonerDef) @@ -629,6 +658,11 @@ menu_t *M_SpecificMenuRestore(menu_t *torestore) M_SetupPlayMenu(-1); PLAY_CharSelectDef.prevMenu = &MainDef; + if (torestore != &MISC_ChallengesDef) + { + M_ConsiderSealedSwapAlert(); + } + return torestore; } diff --git a/src/k_podium.cpp b/src/k_podium.cpp index 103640d02..30e863298 100644 --- a/src/k_podium.cpp +++ b/src/k_podium.cpp @@ -83,6 +83,7 @@ static struct podiumData_s sfxenum_t gradeVoice; cupheader_t *cup; + UINT8 emeraldnum; boolean fastForward; @@ -102,6 +103,7 @@ void podiumData_s::Init(void) { rank = grandprixinfo.rank; cup = grandprixinfo.cup; + emeraldnum = cup->emeraldnum; } else { @@ -119,6 +121,7 @@ void podiumData_s::Init(void) cup = cup->next; } + emeraldnum = 0; memset(&rank, 0, sizeof(gpRank_t)); rank.skin = players[consoleplayer].skin; @@ -628,12 +631,7 @@ void podiumData_s::Draw(void) case GPEVENT_SPECIAL: { srb2::Draw drawer_emerald = drawer_gametype; - UINT8 emeraldNum = 0; - - if (cup != nullptr) - { - emeraldNum = cup->emeraldnum; - } + UINT8 emeraldNum = g_podiumData.emeraldnum; boolean useWhiteFrame = ((leveltime & 1) || !dta->gotSpecialPrize); patch_t *emeraldPatch = nullptr; @@ -844,12 +842,7 @@ void podiumData_s::Draw(void) if (rank.specialWon == true) { - UINT8 emeraldNum = 0; - - if (cup != nullptr) - { - emeraldNum = cup->emeraldnum; - } + UINT8 emeraldNum = g_podiumData.emeraldnum; const boolean emeraldBlink = (leveltime & 1); patch_t *emeraldOverlay = nullptr; @@ -1263,6 +1256,60 @@ void K_ResetCeremony(void) return; } + cupheader_t *emeraldcup = NULL; + + if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found + || grandprixinfo.cup->id >= basenumkartcupheaders // custom content + || M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order + { + // Standard order. + emeraldcup = grandprixinfo.cup; + } + else + { + // Determine order from sealedswaps. + for (i = 0; i < GDMAX_SEALEDSWAPS; i++) + { + if (gamedata->sealedswaps[i] == NULL) + { + if (g_podiumData.rank.specialWon == true) + { + // First visit! Mark it off. + gamedata->sealedswaps[i] = grandprixinfo.cup; + } + + break; + } + + if (gamedata->sealedswaps[i] != grandprixinfo.cup) + continue; + + // Repeat visit, grab the same ID. + break; + } + + // If there's pending stars, apply them to the new cup order. + if (i < GDMAX_SEALEDSWAPS) + { + emeraldcup = kartcupheaders; + while (emeraldcup) + { + if (emeraldcup->id >= basenumkartcupheaders) + { + emeraldcup = NULL; + break; + } + + if (emeraldcup->emeraldnum == i+1) + break; + + emeraldcup = emeraldcup->next; + } + + g_podiumData.emeraldnum = i+1; + } + } + // Write grade, position, and emerald-having-ness for later sessions! i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed; @@ -1292,9 +1339,9 @@ void K_ResetCeremony(void) anymerit = true; } - if (g_podiumData.rank.specialWon == true) + if (g_podiumData.rank.specialWon == true && emeraldcup) { - grandprixinfo.cup->windata[i].got_emerald = true; + emeraldcup->windata[i].got_emerald = true; anymerit = true; } diff --git a/src/m_cheat.c b/src/m_cheat.c index 779d6b526..7a0f1e063 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -96,6 +96,7 @@ static UINT8 cheatf_warp(void) if (success) { gamedata->gonerlevel = GDGONER_DONE; + gamedata->sealedswapalerted = true; G_SetUsedCheats(); } @@ -231,6 +232,7 @@ static UINT8 cheatf_devmode(void) } gamedata->gonerlevel = GDGONER_DONE; + gamedata->sealedswapalerted = true; M_ClearMenus(true); diff --git a/src/m_cond.c b/src/m_cond.c index 345641454..4e35471ed 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -666,6 +666,7 @@ void M_ClearStats(void) gamedata->majorkeyskipattempted = false; gamedata->enteredtutorialchallenge = false; gamedata->finishedtutorialchallenge = false; + gamedata->sealedswapalerted = false; gamedata->musicstate = GDMUSIC_NONE; gamedata->importprofilewins = false; @@ -720,6 +721,8 @@ void M_ClearSecrets(void) skincolors[i].cache_spraycan = UINT16_MAX; } + memset(gamedata->sealedswaps, 0, sizeof(gamedata->sealedswaps)); + Z_Free(gamedata->challengegrid); gamedata->challengegrid = NULL; gamedata->challengegridwidth = 0; diff --git a/src/m_cond.h b/src/m_cond.h index 393d046c5..210a09767 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -291,6 +291,7 @@ typedef enum { // This is the largest number of 9s that will fit in UINT32 and UINT16 respectively. #define GDMAX_RINGS 999999999 #define GDMAX_CHAOKEYS 9999 +#define GDMAX_SEALEDSWAPS 7 #define GDCONVERT_ROUNDSTOKEY 14 @@ -371,12 +372,15 @@ struct gamedata_t UINT32 totalrings; UINT32 totaltumbletime; - // Chao Key condition bypass + // CHAO KEYS AND THEIR GENERATION UINT32 pendingkeyrounds; UINT8 pendingkeyroundoffset; UINT16 keyspending; UINT16 chaokeys; + // EMERALD REMAPPING + cupheader_t *sealedswaps[GDMAX_SEALEDSWAPS]; + // SPECIFIC SPECIAL EVENTS boolean everloadedaddon; boolean everfinishedcredits; @@ -387,6 +391,7 @@ struct gamedata_t boolean majorkeyskipattempted; boolean enteredtutorialchallenge; boolean finishedtutorialchallenge; + boolean sealedswapalerted; gdmusic_t musicstate; UINT8 gonerlevel; diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 6fe8ac330..e1df3066b 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -335,6 +335,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu) challengesmenu.requestnew = false; challengesmenu.chaokeyadd = false; challengesmenu.keywasadded = false; + challengesmenu.considersealedswapalert = false; challengesmenu.chaokeyhold = 0; challengesmenu.currentunlock = MAXUNLOCKABLES; challengesmenu.unlockcondition = NULL; @@ -668,10 +669,15 @@ void M_ChallengesTick(void) if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim == UNLOCKTIME) { + unlockable_t *ref = &unlockables[challengesmenu.currentunlock]; + // Unlock animation... also tied directly to the actual unlock! gamedata->unlocked[challengesmenu.currentunlock] = true; M_UpdateUnlockablesAndExtraEmblems(true, true); + if (ref->type == SECRET_SPECIALATTACK) + challengesmenu.considersealedswapalert = true; + // Update shown description just in case..? if (challengesmenu.unlockcondition) Z_Free(challengesmenu.unlockcondition); @@ -682,12 +688,10 @@ void M_ChallengesTick(void) if (challengesmenu.extradata) { - unlockable_t *ref; UINT16 bombcolor; M_UpdateChallengeGridExtraData(challengesmenu.extradata); - ref = &unlockables[challengesmenu.currentunlock]; bombcolor = SKINCOLOR_NONE; if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) @@ -747,7 +751,14 @@ void M_ChallengesTick(void) // Play music the moment control returns. M_PlayMenuJam(); - if (gamedata->chaokeytutorial == false + if (challengesmenu.considersealedswapalert == true + && M_ConsiderSealedSwapAlert() == true) + { + // No keygen tutorial in this case... + // not ideal but at least unlikely to + // get at same time?? :V + } + else if (gamedata->chaokeytutorial == false && challengesmenu.keywasadded == true) { M_ChallengesTutorial(CCTUTORIAL_KEYGEN); diff --git a/src/p_saveg.c b/src/p_saveg.c index e516d809c..8d3b51da8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -6280,6 +6280,14 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save) { UINT32 val = READUINT32(save->p); + if (roundqueue.entries[i].rankrestricted && roundqueue.position != i+1) + { + // If this is a Sealed Star that hasn't yet been + // reached, don't be picky about divergance. Just + // use the base game without question. ~toast 010324 + continue; + } + mapnum = roundqueue.entries[i].mapnum; if (mapnum < nummapheaders && mapheaderinfo[mapnum] != NULL) { diff --git a/src/p_user.c b/src/p_user.c index 815551626..7adfa49ea 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -296,9 +296,29 @@ UINT8 P_GetNextEmerald(void) { cupheader_t *cup = NULL; - if (grandprixinfo.gp == true) + if (grandprixinfo.gp == true && grandprixinfo.cup) { - cup = grandprixinfo.cup; + if (gamedata->sealedswaps[GDMAX_SEALEDSWAPS-1] != NULL // all found + || grandprixinfo.cup->id >= basenumkartcupheaders // custom content + || M_SecretUnlocked(SECRET_SPECIALATTACK, false)) // true order + { + cup = grandprixinfo.cup; + } + else + { + // Determine order from sealedswaps. + UINT8 i; + for (i = 0; (i < GDMAX_SEALEDSWAPS && gamedata->sealedswaps[i]); i++) + { + if (gamedata->sealedswaps[i] != grandprixinfo.cup) + continue; + + // Repeat visit, grab the same ID. + break; + } + + return i+1; + } } if (cup == NULL) From 616d2bb87a51c6cfb594b693dd8cfeb87f4b2a48 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 3 Mar 2024 00:22:22 +0000 Subject: [PATCH 2/2] Menu Messages only animate when menuwipe is stopped Reduces the amount of moving parts we have to worry about. Fire M_StartMessage at the same time you change a menu without worry! --- src/menus/transient/message-box.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/menus/transient/message-box.c b/src/menus/transient/message-box.c index 72bc50731..ad901ef11 100644 --- a/src/menus/transient/message-box.c +++ b/src/menus/transient/message-box.c @@ -116,6 +116,9 @@ void M_StopMessage(INT32 choice) boolean M_MenuMessageTick(void) { + if (menuwipe) + return false; + if (menumessage.closing) { if (menumessage.closing > MENUMESSAGECLOSE)