From b6151c131a9e5c81b007746884fde51f99d99ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= <159546+serprex@users.noreply.github.com> Date: Sun, 7 Jun 2026 06:13:09 +0000 Subject: [PATCH] Allow all 8 items in shop to be randomized in No Logic (#6688) --- soh/soh/Enhancements/randomizer/3drando/shops.cpp | 10 ++++++---- soh/soh/Enhancements/randomizer/option.cpp | 8 +++++++- .../Enhancements/randomizer/option_descriptions.cpp | 6 ++---- soh/soh/Enhancements/randomizer/settings.cpp | 6 +++++- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index d0cc4489b0..b3835cb5ea 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -200,9 +200,11 @@ uint16_t GetCheapBalancedPrice() { return -1; } -// Get 0 to 7, or a random number from 1-7 depending on shopsanity setting +// Get 0 to 8, or a random number, depending on shopsanity setting. The 8th item is only allowed with No Logic, +// since logic otherwise requires at least one buyable refill to remain reachable in each shop. int GetShopsanityReplaceAmount() { auto ctx = Rando::Context::GetInstance(); + const int maxReplace = ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) ? 8 : 7; if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) { return 0; } else if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_SPECIFIC_COUNT)) { @@ -223,12 +225,12 @@ int GetShopsanityReplaceAmount() { } else if (ctx->GetOption(RSK_SHOPSANITY_COUNT).Is(RO_SHOPSANITY_COUNT_SEVEN_ITEMS)) { return 7; } else if (ctx->GetOption(RSK_SHOPSANITY_COUNT).Is(RO_SHOPSANITY_COUNT_EIGHT_ITEMS)) { - return 8; // temporarily unreachable due to logic limitations + return maxReplace; // Clamped to 7 unless No Logic } else { assert(false); return 0; } - } else { // Random, get number in [1, 7] - return Random(1, 8); + } else { // Random, get number in [1, maxReplace] + return Random(1, maxReplace + 1); } } diff --git a/soh/soh/Enhancements/randomizer/option.cpp b/soh/soh/Enhancements/randomizer/option.cpp index 57ceced7d7..aa9eec445c 100644 --- a/soh/soh/Enhancements/randomizer/option.cpp +++ b/soh/soh/Enhancements/randomizer/option.cpp @@ -321,7 +321,13 @@ void Option::AddWidget(WidgetPath& path) { UIWidgets::IntSliderOptions* sliderOpts = (UIWidgets::IntSliderOptions*)info.options.get(); sliderOpts->Format(this->GetOptionText(this->GetOptionIndex()).c_str()); - sliderOpts->Max(this->options.size() - 1); + size_t maxIndex = this->options.size() - 1; + if (this->GetKey() == RSK_SHOPSANITY_COUNT && maxIndex > 7 && + CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) != + RO_LOGIC_NO_LOGIC) { + maxIndex = 7; + } + sliderOpts->Max(maxIndex); } }) .CVar(cvarName.c_str()) diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index d4b9d41f17..6200b08f10 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -369,11 +369,9 @@ void Settings::CreateOptionDescriptions() { "\n" "1-7 Items - Vanilla shop items will be shuffled among different shops, and " "each shop will contain 1-7 non-vanilla shop items.\n" - /* "\n" - "8 Items - All shops will contain 8 non-vanilla shop items.\n" - */ - ; + "8 Items - All shops will contain 8 non-vanilla shop items. " + "Only available with No Logic, since logic otherwise requires at least one buyable refill per shop.\n"; mOptionDescriptions[RSK_SHOPSANITY_PRICES] = "Vanilla - The same price as the item it replaced.\n" "Cheap Balanced - Prices will range between 0 to 95 rupees, favoring lower numbers.\n" diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 7cef5d9c53..0c13f70eba 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -636,7 +636,7 @@ void Settings::CreateOptions() { break; } }); - OPT_U8(RSK_SHOPSANITY_COUNT, "Shops Item Count", {NumOpts(0, 7/*8*/)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WIDGET_CVAR_SLIDER_INT, 0, false, nullptr, IMFLAG_NONE); + OPT_U8(RSK_SHOPSANITY_COUNT, "Shops Item Count", {NumOpts(0, 8)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityCount"), mOptionDescriptions[RSK_SHOPSANITY_COUNT], WIDGET_CVAR_SLIDER_INT, 0, false, nullptr, IMFLAG_NONE); OPT_U8(RSK_SHOPSANITY_PRICES, "Shops Prices", {"Vanilla", "Cheap Balanced", "Balanced", "Fixed", "Range", "Set By Wallet"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShopsanityPrices"), mOptionDescriptions[RSK_SHOPSANITY_PRICES], WIDGET_CVAR_COMBOBOX, RO_PRICE_VANILLA, false, nullptr, IMFLAG_NONE); OPT_CALLBACK(RSK_SHOPSANITY_PRICES, { HandleShopsanityPriceUI(); @@ -1336,6 +1336,10 @@ void Settings::CreateOptions() { OPT_U8(RSK_LOGIC_RULES, "Logic", {"Glitchless", "No Logic"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LogicRules"), mOptionDescriptions[RSK_LOGIC_RULES], WIDGET_CVAR_COMBOBOX, RO_LOGIC_GLITCHLESS, false, nullptr, IMFLAG_LABEL_INLINE); OPT_CALLBACK(RSK_LOGIC_RULES, { HandleStartingAgeUI(); + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) != RO_LOGIC_NO_LOGIC && + CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShopsanityCount"), 0) > 7) { + CVarSetInteger(CVAR_RANDOMIZER_SETTING("ShopsanityCount"), 7); + } }); OPT_BOOL(RSK_ALL_LOCATIONS_REACHABLE, "All Locations Reachable", {"Off", "On"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("AllLocationsReachable"), mOptionDescriptions[RSK_ALL_LOCATIONS_REACHABLE], WIDGET_CVAR_CHECKBOX, RO_GENERIC_ON, false, nullptr, IMFLAG_SAME_LINE); OPT_BOOL(RSK_SKULLS_SUNS_SONG, "Night Skulltula's Expect Sun's Song", CVAR_RANDOMIZER_SETTING("GsExpectSunsSong"), mOptionDescriptions[RSK_SKULLS_SUNS_SONG]);