Better Save Menu: Ability to Reset to Spawn from anywhere (#6937)

Adds an option for a Better Save Menu that, after saving, allows you to effectively soft-reset the current save (either return to spawn or reset to the dungeon entrance), and additionally lets you reset to spawn specifcally, even if you are in a dungeon. This allows for escaping from the rare entrance-rando related softlock that can happen.
This commit is contained in:
Christopher Leggett
2026-07-19 13:01:50 -04:00
committed by GitHub
parent 29d4ff4205
commit 8cb0c74592
7 changed files with 349 additions and 91 deletions
@@ -1764,7 +1764,8 @@ void KaleidoScope_DrawPages(PlayState* play, GraphicsContext* gfxCtx) {
Gfx_SetupDL_42Opa(gfxCtx);
if ((pauseCtx->state == 7) || ((pauseCtx->state >= 8) && (pauseCtx->state < 0x12))) {
if ((GameInteractor_Should(VB_DRAW_SAVE_MENU, pauseCtx->state == 7, pauseCtx)) ||
((pauseCtx->state >= 8) && (pauseCtx->state < 0x12))) {
KaleidoScope_UpdatePrompt(play);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA, G_CC_MODULATEIA);
@@ -4397,20 +4398,61 @@ void KaleidoScope_Update(PlayState* play) {
break;
case 7:
switch (pauseCtx->unk_1EC) {
case 0:
pauseCtx->unk_204 -= 314.0f / WREG(6);
WREG(16) -= WREG(25) / WREG(6);
WREG(17) -= WREG(26) / WREG(6);
if (pauseCtx->unk_204 <= -628.0f) {
pauseCtx->unk_204 = -628.0f;
pauseCtx->unk_1EC = 1;
}
break;
if (GameInteractor_Should(VB_LOAD_SAVE_MENU, 1, play)) {
switch (pauseCtx->unk_1EC) {
case 0:
pauseCtx->unk_204 -= 314.0f / WREG(6);
WREG(16) -= WREG(25) / WREG(6);
WREG(17) -= WREG(26) / WREG(6);
if (pauseCtx->unk_204 <= -628.0f) {
pauseCtx->unk_204 = -628.0f;
pauseCtx->unk_1EC = 1;
}
break;
case 1:
if (CHECK_BTN_ALL(input->press.button, BTN_A)) {
if (pauseCtx->promptChoice != 0) {
case 1:
if (CHECK_BTN_ALL(input->press.button, BTN_A)) {
if (pauseCtx->promptChoice != 0) {
Interface_SetDoAction(play, DO_ACTION_NONE);
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] =
gSaveContext.buttonStatus[2] = gSaveContext.buttonStatus[3] = BTN_ENABLED;
gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] =
gSaveContext.buttonStatus[7] = gSaveContext.buttonStatus[8] = BTN_ENABLED;
gSaveContext.hudVisibilityMode = 0;
Interface_ChangeHudVisibilityMode(50);
pauseCtx->unk_1EC = 2;
WREG(2) = -6240;
YREG(8) = pauseCtx->unk_204;
func_800F64E0(0);
} else {
Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &gSfxDefaultPos, 4,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
Play_PerformSave(play);
pauseCtx->unk_1EC = 4;
D_8082B25C = CVarGetInteger(CVAR_ENHANCEMENT("SkipSaveConfirmation"), 0)
? 3 /* 0.1 sec */
: 90 /* 3 secs */;
}
} else if (CHECK_BTN_ALL(input->press.button, BTN_START) ||
CHECK_BTN_ALL(input->press.button, BTN_B)) {
Interface_SetDoAction(play, DO_ACTION_NONE);
pauseCtx->unk_1EC = 2;
WREG(2) = -6240;
YREG(8) = pauseCtx->unk_204;
func_800F64E0(0);
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
gSaveContext.buttonStatus[3] = BTN_ENABLED;
gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] =
gSaveContext.buttonStatus[8] = BTN_ENABLED;
gSaveContext.hudVisibilityMode = 0;
Interface_ChangeHudVisibilityMode(50);
}
break;
case 4:
if (CHECK_BTN_ALL(input->press.button, BTN_B) || CHECK_BTN_ALL(input->press.button, BTN_A) ||
CHECK_BTN_ALL(input->press.button, BTN_START) || (--D_8082B25C == 0)) {
Interface_SetDoAction(play, DO_ACTION_NONE);
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
gSaveContext.buttonStatus[3] = BTN_ENABLED;
@@ -4418,88 +4460,50 @@ void KaleidoScope_Update(PlayState* play) {
gSaveContext.buttonStatus[8] = BTN_ENABLED;
gSaveContext.hudVisibilityMode = 0;
Interface_ChangeHudVisibilityMode(50);
pauseCtx->unk_1EC = 2;
pauseCtx->unk_1EC = 5;
WREG(2) = -6240;
YREG(8) = pauseCtx->unk_204;
func_800F64E0(0);
}
break;
case 3:
case 6:
pauseCtx->unk_204 += 314.0f / WREG(6);
WREG(16) += WREG(25) / WREG(6);
WREG(17) += WREG(26) / WREG(6);
if (pauseCtx->unk_204 >= -314.0f) {
pauseCtx->state = 6;
pauseCtx->unk_1EC = 0;
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 = 0.0f;
pauseCtx->unk_204 = -314.0f;
}
break;
case 2:
case 5:
if (pauseCtx->unk_204 != (YREG(8) + 160.0f)) {
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 +=
160.0f / WREG(6);
pauseCtx->unk_204 += 160.0f / WREG(6);
pauseCtx->infoPanelOffsetY -= 40 / WREG(6);
WREG(16) -= WREG(25) / WREG(6);
WREG(17) -= WREG(26) / WREG(6);
XREG(5) -= 150 / WREG(6);
pauseCtx->alpha -= (u16)(255 / WREG(6));
if (pauseCtx->unk_204 == (YREG(8) + 160.0f)) {
pauseCtx->alpha = 0;
}
} else {
Audio_PlaySoundGeneral(NA_SE_SY_PIECE_OF_HEART, &gSfxDefaultPos, 4,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
Play_PerformSave(play);
pauseCtx->unk_1EC = 4;
D_8082B25C = CVarGetInteger(CVAR_ENHANCEMENT("SkipSaveConfirmation"), 0) ? 3 /* 0.1 sec */
: 90 /* 3 secs */;
pauseCtx->debugState = 0;
pauseCtx->state = 0x13;
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 = 160.0f;
pauseCtx->namedItem = PAUSE_ITEM_NONE;
pauseCtx->unk_1E4 = 0;
pauseCtx->unk_204 = -434.0f;
}
} else if (CHECK_BTN_ALL(input->press.button, BTN_START) ||
CHECK_BTN_ALL(input->press.button, BTN_B)) {
Interface_SetDoAction(play, DO_ACTION_NONE);
pauseCtx->unk_1EC = 2;
WREG(2) = -6240;
YREG(8) = pauseCtx->unk_204;
func_800F64E0(0);
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
gSaveContext.buttonStatus[3] = BTN_ENABLED;
gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] =
gSaveContext.buttonStatus[8] = BTN_ENABLED;
gSaveContext.hudVisibilityMode = 0;
Interface_ChangeHudVisibilityMode(50);
}
break;
case 4:
if (CHECK_BTN_ALL(input->press.button, BTN_B) || CHECK_BTN_ALL(input->press.button, BTN_A) ||
CHECK_BTN_ALL(input->press.button, BTN_START) || (--D_8082B25C == 0)) {
Interface_SetDoAction(play, DO_ACTION_NONE);
gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
gSaveContext.buttonStatus[3] = BTN_ENABLED;
gSaveContext.buttonStatus[5] = gSaveContext.buttonStatus[6] = gSaveContext.buttonStatus[7] =
gSaveContext.buttonStatus[8] = BTN_ENABLED;
gSaveContext.hudVisibilityMode = 0;
Interface_ChangeHudVisibilityMode(50);
pauseCtx->unk_1EC = 5;
WREG(2) = -6240;
YREG(8) = pauseCtx->unk_204;
func_800F64E0(0);
}
break;
case 3:
case 6:
pauseCtx->unk_204 += 314.0f / WREG(6);
WREG(16) += WREG(25) / WREG(6);
WREG(17) += WREG(26) / WREG(6);
if (pauseCtx->unk_204 >= -314.0f) {
pauseCtx->state = 6;
pauseCtx->unk_1EC = 0;
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 = 0.0f;
pauseCtx->unk_204 = -314.0f;
}
break;
case 2:
case 5:
if (pauseCtx->unk_204 != (YREG(8) + 160.0f)) {
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 +=
160.0f / WREG(6);
pauseCtx->unk_204 += 160.0f / WREG(6);
pauseCtx->infoPanelOffsetY -= 40 / WREG(6);
WREG(16) -= WREG(25) / WREG(6);
WREG(17) -= WREG(26) / WREG(6);
XREG(5) -= 150 / WREG(6);
pauseCtx->alpha -= (u16)(255 / WREG(6));
if (pauseCtx->unk_204 == (YREG(8) + 160.0f)) {
pauseCtx->alpha = 0;
}
} else {
pauseCtx->debugState = 0;
pauseCtx->state = 0x13;
pauseCtx->unk_1F4 = pauseCtx->unk_1F8 = pauseCtx->unk_1FC = pauseCtx->unk_200 = 160.0f;
pauseCtx->namedItem = PAUSE_ITEM_NONE;
pauseCtx->unk_1E4 = 0;
pauseCtx->unk_204 = -434.0f;
}
break;
break;
}
}
break;