From e1b72e4ea9d0c9c162a7cbf6a1f8475277a3c8a6 Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Sun, 17 Aug 2025 22:57:25 -0400 Subject: [PATCH 1/3] Add enhancement to toggle grave hole geometry --- .../Restorations/GraveHoleJumps.cpp | 73 +++++++++++++++++++ soh/soh/SohGui/SohMenuEnhancements.cpp | 4 + 2 files changed, 77 insertions(+) create mode 100644 soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp diff --git a/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp new file mode 100644 index 000000000..57d9ac848 --- /dev/null +++ b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp @@ -0,0 +1,73 @@ +#include "public/bridge/consolevariablebridge.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include "functions.h" +#include "soh/Enhancements/enhancementTypes.h" +#include "soh/resource/type/Scene.h" +#include "soh/resource/type/scenecommand/SceneCommand.h" +#include "soh/resource/type/scenecommand/SetCollisionHeader.h" + +#define CVAR_GRAVE_HOLE_NAME CVAR_ENHANCEMENT("GraveHoles") +#define GRAVE_HOLES_DEFAULT 0 +#define CVAR_GRAVE_HOLE_VALUE CVarGetInteger(CVAR_GRAVE_HOLE_NAME, GRAVE_HOLES_DEFAULT) +#define GRAVEYARD_SCENE_FILEPATH "scenes/shared/spot02_scene/spot02_scene" +#define CUSTOM_SURFACE_TYPE 32 + +const static std::vector, std::pair>> graveyardGeometryPatches = { + // { { startPolygon, endPolygon }, { originalSurfaceType, patchedSurfaceType } } + { { 487, 509 }, { 20, CUSTOM_SURFACE_TYPE } }, // Floor around graves + { { 651, 658 }, { 20, CUSTOM_SURFACE_TYPE } }, // Floor around Royal Family Tomb + { { 613, 620 }, { 0, 15 } }, // Grave ledges (Hylian Shield) + { { 623, 630 }, { 0, 15 } }, // Grave ledges (Redead) + { { 633, 640 }, { 0, 15 } }, // Grave ledges (Dampe) + { { 643, 650 }, { 0, 15 } }, // Grave ledges (Royal Family) +}; + +CollisionHeader* getGraveyardCollisionHeader() { + /* + * Load the graveyard collision header manually. Since its position varies between versions, we cannot directly use + * dspot02_sceneCollisionHeader_003C54. We have to scroll through the scene cmds to get the header the same way the + * game does. + */ + SOH::Scene* scene = + (SOH::Scene*)Ship::Context::GetInstance()->GetResourceManager()->LoadResource(GRAVEYARD_SCENE_FILEPATH).get(); + SOH::ISceneCommand* sceneCmd = nullptr; + for (int i = 0; i < scene->commands.size(); i++) { + auto cmd = scene->commands[i]; + if (cmd->cmdId == SOH::SceneCommandID::SetCollisionHeader) { + sceneCmd = cmd.get(); + break; + } + } + CollisionHeader* graveyardColHeader = (CollisionHeader*)((SOH::SetCollisionHeader*)sceneCmd)->GetRawPointer(); + + /* + * Copy the surface type list and give ourselves some extra space to create another surface type for Link to fall + * into graves. NTSC 1.0's graveyard has 31 surface types, while later versions have 32. The contents of the lists + * are shifted somewhat between versions, so to be safe we just create an extra slot that is not in any version. + */ + size_t surfaceTypeListSize = sizeof(SurfaceType) * 33; + SurfaceType* newSurfaceTypes = (SurfaceType*)malloc(surfaceTypeListSize); + memcpy(newSurfaceTypes, graveyardColHeader->surfaceTypeList, surfaceTypeListSize); + newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[0] = 0x24000004; + newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[1] = 0xFC8; + graveyardColHeader->surfaceTypeList = newSurfaceTypes; + + return graveyardColHeader; +} + +void ApplyGraveyardGeometryPatches() { + static CollisionHeader* graveyardColHeader = getGraveyardCollisionHeader(); + for (auto& mappingPatch : graveyardGeometryPatches) { + for (int i = mappingPatch.first.first; i <= mappingPatch.first.second; i++) { + CollisionPoly* poly = &graveyardColHeader->polyList[i]; + poly->type = CVAR_GRAVE_HOLE_VALUE ? mappingPatch.second.first : mappingPatch.second.second; + } + } +} + +void RegisterGraveHoleJumps() { + ApplyGraveyardGeometryPatches(); +} + +static RegisterShipInitFunc initFunc_GraveHoleJumps(RegisterGraveHoleJumps, { CVAR_GRAVE_HOLE_NAME }); diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 488aeb720..0a1913ea5 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -1161,6 +1161,10 @@ void SohMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("NGCKaleidoSwitcher")) .Options(CheckboxOptions().Tooltip( "Makes L and R switch pages like on the GameCube. Z opens the Debug Menu instead.")); + AddWidget(path, "Grave Hole Jumps", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("GraveHoles")) + .Options(CheckboxOptions().Tooltip( + "Restores NTSC 1.0 behavior where Link jumps over grave holes and grabs the ledges.")); // Difficulty Options path.sidebarName = "Difficulty"; From 836d377ff03a73607224152381abcabe3a7c237f Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Mon, 18 Aug 2025 23:55:31 -0400 Subject: [PATCH 2/3] Replace malloc and vector with fixed-size arrays --- soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp index 57d9ac848..3ebcf8bfc 100644 --- a/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp +++ b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp @@ -13,7 +13,7 @@ #define GRAVEYARD_SCENE_FILEPATH "scenes/shared/spot02_scene/spot02_scene" #define CUSTOM_SURFACE_TYPE 32 -const static std::vector, std::pair>> graveyardGeometryPatches = { +const static std::array, std::pair>, 6> graveyardGeometryPatches = { { // { { startPolygon, endPolygon }, { originalSurfaceType, patchedSurfaceType } } { { 487, 509 }, { 20, CUSTOM_SURFACE_TYPE } }, // Floor around graves { { 651, 658 }, { 20, CUSTOM_SURFACE_TYPE } }, // Floor around Royal Family Tomb @@ -21,7 +21,7 @@ const static std::vector, std::pair>> gr { { 623, 630 }, { 0, 15 } }, // Grave ledges (Redead) { { 633, 640 }, { 0, 15 } }, // Grave ledges (Dampe) { { 643, 650 }, { 0, 15 } }, // Grave ledges (Royal Family) -}; +} }; CollisionHeader* getGraveyardCollisionHeader() { /* @@ -46,9 +46,8 @@ CollisionHeader* getGraveyardCollisionHeader() { * into graves. NTSC 1.0's graveyard has 31 surface types, while later versions have 32. The contents of the lists * are shifted somewhat between versions, so to be safe we just create an extra slot that is not in any version. */ - size_t surfaceTypeListSize = sizeof(SurfaceType) * 33; - SurfaceType* newSurfaceTypes = (SurfaceType*)malloc(surfaceTypeListSize); - memcpy(newSurfaceTypes, graveyardColHeader->surfaceTypeList, surfaceTypeListSize); + SurfaceType newSurfaceTypes[33]; + memcpy(newSurfaceTypes, graveyardColHeader->surfaceTypeList, sizeof(SurfaceType) * 33); newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[0] = 0x24000004; newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[1] = 0xFC8; graveyardColHeader->surfaceTypeList = newSurfaceTypes; From d0eb3e954d6f23d499a6f90460e86f2900f7639f Mon Sep 17 00:00:00 2001 From: Eblo <7004497+Eblo@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:10:14 -0400 Subject: [PATCH 3/3] Make newSurfaceTypes static --- soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp index 3ebcf8bfc..32157b5ce 100644 --- a/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp +++ b/soh/soh/Enhancements/Restorations/GraveHoleJumps.cpp @@ -46,7 +46,7 @@ CollisionHeader* getGraveyardCollisionHeader() { * into graves. NTSC 1.0's graveyard has 31 surface types, while later versions have 32. The contents of the lists * are shifted somewhat between versions, so to be safe we just create an extra slot that is not in any version. */ - SurfaceType newSurfaceTypes[33]; + static SurfaceType newSurfaceTypes[33]; memcpy(newSurfaceTypes, graveyardColHeader->surfaceTypeList, sizeof(SurfaceType) * 33); newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[0] = 0x24000004; newSurfaceTypes[CUSTOM_SURFACE_TYPE].data[1] = 0xFC8;