From 33758e49db66adf2b1bf0599ac0b4cbfff14975d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Fri, 2 Jan 2026 15:17:57 +0000 Subject: [PATCH] Medallions Locked Trials (#6046) Adds rando option to bar doors to trials until corresponding medallion acquired --- .../randomizer/LockOverworldDoors.cpp | 1 - .../randomizer/MedallionLockedTrials.cpp | 48 +++++++++++++++++++ .../randomizer/option_descriptions.cpp | 2 + .../Enhancements/randomizer/randomizerTypes.h | 1 + soh/soh/Enhancements/randomizer/settings.cpp | 4 +- 5 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp diff --git a/soh/soh/Enhancements/randomizer/LockOverworldDoors.cpp b/soh/soh/Enhancements/randomizer/LockOverworldDoors.cpp index 04e0e4ea5..fe934456c 100644 --- a/soh/soh/Enhancements/randomizer/LockOverworldDoors.cpp +++ b/soh/soh/Enhancements/randomizer/LockOverworldDoors.cpp @@ -60,7 +60,6 @@ std::map lookupTable = { {{ SCENE_LON_LON_RANCH, 447 }, RAND_INF_BACK_TOWER_UNLOCKED }, {{ SCENE_LAKE_HYLIA, 447 }, RAND_INF_HYLIA_LAB_UNLOCKED }, {{ SCENE_LAKE_HYLIA, 1471 }, RAND_INF_FISHING_HOLE_UNLOCKED }, - // clang-format on }; diff --git a/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp b/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp new file mode 100644 index 000000000..1c769d9e9 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/MedallionLockedTrials.cpp @@ -0,0 +1,48 @@ +#include "soh/OTRGlobals.h" +#include "soh/ShipInit.hpp" + +extern "C" { +extern PlayState* gPlayState; +#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h" +void DoorShutter_SetupAction(DoorShutter*, DoorShutterActionFunc); +void DoorShutter_SetupType(DoorShutter*, PlayState*); +} + +static void OnDoorInit(void* actorRef) { + if (gPlayState->sceneNum == SCENE_INSIDE_GANONS_CASTLE) { + DoorShutter* door = static_cast(actorRef); + bool barred = false; + switch (door->dyna.actor.params) { + case 8255: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST); + break; + case 9279: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER); + break; + case 10303: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_LIGHT); + break; + case 11327: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE); + break; + case 12351: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW); + break; + case 16447: + barred = !CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT); + break; + } + if (barred) { + door->doorType = SHUTTER_FRONT_SWITCH_BACK_CLEAR; + DoorShutter_SetupAction(door, DoorShutter_SetupType); + } + } +} + +void RegisterMedallionLockedTrials() { + bool shouldRegister = IS_RANDO && RAND_GET_OPTION(RSK_MEDALLION_LOCKED_TRIALS); + + COND_ID_HOOK(OnActorInit, ACTOR_DOOR_SHUTTER, shouldRegister, OnDoorInit); +} + +static RegisterShipInitFunc initFunc(RegisterMedallionLockedTrials, { "IS_RANDO" }); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index b47bf652a..99b15c619 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -103,6 +103,8 @@ void Settings::CreateOptionDescriptions() { "\n" "Random Number - A random number and set of trials will be required."; mOptionDescriptions[RSK_TRIAL_COUNT] = "Set the number of trials required to enter Ganon's Tower."; + mOptionDescriptions[RSK_MEDALLION_LOCKED_TRIALS] = + "Doors to trials will be barred until their corresponding medallion is acquired."; mOptionDescriptions[RSK_MQ_DUNGEON_RANDOM] = "Sets the number of Master Quest Dungeons that are shuffled into the pool.\n" "\n" diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 826c54a2d..9229626c4 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -6217,6 +6217,7 @@ typedef enum { RSK_BRIDGE_OPTIONS, RSK_GANONS_TRIALS, RSK_TRIAL_COUNT, + RSK_MEDALLION_LOCKED_TRIALS, RSK_STARTING_OCARINA, RSK_SHUFFLE_OCARINA, RSK_SHUFFLE_OCARINA_BUTTONS, diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index d394c21da..fb01c5741 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -279,6 +279,7 @@ void Settings::CreateOptions() { } }); OPT_U8(RSK_TRIAL_COUNT, "Ganon's Trials Count", {NumOpts(0, 6)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrialCount"), mOptionDescriptions[RSK_TRIAL_COUNT], WIDGET_CVAR_SLIDER_INT, 6, true); + OPT_BOOL(RSK_MEDALLION_LOCKED_TRIALS, "Medallion Locked Trials", CVAR_RANDOMIZER_SETTING("MedallionLockedTrials"), mOptionDescriptions[RSK_MEDALLION_LOCKED_TRIALS]); OPT_U8(RSK_STARTING_AGE, "Starting Age", {"Child", "Adult", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WIDGET_CVAR_COMBOBOX, RO_AGE_CHILD); OPT_U8(RSK_SELECTED_STARTING_AGE, "Selected Starting Age", {"Child", "Adult"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SelectedStartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WIDGET_CVAR_COMBOBOX, RO_AGE_CHILD); OPT_BOOL(RSK_SHUFFLE_ENTRANCES, "Shuffle Entrances"); @@ -2167,7 +2168,6 @@ void Settings::CreateOptions() { } } mOptionGroups[RSG_TRICKS] = OptionGroup::SubGroup("Logical Tricks", tricksOption); - // TODO: Glitches mOptionGroups[RSG_MENU_SECTION_LOGIC] = OptionGroup::SubGroup("Logic", { &mOptions[RSK_LOGIC_RULES], @@ -2219,6 +2219,7 @@ void Settings::CreateOptions() { &mOptions[RSK_RAINBOW_BRIDGE_TOKEN_COUNT], &mOptions[RSK_GANONS_TRIALS], &mOptions[RSK_TRIAL_COUNT], + &mOptions[RSK_MEDALLION_LOCKED_TRIALS], }, WidgetContainerType::SECTION); mOptionGroups[RSG_MENU_COLUMN_AREA_ACCESS] = @@ -2519,6 +2520,7 @@ void Settings::CreateOptions() { &mOptions[RSK_BRIDGE_OPTIONS], &mOptions[RSK_GANONS_TRIALS], &mOptions[RSK_TRIAL_COUNT], + &mOptions[RSK_MEDALLION_LOCKED_TRIALS], }); mOptionGroups[RSG_WORLD] = OptionGroup("World Settings", { &mOptions[RSK_STARTING_AGE],