From b0c7c309e8bd042811c41595e7d5d8ff2bb3771e Mon Sep 17 00:00:00 2001 From: HylianFreddy <82058772+HylianFreddy@users.noreply.github.com> Date: Sat, 22 Oct 2022 11:43:35 +0200 Subject: [PATCH] Generalize grotto return fix (#578) --- code/include/z3D/z3D.h | 3 +++ code/oot.ld | 8 ++++++-- code/oot_e.ld | 8 ++++++-- code/src/actors/player.c | 2 ++ code/src/grotto.c | 32 +++++++++++++++++++++++++------- code/src/grotto.h | 2 +- code/src/hooks.s | 15 +++++++++++++-- code/src/main.c | 2 -- code/src/patches.s | 17 ++++++++++++----- 9 files changed, 68 insertions(+), 21 deletions(-) diff --git a/code/include/z3D/z3D.h b/code/include/z3D/z3D.h index adcf3a4e..c1e811b5 100644 --- a/code/include/z3D/z3D.h +++ b/code/include/z3D/z3D.h @@ -9,6 +9,9 @@ // #include "hid.h" +#define TRUE 1 +#define FALSE 0 + typedef struct { /* 0x00 */ u8 buttonItems[5]; //B,Y,X,I,II /* 0x05 */ u8 buttonSlots[4]; //Y,X,I,II diff --git a/code/oot.ld b/code/oot.ld index 60658dee..228fb506 100644 --- a/code/oot.ld +++ b/code/oot.ld @@ -1348,6 +1348,10 @@ SECTIONS *(.patch_WarpSongEntranceOverride) } + .patch_SetFWPlayerParams 0x4911B8 : { + *(.patch_SetFWPlayerParams) + } + .patch_SwapFaroresWind 0x49186C : { *(.patch_SwapFaroresWind) } @@ -1376,8 +1380,8 @@ SECTIONS *(.patch_SendDroppedBottleContents) } - .patch_ReturnFWSetupGrottoInfo 0x496B88 : { - *(.patch_ReturnFWSetupGrottoInfo) + .patch_ReturnFW 0x496B88 : { + *(.patch_ReturnFW) } .patch_SetSpecialVoidOutRespawnFlag 0x496C70 : { diff --git a/code/oot_e.ld b/code/oot_e.ld index a0ab8a63..db2926c2 100644 --- a/code/oot_e.ld +++ b/code/oot_e.ld @@ -1348,6 +1348,10 @@ SECTIONS *(.patch_WarpSongEntranceOverride) } + .patch_SetFWPlayerParams 0x4911D8 : { + *(.patch_SetFWPlayerParams) + } + .patch_SwapFaroresWind 0x49188C : { *(.patch_SwapFaroresWind) } @@ -1376,8 +1380,8 @@ SECTIONS *(.patch_SendDroppedBottleContents) } - .patch_ReturnFWSetupGrottoInfo 0x496BA8 : { - *(.patch_ReturnFWSetupGrottoInfo) + .patch_ReturnFW 0x496BA8 : { + *(.patch_ReturnFW) } .patch_SetSpecialVoidOutRespawnFlag 0x496C90 : { diff --git a/code/src/actors/player.c b/code/src/actors/player.c index f6491521..7fe3c012 100644 --- a/code/src/actors/player.c +++ b/code/src/actors/player.c @@ -7,6 +7,7 @@ #include "fairy.h" #include "icetrap.h" #include "arrow.h" +#include "grotto.h" #define PlayerActor_Init_addr 0x191844 #define PlayerActor_Init ((ActorFunc)PlayerActor_Init_addr) @@ -69,6 +70,7 @@ void PlayerActor_rInit(Actor* thisx, GlobalContext* globalCtx) { gSaveContext.equips.equipment &= ~0xF0; // unequip shield } + Grotto_SanitizeEntranceType(); // If the player has started with 0 hearts, some entrances that knock Link down will cause a Game Over. // When respawning after the Game Over, change the entrance type to avoid softlocks. u8 playerEntranceType = (thisx->params & 0xF00) >> 8; diff --git a/code/src/grotto.c b/code/src/grotto.c index 0d69b08c..81dc6e5d 100644 --- a/code/src/grotto.c +++ b/code/src/grotto.c @@ -2,7 +2,6 @@ #include "grotto.h" #include "savefile.h" #include "settings.h" -#include "common.h" // Information necessary for entering each grotto static const GrottoLoadInfo grottoLoadTable[NUM_GROTTOS] = { @@ -82,6 +81,7 @@ static s16 grottoExitList[NUM_GROTTOS] = {0}; static s16 grottoLoadList[NUM_GROTTOS] = {0}; static s8 grottoId = 0xFF; static s8 lastEntranceType = NOT_GROTTO; +static u8 overridingNextEntrance = FALSE; // Initialize both lists so that each index refers to itself. An index referring // to itself means that the entrance is not shuffled. Indices will be overwritten @@ -179,6 +179,7 @@ s16 Grotto_CheckSpecialEntrance(s16 nextEntranceIndex) { lastEntranceType = NOT_GROTTO; } + overridingNextEntrance = TRUE; return nextEntranceIndex; } @@ -242,21 +243,38 @@ void Grotto_ForceRegularVoidOut(void) { } } +// If setting FW at a grotto exit, save different player params in the FW data, so +// we can remember to restore the lastEntranceType when returning to the warp point. +s32 Grotto_ChooseFWPlayerParams() { + if ((gSettingsContext.shuffleGrottoEntrances == ON || gSettingsContext.shuffleOverworldSpawns == ON || gSettingsContext.shuffleWarpSongs == ON) && + lastEntranceType == GROTTO_RETURN) { + + return 0x4FF; + } + return 0x6FF; // Normal FW params +} + // If returning to a FW point saved at a grotto exit, copy the FW data to the Grotto Return Point // so that Sun's Song and Game Over will behave correctly void Grotto_SetupReturnInfoOnFWReturn(void) { - if (gSettingsContext.shuffleGrottoEntrances == ON || gSettingsContext.shuffleOverworldSpawns == ON || gSettingsContext.shuffleWarpSongs == ON) { + if ((gSettingsContext.shuffleGrottoEntrances == ON || gSettingsContext.shuffleOverworldSpawns == ON || gSettingsContext.shuffleWarpSongs == ON) && + gSaveContext.fw.playerParams == 0x4FF) { + + gSaveContext.fw.playerParams = gSaveContext.respawn[RESPAWN_MODE_TOP].playerParams = 0x6FF; gSaveContext.respawn[RESPAWN_MODE_RETURN] = gSaveContext.respawn[RESPAWN_MODE_TOP]; gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams = 0x0DFF; lastEntranceType = GROTTO_RETURN; + } else { + lastEntranceType = NOT_GROTTO; } } -void Grotto_SanitizeEntranceType(void) { - // Clear entrance type when on the title screen or after being thrown out - // by the Hyrule Castle guards if the last entrance was HC Storms Grotto -> HC - // This allows OHKO playthroughs to get past the guards properly. - if (!IsInGame() || gSaveContext.entranceIndex == 0x47E) { +// If a scene transition is not overridden at all (i.e. guards throwing Link out / quitting game) +// the lastEntranceType must be cleared to avoid messing up savewarps and deathwarps. +// This does not apply to void out and other respawns, which should keep the lastEntranceType. +void Grotto_SanitizeEntranceType() { + if (!overridingNextEntrance && gSaveContext.respawnFlag == 0) { lastEntranceType = NOT_GROTTO; } + overridingNextEntrance = FALSE; } diff --git a/code/src/grotto.h b/code/src/grotto.h index 661727be..1d149f89 100644 --- a/code/src/grotto.h +++ b/code/src/grotto.h @@ -28,6 +28,6 @@ void Grotto_SetExitOverride(s16 originalIndex, s16 overrideIndex); void Grotto_SetLoadOverride(s16 originalIndex, s16 overrideIndex); s16 Grotto_CheckSpecialEntrance(s16 nextEntranceIndex); void Grotto_ForceGrottoReturnOnSpecialEntrance(void); -void Grotto_SanitizeEntranceType(); +void Grotto_SanitizeEntranceType(void); #endif //_GROTTO_H_ diff --git a/code/src/hooks.s b/code/src/hooks.s index 3ddfbd32..16f9700a 100644 --- a/code/src/hooks.s +++ b/code/src/hooks.s @@ -1258,8 +1258,8 @@ hook_OverrideGrottoActorEntrance: pop {r0-r12, lr} b 0x3F22C4 -.global hook_ReturnFWSetupGrottoInfo -hook_ReturnFWSetupGrottoInfo: +.global hook_ReturnFW +hook_ReturnFW: push {r0-r12, lr} bl Grotto_SetupReturnInfoOnFWReturn pop {r0-r12, lr} @@ -1708,6 +1708,17 @@ hook_GanonDrawMasterSword: strb r10,[r4,#0x0] @ delete MS effect bx lr +.global hook_SetFWPlayerParams +hook_SetFWPlayerParams: + push {r0-r9,r11-r12,lr} + bl Grotto_ChooseFWPlayerParams + mov r10,r0 + pop {r0-r9,r11-r12,lr} + bx lr + +@ ---------------------------------- +@ ---------------------------------- + .section .loader .global hook_into_loader hook_into_loader: diff --git a/code/src/main.c b/code/src/main.c index 4bc8e9b0..9299dca4 100644 --- a/code/src/main.c +++ b/code/src/main.c @@ -43,8 +43,6 @@ void before_GlobalContext_Update(GlobalContext* globalCtx) { Settings_SkipSongReplays(); - Grotto_SanitizeEntranceType(); - Multiplayer_Run(); } diff --git a/code/src/patches.s b/code/src/patches.s index f902009e..d90f1fd3 100644 --- a/code/src/patches.s +++ b/code/src/patches.s @@ -1636,10 +1636,10 @@ SceneExitDynamicOverride_patch: OverrideGrottoActorEntrance_patch: b hook_OverrideGrottoActorEntrance -.section .patch_ReturnFWSetupGrottoInfo -.global ReturnFWSetupGrottoInfo_patch -ReturnFWSetupGrottoInfo_patch: - bl hook_ReturnFWSetupGrottoInfo +.section .patch_ReturnFW +.global ReturnFW_patch +ReturnFW_patch: + bl hook_ReturnFW .section .patch_WarpSongEntranceOverride .global WarpSongEntranceOverride_patch @@ -1981,8 +1981,15 @@ CollisionATvsAC_patch: GanonDrawMasterSword_patch: bl hook_GanonDrawMasterSword +.section .patch_SetFWPlayerParams +.global SetFWPlayerParams_patch +SetFWPlayerParams_patch: + bl hook_SetFWPlayerParams + +@ ---------------------------------- +@ ---------------------------------- + .section .patch_loader .global loader_patch - loader_patch: b hook_into_loader