diff --git a/soh/soh/Enhancements/AlwaysOnFixes.cpp b/soh/soh/Enhancements/AlwaysOnFixes.cpp index 16feeaf75c..6b1eec2c95 100644 --- a/soh/soh/Enhancements/AlwaysOnFixes.cpp +++ b/soh/soh/Enhancements/AlwaysOnFixes.cpp @@ -3,6 +3,9 @@ #include "soh/ShipInit.hpp" extern "C" { +#include "macros.h" +#include "functions.h" +#include "variables.h" extern void Player_UseItem(PlayState*, Player*, s32); extern PlayState* gPlayState; } @@ -20,6 +23,17 @@ void RegisterFixOutsideTotCrash() { }); } +// Vanilla bug: `Actor_Item_Shield` (dropped Deku Shield when burning) assumes that segment 12 +// contains Link display list `gCullBackDList`. If an actor is drawn between player and shield +// that uses segment 12 (such as Jabu-Jabu tentacles), the game will crash on Deku Shield drop. +// Fix: Re-set segment 12 to the required display list. +void RegisterFixDekuShieldDropCrash() { + COND_VB_SHOULD(VB_ITEMSHIELD_DRAW, true, { + GraphicsContext* __gfxCtx = gPlayState->state.gfxCtx; + gSPSegment(POLY_OPA_DISP++, 0x0C, (uintptr_t)SEGMENTED_TO_VIRTUAL(gCullBackDList)); + }); +} + // Vanilla bug: If Hookshot doesn't spawn, player is softlocked. (eg. use as child, no memory left) // Fix: Change item to none if no spawn. (Ranged weapon state is removed by `Player_InitItemAction`) void RegisterPreventHookshotNoSpawnSoftlock() { @@ -45,5 +59,6 @@ void RegisterPreventHookshotParentSoftlock() { } static RegisterShipInitFunc initFuncFixOutsideTotCrash(RegisterFixOutsideTotCrash, { "" }); +static RegisterShipInitFunc initFuncFixDekuShieldDropCrash(RegisterFixDekuShieldDropCrash, { "" }); static RegisterShipInitFunc initFuncHookshotNospawnSoftlock(RegisterPreventHookshotNoSpawnSoftlock, { "" }); static RegisterShipInitFunc initFuncHookshotParentSoftlock(RegisterPreventHookshotParentSoftlock, { "" }); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 96f8bb8528..d6624b9c75 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -3066,6 +3066,14 @@ typedef enum { // - `*EnItem00` VB_ITEM00_KILL, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - none + VB_ITEMSHIELD_DRAW, + // #### `result` // ```c // true diff --git a/soh/src/overlays/actors/ovl_Item_Shield/z_item_shield.c b/soh/src/overlays/actors/ovl_Item_Shield/z_item_shield.c index 2f17865bc1..4242cc0dea 100644 --- a/soh/src/overlays/actors/ovl_Item_Shield/z_item_shield.c +++ b/soh/src/overlays/actors/ovl_Item_Shield/z_item_shield.c @@ -7,6 +7,8 @@ #include "vt.h" #include "z_item_shield.h" #include "objects/object_link_child/object_link_child.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #define FLAGS ACTOR_FLAG_UPDATE_CULLING_DISABLED @@ -221,6 +223,7 @@ void ItemShield_Draw(Actor* thisx, PlayState* play) { if (!(this->unk_19C & 2)) { OPEN_DISPS(play->state.gfxCtx); Gfx_SetupDL_25Opa(play->state.gfxCtx); + GameInteractor_Should(VB_ITEMSHIELD_DRAW, true); gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); gSPDisplayList(POLY_OPA_DISP++, SEGMENTED_TO_VIRTUAL(gLinkChildDekuShieldDL)); CLOSE_DISPS(play->state.gfxCtx);