summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/port/Game.cpp67
-rw-r--r--src/port/Game.h1
-rw-r--r--src/port/ui/Menu.h44
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: