From da6cf439d68bf9ab6a2e6bd4a527a9f62491edd1 Mon Sep 17 00:00:00 2001 From: Jordan Longstaff Date: Mon, 24 Nov 2025 13:48:56 -0500 Subject: [PATCH] Modularize equipment hand patch hooks (#5876) * Modularize equipment hand hooks * Remove unnecessary include * More efficient hammer hand hook * More efficient equipment visible hook * Add declarations of patching/resetting functions up front * Remove forward declarations * Make mod file self-contained --- soh/soh/Enhancements/Fixes/HammerHandFix.cpp | 38 ++++++++ .../Graphics/AgeDependentEquipment.cpp | 86 +++++++++++++++++++ soh/soh/Enhancements/mods.cpp | 71 --------------- soh/soh/Enhancements/mods.h | 1 - soh/soh/SohGui/SohMenuEnhancements.cpp | 2 - 5 files changed, 124 insertions(+), 74 deletions(-) create mode 100644 soh/soh/Enhancements/Fixes/HammerHandFix.cpp create mode 100644 soh/soh/Enhancements/Graphics/AgeDependentEquipment.cpp diff --git a/soh/soh/Enhancements/Fixes/HammerHandFix.cpp b/soh/soh/Enhancements/Fixes/HammerHandFix.cpp new file mode 100644 index 000000000..5cee8c30d --- /dev/null +++ b/soh/soh/Enhancements/Fixes/HammerHandFix.cpp @@ -0,0 +1,38 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "macros.h" +#include "soh/ResourceManagerHelpers.h" +#include "objects/object_link_boy/object_link_boy.h" +extern SaveContext gSaveContext; +} + +static constexpr int32_t CVAR_HAMMER_HAND_DEFAULT = 0; +#define CVAR_HAMMER_HAND_NAME CVAR_ENHANCEMENT("FixHammerHand") +#define CVAR_HAMMER_HAND_VALUE CVarGetInteger(CVAR_HAMMER_HAND_NAME, CVAR_HAMMER_HAND_DEFAULT) + +static void FixHammerHand() { + if (LINK_IS_ADULT) { + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1", 92, + gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2", 93, gsSPEndDisplayList()); + } +} + +static void ResetHammerHand() { + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2"); +} + +static void RegisterHammerHandFix() { + if (CVAR_HAMMER_HAND_VALUE) { + FixHammerHand(); + } else { + ResetHammerHand(); + } + + COND_HOOK(OnSceneInit, CVAR_HAMMER_HAND_VALUE, [](int32_t) { FixHammerHand(); }); +} + +static RegisterShipInitFunc initFunc(RegisterHammerHandFix, { CVAR_HAMMER_HAND_NAME }); diff --git a/soh/soh/Enhancements/Graphics/AgeDependentEquipment.cpp b/soh/soh/Enhancements/Graphics/AgeDependentEquipment.cpp new file mode 100644 index 000000000..e8b0d1270 --- /dev/null +++ b/soh/soh/Enhancements/Graphics/AgeDependentEquipment.cpp @@ -0,0 +1,86 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +#include "macros.h" +#include "soh/ResourceManagerHelpers.h" +#include "objects/object_link_boy/object_link_boy.h" +#include "objects/object_link_child/object_link_child.h" +extern SaveContext gSaveContext; +} + +static constexpr int32_t CVAR_AGE_EQUIPMENT_DEFAULT = 0; +#define CVAR_AGE_EQUIPMENT_NAME CVAR_ENHANCEMENT("EquipmentAlwaysVisible") +#define CVAR_AGE_EQUIPMENT_VALUE CVarGetInteger(CVAR_AGE_EQUIPMENT_NAME, CVAR_AGE_EQUIPMENT_DEFAULT) + +static void ResetAdultHands() { + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2"); + ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2"); + ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2"); + ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1"); + ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2"); +} + +static void ResetChildHands() { + ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword"); + ResourceMgr_UnpatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot"); + ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang"); + ResourceMgr_UnpatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield"); +} + +static void MakeEquipmentAlwaysVisible() { + if (LINK_IS_CHILD) { + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92, + gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2", 93, gsSPEndDisplayList()); + ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1", 84, + gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2", 85, + gsSPEndDisplayList()); + ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1", 51, + gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2", 52, gsSPEndDisplayList()); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1", 104, + gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2", 105, + gsSPEndDisplayList()); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1", 79, + gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2", 80, gsSPEndDisplayList()); + ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1", 76, + gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); + ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2", 77, + gsSPEndDisplayList()); + ResetChildHands(); + } else { + ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword", 13, + gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot", 13, + gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang", 50, + gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); + ResourceMgr_PatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield", 49, + gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL)); + ResetAdultHands(); + } +} + +static void RegisterAgeDependentEquipmentHook() { + if (CVAR_AGE_EQUIPMENT_VALUE) { + MakeEquipmentAlwaysVisible(); + } else { + ResetAdultHands(); + ResetChildHands(); + } + + COND_HOOK(OnSceneInit, CVAR_AGE_EQUIPMENT_VALUE, [](int32_t) { MakeEquipmentAlwaysVisible(); }); +} + +static RegisterShipInitFunc initFunc(RegisterAgeDependentEquipmentHook, { CVAR_AGE_EQUIPMENT_NAME }); diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index f4ad7ee47..205c35ae6 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -25,8 +25,6 @@ #include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h" #include "src/overlays/actors/ovl_Door_Gerudo/z_door_gerudo.h" #include "src/overlays/actors/ovl_En_Elf/z_en_elf.h" -#include "objects/object_link_boy/object_link_boy.h" -#include "objects/object_link_child/object_link_child.h" #include "soh_assets.h" #include "kaleido.h" @@ -228,74 +226,6 @@ void UpdateHyperEnemiesState() { } } -void UpdatePatchHand() { - if ((CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0)) && LINK_IS_CHILD) { - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1", 92, - gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2", 93, gsSPEndDisplayList()); - ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1", 84, - gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2", 85, - gsSPEndDisplayList()); - ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1", 51, - gsSPDisplayListOTRFilePath(gLinkChildRightHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2", 52, gsSPEndDisplayList()); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1", 104, - gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2", 105, - gsSPEndDisplayList()); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1", 79, - gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2", 80, gsSPEndDisplayList()); - ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1", 76, - gsSPDisplayListOTRFilePath(gLinkChildLeftFistNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2", 77, - gsSPEndDisplayList()); - - } else { - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "childHammer2"); - ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingHookshotNearDL, "childHookshot2"); - ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultRightHandHoldingBowNearDL, "childBow2"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingMasterSwordNearDL, "childMasterSword2"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingBgsNearDL, "childBiggoronSword2"); - ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultHandHoldingBrokenGiantsKnifeDL, "childBrokenGiantsKnife2"); - } - if ((CVarGetInteger(CVAR_ENHANCEMENT("EquipmentAlwaysVisible"), 0)) && LINK_IS_ADULT) { - ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword", 13, - gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot", 13, - gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang", 50, - gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield", 49, - gsSPDisplayListOTRFilePath(gLinkAdultRightHandClosedNearDL)); - } else { - ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndKokiriSwordNearDL, "adultKokiriSword"); - ResourceMgr_UnpatchGfxByName(gLinkChildRightHandHoldingSlingshotNearDL, "adultSlingshot"); - ResourceMgr_UnpatchGfxByName(gLinkChildLeftFistAndBoomerangNearDL, "adultBoomerang"); - ResourceMgr_UnpatchGfxByName(gLinkChildRightFistAndDekuShieldNearDL, "adultDekuShield"); - } - if (CVarGetInteger("gEnhancements.FixHammerHand", 0) && LINK_IS_ADULT) { - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1", 92, - gsSPDisplayListOTRFilePath(gLinkAdultLeftHandClosedNearDL)); - ResourceMgr_PatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2", 93, gsSPEndDisplayList()); - } else { - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand1"); - ResourceMgr_UnpatchGfxByName(gLinkAdultLeftHandHoldingHammerNearDL, "hammerHand2"); - } -} - -void RegisterPatchHandHandler() { - GameInteractor::Instance->RegisterGameHook( - [](int32_t sceneNum) { UpdatePatchHand(); }); -} - // this map is used for enemies that can be uniquely identified by their id // and that are always counted // enemies that can't be uniquely identified by their id @@ -549,6 +479,5 @@ void InitMods() { UpdateHyperEnemiesState(); RegisterEnemyDefeatCounts(); RegisterRandomizedEnemySizes(); - RegisterPatchHandHandler(); RandoKaleido_RegisterHooks(); } diff --git a/soh/soh/Enhancements/mods.h b/soh/soh/Enhancements/mods.h index 7ba012737..2aa9c63be 100644 --- a/soh/soh/Enhancements/mods.h +++ b/soh/soh/Enhancements/mods.h @@ -14,7 +14,6 @@ void UpdatePermanentHeartLossState(); void UpdateHyperEnemiesState(); void UpdateHyperBossesState(); void InitMods(); -void UpdatePatchHand(); void SwitchAge(); #ifdef __cplusplus diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index b528c6f45..bfbc9bab3 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -581,7 +581,6 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Show Age-Dependent Equipment", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("EquipmentAlwaysVisible")) .RaceDisable(false) - .Callback([](WidgetInfo& info) { UpdatePatchHand(); }) .Options(CheckboxOptions().Tooltip("Makes all equipment visible, regardless of age.")); AddWidget(path, "Scale Adult Equipment as Child", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("ScaleAdultEquipmentAsChild")) @@ -1074,7 +1073,6 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Fix Hand Holding Hammer", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("FixHammerHand")) .RaceDisable(false) - .Callback([](WidgetInfo& info) { UpdatePatchHand(); }) .Options(CheckboxOptions().Tooltip( "Fixes Adult Link having a backwards Left hand when holding the Megaton Hammer.")); AddWidget(path, "Fix Vanishing Paths", WIDGET_CVAR_COMBOBOX)