mirror of
https://github.com/HarbourMasters/SpaghettiKart
synced 2026-08-25 16:15:53 -04:00
Fix the reset button doing nothing or looping the start screen when pressed repeatedly (#719)
* Make the reset button reliable from any screen Pressing reset repeatedly near app start could do nothing, fade the music with no reset, or bounce the press-start screen back to itself. Three defects in the old handler: - It ran from the ImGui widget, racing the menu state machine; a press landing mid-fade was re-advanced by the in-flight transition (the press-start loop). - It always wrote gGamestateNext = MAIN_MENU_FROM_QUIT; once the game was already in that state a repeat write is swallowed by the != guard in main.c, so nothing happened. - CM_ResetAudio ran unconditionally, so the music faded even when the reset was swallowed. The widget now only sets an atomic request flag; ApplyPendingReset (top of push_frame, on the game loop) performs the reset. It alternates between the two identical FROM_QUIT gamestates so every press trips the gamestate switch, and re-enters the menus through the intro's own transition protocol (FADE_MODE_LOGO -> setup_menus rebuild + fresh fade-in), which replaces any in-flight transition. Audio only fades when a reset actually executes. The dead gSkipIntro switch in the old handler (an unconditional override below it always won) is gone; behavior is unchanged: reset lands on the logo intro, or the start menu in debug mode. Play-verified: hammering reset during the splash screens restarts the logo every press; reset mid-fade after press-start no longer loops back; resets from the main menu and mid-race work as before. * Honor gSkipIntro when picking the post-reset screen Review feedback on #719: restore the gSkipIntro switch from the old handler instead of hard-coding the logo intro, keeping the debug-mode override on top (no else), matching the boot-time logic in main(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+4
-40
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user