From db4bc12b7619fc8560b05e3b4e9454e62ca551c4 Mon Sep 17 00:00:00 2001 From: nclok1405 <155463060+nclok1405@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:45:13 +0900 Subject: [PATCH 1/4] "Targetable Gold Skulltula" Cheat --- soh/soh/Enhancements/Cheats/GSTargetable.cpp | 35 ++++++++++++++++++++ soh/soh/SohGui/SohMenuEnhancements.cpp | 4 +++ 2 files changed, 39 insertions(+) create mode 100644 soh/soh/Enhancements/Cheats/GSTargetable.cpp diff --git a/soh/soh/Enhancements/Cheats/GSTargetable.cpp b/soh/soh/Enhancements/Cheats/GSTargetable.cpp new file mode 100644 index 00000000000..4015a87dc9f --- /dev/null +++ b/soh/soh/Enhancements/Cheats/GSTargetable.cpp @@ -0,0 +1,35 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include + +extern "C" { +#include "functions.h" +#include "macros.h" +#include "src/overlays/actors/ovl_En_Sw/z_en_sw.h" + +extern PlayState* gPlayState; +} + +static constexpr int32_t CVAR_GSTARGETABLE_DEFAULT = 0; +#define CVAR_GSTARGETABLE_NAME CVAR_CHEAT("GSTargetable") +#define CVAR_GSTARGETABLE_VALUE CVarGetInteger(CVAR_GSTARGETABLE_NAME, CVAR_GSTARGETABLE_DEFAULT) + +static void OnInitGSTargetable(void* refActor) { + EnSw* enSw = reinterpret_cast(refActor); + + if (enSw->actor.naviEnemyId == 0x20) { + // Enable Targeting this Gold Skulltula + enSw->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; + + // By default Gold Skulltulas are categorized as NPCs (blue cursor) which feels wrong. + // Change the category to Misc (green cursor) instead. + // It might be possible to change the category to Enemy but doing so will likely affect Clear Rooms. + Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, &enSw->actor, ACTORCAT_MISC); + } +} + +static void RegisterGSTargetable() { + COND_ID_HOOK(OnActorInit, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnInitGSTargetable); +} + +static RegisterShipInitFunc initFunc(RegisterGSTargetable, { CVAR_GSTARGETABLE_NAME }); diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index c32b1175587..b2d9dd69209 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1724,6 +1724,10 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Disable Haunted Wasteland Sandstorm", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("DisableSandstorm")) .Options(CheckboxOptions().Tooltip("Disables sandstorm effect in Haunted Wasteland.")); + AddWidget(path, "Targetable Gold Skulltula", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("GSTargetable")) + .Options( + CheckboxOptions().Tooltip("Allows Z-Targeting Gold Skulltulas. Requires a scene reload to take effect.")); AddWidget(path, "Glitch Aids", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Easy Frame Advancing with Pause", WIDGET_CVAR_CHECKBOX) From e2b326d79c6519ae390c4a32d71feae284fdad6d Mon Sep 17 00:00:00 2001 From: nclok1405 <155463060+nclok1405@users.noreply.github.com> Date: Tue, 25 Nov 2025 23:23:10 +0900 Subject: [PATCH 2/4] Disable Targeting immediately when the Gold Skulltula is defeated (like regular Skullwalltulas) --- soh/soh/Enhancements/Cheats/GSTargetable.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/Cheats/GSTargetable.cpp b/soh/soh/Enhancements/Cheats/GSTargetable.cpp index 4015a87dc9f..e15f4ea7376 100644 --- a/soh/soh/Enhancements/Cheats/GSTargetable.cpp +++ b/soh/soh/Enhancements/Cheats/GSTargetable.cpp @@ -1,6 +1,5 @@ #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/ShipInit.hpp" -#include extern "C" { #include "functions.h" @@ -28,8 +27,18 @@ static void OnInitGSTargetable(void* refActor) { } } +static void OnEnemyDefeatGSTargetable(void* refActor) { + EnSw* enSw = reinterpret_cast(refActor); + + if (enSw->actor.naviEnemyId == 0x20) { + // Disable Targeting immediately when the Gold Skulltula is defeated (like regular Skullwalltulas) + enSw->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; + } +} + static void RegisterGSTargetable() { COND_ID_HOOK(OnActorInit, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnInitGSTargetable); + COND_ID_HOOK(OnEnemyDefeat, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnEnemyDefeatGSTargetable); } static RegisterShipInitFunc initFunc(RegisterGSTargetable, { CVAR_GSTARGETABLE_NAME }); From ecf5d3b8045288469b34f0ec142610a7861cd189 Mon Sep 17 00:00:00 2001 From: nclok1405 <155463060+nclok1405@users.noreply.github.com> Date: Fri, 28 Nov 2025 14:16:02 +0900 Subject: [PATCH 3/4] Added realtime toggle --- soh/soh/Enhancements/Cheats/GSTargetable.cpp | 57 ++++++++++++++++++++ soh/soh/SohGui/SohMenuEnhancements.cpp | 3 +- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/Cheats/GSTargetable.cpp b/soh/soh/Enhancements/Cheats/GSTargetable.cpp index e15f4ea7376..4185906fbd7 100644 --- a/soh/soh/Enhancements/Cheats/GSTargetable.cpp +++ b/soh/soh/Enhancements/Cheats/GSTargetable.cpp @@ -1,5 +1,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/ShipInit.hpp" +#include +#include extern "C" { #include "functions.h" @@ -36,7 +38,62 @@ static void OnEnemyDefeatGSTargetable(void* refActor) { } } +static void UpdateGSTargetable() { + if (gPlayState != nullptr) { + if (CVAR_GSTARGETABLE_VALUE) { + SPDLOG_DEBUG("GSTargetable has been toggled on"); + + // Find all Gold Skulltulas that are in NPC category + std::vector goldSkulltulasInNPCCategory; + + Actor* actorNPC = gPlayState->actorCtx.actorLists[ACTORCAT_NPC].head; + while (actorNPC != nullptr) { + if ((actorNPC->id == ACTOR_EN_SW) && (actorNPC->naviEnemyId == 0x20)) { + goldSkulltulasInNPCCategory.push_back(actorNPC); + } + actorNPC = actorNPC->next; + } + + // Move all NPC Gold Skulltulas to Misc category + for (auto& actor : goldSkulltulasInNPCCategory) { + Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_MISC); + } + + // Make all Gold Skulltulas in Misc category targetable + Actor* actorMisc = gPlayState->actorCtx.actorLists[ACTORCAT_MISC].head; + while (actorMisc != nullptr) { + if ((actorMisc->id == ACTOR_EN_SW) && (actorMisc->naviEnemyId == 0x20)) { + actorMisc->flags |= ACTOR_FLAG_ATTENTION_ENABLED; + } + actorMisc = actorMisc->next; + } + } else { + SPDLOG_DEBUG("GSTargetable has been toggled off"); + + // Make all Gold Skulltulas in NPC category not targetable + Actor* actorNPC = gPlayState->actorCtx.actorLists[ACTORCAT_NPC].head; + while (actorNPC != nullptr) { + if ((actorNPC->id == ACTOR_EN_SW) && (actorNPC->naviEnemyId == 0x20)) { + actorNPC->flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; + } + actorNPC = actorNPC->next; + } + + // Make all Gold Skulltulas in Misc category not targetable + Actor* actorMisc = gPlayState->actorCtx.actorLists[ACTORCAT_MISC].head; + while (actorMisc != nullptr) { + if ((actorMisc->id == ACTOR_EN_SW) && (actorMisc->naviEnemyId == 0x20)) { + actorMisc->flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; + } + actorMisc = actorMisc->next; + } + } + } +} + static void RegisterGSTargetable() { + UpdateGSTargetable(); + COND_ID_HOOK(OnActorInit, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnInitGSTargetable); COND_ID_HOOK(OnEnemyDefeat, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnEnemyDefeatGSTargetable); } diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index b2d9dd69209..84c010f2824 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1726,8 +1726,7 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip("Disables sandstorm effect in Haunted Wasteland.")); AddWidget(path, "Targetable Gold Skulltula", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_CHEAT("GSTargetable")) - .Options( - CheckboxOptions().Tooltip("Allows Z-Targeting Gold Skulltulas. Requires a scene reload to take effect.")); + .Options(CheckboxOptions().Tooltip("Allows Z-Targeting Gold Skulltulas.")); AddWidget(path, "Glitch Aids", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Easy Frame Advancing with Pause", WIDGET_CVAR_CHECKBOX) From 83c04eb7936d5649410b983be9d75aca9b0b468f Mon Sep 17 00:00:00 2001 From: nclok1405 <155463060+nclok1405@users.noreply.github.com> Date: Mon, 29 Dec 2025 00:34:16 +0900 Subject: [PATCH 4/4] Correctly handle Night GS Spawning/Despawning (do not allow targeting before they become visible) --- soh/soh/Enhancements/Cheats/GSTargetable.cpp | 33 ++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/soh/soh/Enhancements/Cheats/GSTargetable.cpp b/soh/soh/Enhancements/Cheats/GSTargetable.cpp index 4185906fbd7..60911a06eac 100644 --- a/soh/soh/Enhancements/Cheats/GSTargetable.cpp +++ b/soh/soh/Enhancements/Cheats/GSTargetable.cpp @@ -15,12 +15,14 @@ static constexpr int32_t CVAR_GSTARGETABLE_DEFAULT = 0; #define CVAR_GSTARGETABLE_NAME CVAR_CHEAT("GSTargetable") #define CVAR_GSTARGETABLE_VALUE CVarGetInteger(CVAR_GSTARGETABLE_NAME, CVAR_GSTARGETABLE_DEFAULT) -static void OnInitGSTargetable(void* refActor) { +static void OnActorInitGSTargetable(void* refActor) { EnSw* enSw = reinterpret_cast(refActor); if (enSw->actor.naviEnemyId == 0x20) { - // Enable Targeting this Gold Skulltula - enSw->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; + // Enable Targeting this Gold Skulltula, if visible by default + if (enSw->actor.scale.x >= 0.0139999995f) { + enSw->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; + } // By default Gold Skulltulas are categorized as NPCs (blue cursor) which feels wrong. // Change the category to Misc (green cursor) instead. @@ -38,6 +40,23 @@ static void OnEnemyDefeatGSTargetable(void* refActor) { } } +static void OnActorUpdateGSTargetable(void* refActor) { + EnSw* enSw = reinterpret_cast(refActor); + + // Handle Night GS Spawning/Despawning + if ((enSw->actor.naviEnemyId == 0x20) && (((enSw->actor.params & 0xE000) >> 0xD) == 2) && + (enSw->actor.colChkInfo.health > 0)) { + if (enSw->actor.scale.x < 0.0139999995f) { + // Night GS Despawn + enSw->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; + } + if (enSw->actor.scale.x >= 0.0139999995f) { + // Night GS Spawn + enSw->actor.flags |= ACTOR_FLAG_ATTENTION_ENABLED; + } + } +} + static void UpdateGSTargetable() { if (gPlayState != nullptr) { if (CVAR_GSTARGETABLE_VALUE) { @@ -59,10 +78,11 @@ static void UpdateGSTargetable() { Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_MISC); } - // Make all Gold Skulltulas in Misc category targetable + // Make all Gold Skulltulas in Misc category targetable, if visible Actor* actorMisc = gPlayState->actorCtx.actorLists[ACTORCAT_MISC].head; while (actorMisc != nullptr) { - if ((actorMisc->id == ACTOR_EN_SW) && (actorMisc->naviEnemyId == 0x20)) { + if ((actorMisc->id == ACTOR_EN_SW) && (actorMisc->naviEnemyId == 0x20) && + (actorMisc->scale.x >= 0.0139999995f)) { actorMisc->flags |= ACTOR_FLAG_ATTENTION_ENABLED; } actorMisc = actorMisc->next; @@ -94,8 +114,9 @@ static void UpdateGSTargetable() { static void RegisterGSTargetable() { UpdateGSTargetable(); - COND_ID_HOOK(OnActorInit, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnInitGSTargetable); + COND_ID_HOOK(OnActorInit, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnActorInitGSTargetable); COND_ID_HOOK(OnEnemyDefeat, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnEnemyDefeatGSTargetable); + COND_ID_HOOK(OnActorUpdate, ACTOR_EN_SW, CVAR_GSTARGETABLE_VALUE, OnActorUpdateGSTargetable); } static RegisterShipInitFunc initFunc(RegisterGSTargetable, { CVAR_GSTARGETABLE_NAME });