diff --git a/include/d/actor/d_a_obj_bosswarp.h b/include/d/actor/d_a_obj_bosswarp.h index 9b62f1a0f6..71b5b2b58f 100644 --- a/include/d/actor/d_a_obj_bosswarp.h +++ b/include/d/actor/d_a_obj_bosswarp.h @@ -60,7 +60,7 @@ public: bool isFirst() { return fopAcM_GetParamBit(this, 0x1b, 1); } void setAction(u8 action) { mAction = action; } -private: +// private: /* 0x568 */ request_of_phase_process_class mPhaseReq; /* 0x570 */ J3DModel* mpModel; /* 0x574 */ mDoExt_btkAnm* mpBtkAnm[2]; diff --git a/mods/randomizer/src/hooks.cpp b/mods/randomizer/src/hooks.cpp index f24f4ce932..ccfe4d98c0 100644 --- a/mods/randomizer/src/hooks.cpp +++ b/mods/randomizer/src/hooks.cpp @@ -22,6 +22,7 @@ #include "d/actor/d_a_tag_kmsg.h" #include "d/actor/d_a_npc_fairy.h" #include "d/actor/d_a_obj_master_sword.h" +#include "d/actor/d_a_obj_bosswarp.h" #include "d/actor/d_a_obj_swBallC.h" #include "d/actor/d_a_npc_shad.h" #include "d/actor/d_a_tbox2.h" @@ -29,6 +30,7 @@ #include "d/actor/d_a_npc_ykm.h" #include "d/actor/d_a_npc_ykw.h" #include "d/actor/d_a_npc_zrz.h" +#include "d/actor/d_a_demo_item.h" #include "d/d_door_param2.h" #include "d/d_file_sel_info.h" #include "d/d_file_select.h" @@ -142,6 +144,10 @@ DEFINE_HOOK(&dGameover_c::_create, dGameover_c___create); DEFINE_HOOK(&daObjSwBallC_c::Create, daObjSwBallC_c__Create); DEFINE_HOOK(&daObjSwBallC_c::actionWait, daObjSwBallC_c__actionWait); +DEFINE_HOOK_SYMBOL("daDitem_Execute", int(daDitem_c*), daDitem_c__execute); + +DEFINE_HOOK(&daObjBossWarp_c::demoProc, daObjBossWarp_c__demoProc); + namespace randomizer::ui { dialogSelectModeState g_dialogSelectModeState = SelectReady; } @@ -2270,6 +2276,125 @@ HookAction hookPreSwBallActionWait(ModContext*, void* args, void*, void*) { return HOOK_SKIP_ORIGINAL; } +void hookPostDitemExecute(ModContext*, void* args, void* retval, void*) { + auto* i_this = mods::arg(args, 0); + + // Certain items use field models that are too big to fit in link's hands so we want to scale them down to fit. + switch (i_this->m_itemNo) { + case dItemNo_Randomizer_MIRROR_PIECE_1_e: + case dItemNo_Randomizer_MIRROR_PIECE_2_e: + case dItemNo_Randomizer_MIRROR_PIECE_3_e: + case dItemNo_Randomizer_MIRROR_PIECE_4_e: + { + i_this->scale.x = 0.05f; + break; + } + case dItemNo_Randomizer_MASTER_SWORD_e: + case dItemNo_Randomizer_LIGHT_SWORD_e: + { + i_this->scale.x = 0.001f; + break; + } + } +} + +// pretty ugly way of handling this, but oh well. basically, we reconstruct the actionTable +// and use it to check that we're in the correct action before proceeding. then store info +// about what level we're on, and use it in the post-hook to undo the flag that's normally set. +daObjBossWarp_c* hookBossWarpDemoProc_patchActor = nullptr; +int hookBossWarpDemoProc_nowLevel = -1; +HookAction hookPreBossWarpDemoProc(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + + hookBossWarpDemoProc_patchActor = nullptr; + hookBossWarpDemoProc_nowLevel = -1; + + static const char* const actionTable[15] = { + "WAIT", + "APPEAR", + "DISAPPEAR", + "SCENE_CHG", + "STONE_FALL", + "STONE_MIDNA", + "WALK_TARGET1", + "APPEAR_END", + "STONE_DELETE", + "STONE_PUTAWAY", + "WCHECK", + "SETPOS", + "SCALING", + "STONE_SCALE", + "HEART_MOVE", + }; + + bool isRewardAction = + dComIfGp_evmng_getIsAddvance(i_this->mStaffId) + && dComIfGp_evmng_getMyActIdx(i_this->mStaffId, actionTable, 15, 0, 0) == 4; + if (!isRewardAction) { + return HOOK_CONTINUE; + } + + // this was a static function in the original TU, so reconstructing it for use here + auto getNowLevel = []() { + static const char* const stages[9] = { + "D_MN05A", + "D_MN04A", + "D_MN01A", + "D_MN10A", + "D_MN11A", + "D_MN06A", + "D_MN07A", + "D_MN08A", + "D_MN01A", + }; + + for (int i = 0; i < 9; i++) { + if (std::strcmp(dComIfGp_getStartStageName(), stages[i]) == 0) { + return i; + } + } + + return -1; + }; + + hookBossWarpDemoProc_patchActor = i_this; + hookBossWarpDemoProc_nowLevel = getNowLevel(); + return HOOK_CONTINUE; +} + +void hookPostBossWarpDemoProc(ModContext*, void* args, void*, void*) { + auto* i_this = mods::arg(args, 0); + if (hookBossWarpDemoProc_patchActor != i_this) { + return; + } + + int level = hookBossWarpDemoProc_nowLevel; + hookBossWarpDemoProc_patchActor = nullptr; + hookBossWarpDemoProc_nowLevel = -1; + + // undo the flag that was set in the original function + switch (level) { + case 0: + dComIfGs_offCollectCrystal(0); + break; + case 1: + dComIfGs_offCollectCrystal(1); + break; + case 2: + dComIfGs_offCollectCrystal(2); + break; + case 4: + dComIfGs_offCollectMirror(1); + break; + case 5: + dComIfGs_offCollectMirror(2); + break; + case 6: + dComIfGs_offCollectMirror(3); + break; + } +} + } ModResult initialize() { @@ -2388,6 +2513,11 @@ ModResult initialize() { ADD_HOOK_POST(daObjSwBallC_c__Create, hookPostSwBallCreate); ADD_HOOK_PRE(daObjSwBallC_c__actionWait, hookPreSwBallActionWait); + ADD_HOOK_POST(daDitem_c__execute, hookPostDitemExecute); + + ADD_HOOK_PRE(daObjBossWarp_c__demoProc, hookPreBossWarpDemoProc); + ADD_HOOK_POST(daObjBossWarp_c__demoProc, hookPostBossWarpDemoProc); + return MOD_OK; } @@ -2486,6 +2616,10 @@ ModResult uninstall() { mods::hook::uninstall(svc_hook); mods::hook::uninstall(svc_hook); + mods::hook::uninstall(svc_hook); + + mods::hook::uninstall(svc_hook); + return MOD_OK; } }