diff options
| -rw-r--r-- | src/port/Game.cpp | 67 | ||||
| -rw-r--r-- | src/port/Game.h | 1 | ||||
| -rw-r--r-- | src/port/ui/Menu.h | 44 |
3 files changed, 72 insertions, 40 deletions
diff --git a/src/port/Game.cpp b/src/port/Game.cpp index 8ccd382e6..1c6d49af9 100644 --- a/src/port/Game.cpp +++ b/src/port/Game.cpp @@ -6,6 +6,7 @@ #include <fast/Fast3dWindow.h> #include <memory> +#include <atomic> #include "engine/World.h" #include "engine/AllTracks.h" @@ -911,7 +912,73 @@ void CM_ResetAudio(void) { } } +static std::atomic<bool> sResetRequested{ false }; + +void CM_RequestReset(void) { + sResetRequested.store(true); +} + +// The reset widget only requests; the reset is applied here at the top of the +// game frame. Applying it from the widget raced the menu state machine: a +// press landing mid-fade was re-advanced by the in-flight transition, and a +// repeat press rewrote the gamestate it had already set, which the != guard +// in main.c swallows while the audio fade still runs (silent no-op). +static void ApplyPendingReset() { + if (!sResetRequested.exchange(false)) { + return; + } + + // The FROM_QUIT gamestates run identical inits; alternating keeps + // gGamestateNext != gGamestate true so every press re-enters the menus. + gGamestateNext = (gGamestate == MAIN_MENU_FROM_QUIT) ? START_MENU_FROM_QUIT : MAIN_MENU_FROM_QUIT; + gIsGamePaused = 0; + // Reset credits + D_800DC5E4 = 0; + gTourComplete = false; + SetMarioRaceway(); + memset(&gGameModeMenuColumn, 0, sizeof(s8) * NUM_ROWS_GAME_MODE_MENU); + memset(&gGameModeSubMenuColumn, 0, sizeof(s8) * NUM_COLUMN_GAME_MODE_SUB_MENU * NUM_ROWS_GAME_MODE_SUB_MENU); + + CM_ResetAudio(); + + // Close the editor. + if (gEditor.IsEnabled()) { + gEditor.Disable(); + } + + // Set the debug menu track browsing index back to zero + TrackBrowser::Instance->Reset(); + + // Land on the same screen the gSkipIntro setting picks at boot. + switch (CVarGetInteger("gSkipIntro", 0)) { + case 0: + gMenuSelection = HARBOUR_MASTERS_MENU; + break; + case 1: + gMenuSelection = LOGO_INTRO_MENU; + break; + case 2: + gMenuSelection = START_MENU; + break; + case 3: + gMenuSelection = MAIN_MENU; + break; + } + + // Debug mode override gSkipIntro + if (CVarGetInteger("gEnableDebugMode", 0) == true) { + gMenuSelection = START_MENU; + } + // Re-enter through the intro's own transition protocol (see HM_TickIntro): + // FADE_MODE_LOGO makes setup_menus rebuild the menu items and start a + // fresh fade-in, replacing any in-flight transition that would otherwise + // advance the stale screen right after the reset. + gMenuFadeType = 0; + gFadeModeSelection = FADE_MODE_LOGO; +} + void push_frame() { + ApplyPendingReset(); GameEngine::StartAudioFrame(); GameEngine::Instance->StartFrame(); thread5_iteration(); diff --git a/src/port/Game.h b/src/port/Game.h index 63ad92a4b..edd1902d8 100644 --- a/src/port/Game.h +++ b/src/port/Game.h @@ -35,6 +35,7 @@ extern Registry<ActorInfo, const SpawnParams&> gActorRegistry; extern Registry<ItemInfo> gItemRegistry; extern DataRegistry<RandomItemTable> gItemTableRegistry; World* GetWorld(void); // Retrieve the world instance +void CM_RequestReset(void); // Queue a game reset; applied at the top of the next game frame #endif // NOLINTBEGIN(readability-identifier-naming) diff --git a/src/port/ui/Menu.h b/src/port/ui/Menu.h index f3b2fd3dd..7e84e5d26 100644 --- a/src/port/ui/Menu.h +++ b/src/port/ui/Menu.h @@ -62,46 +62,10 @@ class Menu : public GuiWindow { "Searches all menus for the given text, including tooltips.")) } } } }; virtual void ProcessReset() { - gGamestateNext = MAIN_MENU_FROM_QUIT; - gIsGamePaused = 0; - // Reset credits - D_800DC5E4 = 0; - gTourComplete = false; - SetMarioRaceway(); - memset(&gGameModeMenuColumn, 0, sizeof(s8) * NUM_ROWS_GAME_MODE_MENU); - memset(&gGameModeSubMenuColumn, 0, sizeof(s8) * NUM_COLUMN_GAME_MODE_SUB_MENU * NUM_ROWS_GAME_MODE_SUB_MENU); - - CM_ResetAudio(); - - switch(CVarGetInteger("gSkipIntro", 0)) { - case 0: - gMenuSelection = HARBOUR_MASTERS_MENU; - break; - case 1: - gMenuSelection = LOGO_INTRO_MENU; - break; - case 2: - gMenuSelection = START_MENU; - break; - case 3: - gMenuSelection = MAIN_MENU; - break; - } - - // Close the editor. - if (gEditor.IsEnabled()) { - gEditor.Disable(); - } - - // Set the debug menu track browsing index back to zero - TrackBrowser::Instance->Reset(); - - // Debug mode override gSkipIntro - if (CVarGetInteger("gEnableDebugMode", 0) == true) { - gMenuSelection = START_MENU; - } else { - gMenuSelection = LOGO_INTRO_MENU; - } + // Only request the reset: it is applied at the top of the next game + // frame (ApplyPendingReset in Game.cpp), where it cannot race the menu + // state machine mid-fade or be swallowed as a repeated gamestate write. + CM_RequestReset(); } private: |
