From 88a5b3ff481d6260ff67477779b6c6fe43a3bac4 Mon Sep 17 00:00:00 2001 From: lepideble <147614625+lepideble@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:30:35 +0200 Subject: [PATCH] Add an option to limit the location of triforce pieces (#6710) --- soh/soh/Enhancements/randomizer/3drando/fill.cpp | 8 ++++++++ .../Enhancements/randomizer/option_descriptions.cpp | 6 ++++++ .../randomizer/randomizerEnums/RandomizerOptions.h | 7 +++++++ .../randomizer/randomizerEnums/RandomizerSettingKey.h | 1 + soh/soh/Enhancements/randomizer/settings.cpp | 11 ++++++++--- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 0214d0c11f..cb15b8f70c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -1183,6 +1183,14 @@ static void RandomizeDungeonItems() { AddElementsToPool(overworldItems, rewards); } + if (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_LOCATION).Is(RO_TRIFORCE_HUNT_LOCATION_ANY_DUNGEON)) { + auto triforcePieces = FilterAndEraseFromPool(itemPool, [](const auto i) { return i == RG_TRIFORCE_PIECE; }); + AddElementsToPool(anyDungeonItems, triforcePieces); + } else if (ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_LOCATION).Is(RO_TRIFORCE_HUNT_LOCATION_OVERWORLD)) { + auto triforcePieces = FilterAndEraseFromPool(itemPool, [](const auto i) { return i == RG_TRIFORCE_PIECE; }); + AddElementsToPool(overworldItems, triforcePieces); + } + // Randomize Any Dungeon and Overworld pools AssumedFill(anyDungeonItems, anyDungeonLocations, true); AssumedFill(overworldItems, ctx->overworldLocations, true); diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index de0ff371fb..8efc31f49e 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -135,6 +135,12 @@ void Settings::CreateOptionDescriptions() { "The amount of Triforce pieces that will be placed in the world. " "Keep in mind seed generation can fail if more pieces are placed than there are junk items in the item pool."; mOptionDescriptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED] = "The amount of Triforce pieces required to win the game."; + mOptionDescriptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION] = + "Any dungeon - Triforce pieces can only appear inside of any dungeon.\n" + "\n" + "Overworld - Triforce pieces can only appear outside of dungeons.\n" + "\n" + "Anywhere - Triforce pieces can appear anywhere in the world."; mOptionDescriptions[RSK_SHUFFLE_DUNGEON_ENTRANCES] = "Shuffle the pool of dungeon entrances, including Bottom of the Well, Ice Cavern and Gerudo Training Ground.\n" "\n" diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerOptions.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerOptions.h index 8d8fe074c0..e19e34a599 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerOptions.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerOptions.h @@ -462,6 +462,13 @@ RANDO_ENUM_ITEM(RO_TRIFORCE_HUNT_WIN) RANDO_ENUM_ITEM(RO_TRIFORCE_HUNT_GBK) RANDO_ENUM_END(RandoOptionTriforceHunt) +// Trifoce Hunt location +RANDO_ENUM_BEGIN(RandoOptionTriforceHuntLocation) +RANDO_ENUM_ITEM(RO_TRIFORCE_HUNT_LOCATION_ANY_DUNGEON) +RANDO_ENUM_ITEM(RO_TRIFORCE_HUNT_LOCATION_OVERWORLD) +RANDO_ENUM_ITEM(RO_TRIFORCE_HUNT_LOCATION_ANYWHERE) +RANDO_ENUM_END(RandoOptionTriforceHuntLocation) + RANDO_ENUM_BEGIN(RandoOptionLocationInclusion) RANDO_ENUM_ITEM(RO_LOCATION_INCLUDE) RANDO_ENUM_ITEM(RO_LOCATION_EXCLUDE) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h index ce738a6fa6..3095055b55 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h @@ -230,6 +230,7 @@ RANDO_ENUM_ITEM(RSK_SHUFFLE_100_GS_REWARD) RANDO_ENUM_ITEM(RSK_TRIFORCE_HUNT) RANDO_ENUM_ITEM(RSK_TRIFORCE_HUNT_PIECES_TOTAL) RANDO_ENUM_ITEM(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) +RANDO_ENUM_ITEM(RSK_TRIFORCE_HUNT_PIECES_LOCATION) RANDO_ENUM_ITEM(RSK_SHUFFLE_BEAN_SOULS) RANDO_ENUM_ITEM(RSK_SHUFFLE_BOSS_SOULS) RANDO_ENUM_ITEM(RSK_FISHSANITY) diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 0037d4ad16..29b028002d 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -437,10 +437,12 @@ void Settings::CreateOptions() { if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("TriforceHunt"), RO_TRIFORCE_HUNT_OFF) == RO_TRIFORCE_HUNT_OFF) { mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED].Hide(); mOptions[RSK_TRIFORCE_HUNT_PIECES_TOTAL].Hide(); + mOptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION].Hide(); mOptions[RSK_GANONS_BOSS_KEY].Enable(); } else { mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED].Unhide(); mOptions[RSK_TRIFORCE_HUNT_PIECES_TOTAL].Unhide(); + mOptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION].Unhide(); mOptions[RSK_GANONS_BOSS_KEY].Disable( "This option is disabled because Triforce Hunt is enabled." "Ganon's Boss key\nwill instead be given to you after Triforce Hunt completion."); @@ -455,6 +457,7 @@ void Settings::CreateOptions() { } }); OPT_U8(RSK_TRIFORCE_HUNT_PIECES_REQUIRED, "Triforce Hunt Required Pieces", {NumOpts(1, 100)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("TriforceHuntRequiredPieces"), mOptionDescriptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED], WIDGET_CVAR_SLIDER_INT, 19); + OPT_U8(RSK_TRIFORCE_HUNT_PIECES_LOCATION, "Triforce Hunt Pieces Location", {"Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("TriforceHuntPiecesLocation"), mOptionDescriptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION], WIDGET_CVAR_COMBOBOX, RO_TRIFORCE_HUNT_LOCATION_ANYWHERE); OPT_U8(RSK_MQ_DUNGEON_RANDOM, "MQ Dungeon Setting", {"None", "Set Number", "Random", "Selection Only"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("MQDungeons"), mOptionDescriptions[RSK_MQ_DUNGEON_RANDOM], WIDGET_CVAR_COMBOBOX, RO_MQ_DUNGEONS_NONE, false, nullptr, IMFLAG_NONE); OPT_CALLBACK(RSK_MQ_DUNGEON_RANDOM, { switch (CVarGetInteger(CVAR_RANDOMIZER_SETTING("MQDungeons"), RO_MQ_DUNGEONS_NONE)) { @@ -1752,9 +1755,10 @@ void Settings::CreateOptions() { mOptionGroups[RSG_MENU_SECTION_WINCON] = OptionGroup::SubGroup( "Win Condition", { &mOptions[RSK_TRIFORCE_HUNT], &mOptions[RSK_TRIFORCE_HUNT_PIECES_TOTAL], - &mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED], &mOptions[RSK_GANONS_BOSS_KEY], &mOptions[RSK_LACS_OPTIONS], - &mOptions[RSK_LACS_MEDALLION_COUNT], &mOptions[RSK_LACS_STONE_COUNT], &mOptions[RSK_LACS_DUNGEON_COUNT], - &mOptions[RSK_LACS_REWARD_COUNT], &mOptions[RSK_LACS_TOKEN_COUNT] }, + &mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED], &mOptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION], + &mOptions[RSK_GANONS_BOSS_KEY], &mOptions[RSK_LACS_OPTIONS], &mOptions[RSK_LACS_MEDALLION_COUNT], + &mOptions[RSK_LACS_STONE_COUNT], &mOptions[RSK_LACS_DUNGEON_COUNT], &mOptions[RSK_LACS_REWARD_COUNT], + &mOptions[RSK_LACS_TOKEN_COUNT] }, WidgetContainerType::SECTION); mOptionGroups[RSG_MENU_COLUMN_LOGIC_WINCON] = OptionGroup::SubGroup("", std::initializer_list{ @@ -2117,6 +2121,7 @@ void Settings::CreateOptions() { &mOptions[RSK_TRIFORCE_HUNT], &mOptions[RSK_TRIFORCE_HUNT_PIECES_TOTAL], &mOptions[RSK_TRIFORCE_HUNT_PIECES_REQUIRED], + &mOptions[RSK_TRIFORCE_HUNT_PIECES_LOCATION], &mOptions[RSK_MQ_DUNGEON_RANDOM], &mOptions[RSK_MQ_DUNGEON_COUNT], &mOptions[RSK_MQ_DUNGEON_SET],