diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index a2562c99e..1a931b47a 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -624,25 +624,37 @@ static void PlaceVanillaOverworldFish() { } } -static void PlaceFreestandingItems() { - auto ctx = Rando::Context::GetInstance(); - auto option = ctx->GetOption(RSK_SHUFFLE_FREESTANDING); - for (RandomizerCheck loc : ctx->GetLocations(ctx->allLocations, RCTYPE_FREESTANDING)) { - RandomizerGet vanillaItem = Rando::StaticData::GetLocation(loc)->GetVanillaItem(); - if (option.Is(RO_FREESTANDING_OVERWORLD) || option.Is(RO_FREESTANDING_ALL)) { - AddItemToMainPool(vanillaItem); - } else { - ctx->PlaceItemInLocation(loc, vanillaItem, false, true); - } - } +static void PlaceItemsForType(RandomizerCheckType rctype, bool overworldActive, bool dungeonActive, bool placeVanilla) { + for (RandomizerCheck rc : ctx->GetLocations(ctx->allLocations, rctype)) { + auto loc = Rando::StaticData::GetLocation(rc); - for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) { - for (RandomizerCheck loc : ctx->GetLocations(dungeon->GetDungeonLocations(), RCTYPE_FREESTANDING)) { - RandomizerGet vanillaItem = Rando::StaticData::GetLocation(loc)->GetVanillaItem(); - if (option.Is(RO_FREESTANDING_DUNGEONS) || option.Is(RO_FREESTANDING_ALL)) { - AddItemToMainPool(vanillaItem); - } else { - ctx->PlaceItemInLocation(loc, vanillaItem, false, true); + // If item is in the overworld and shuffled, add its item to the pool + if (loc->IsOverworld()) { + if (overworldActive) { + AddItemToMainPool(loc->GetVanillaItem()); + } else if (placeVanilla) { + ctx->PlaceItemInLocation(rc, loc->GetVanillaItem(), false, true); + } + } else { + if (dungeonActive) { + // If the same in MQ and vanilla, add. + RandomizerCheckQuest currentQuest = loc->GetQuest(); + if (currentQuest == RCQUEST_BOTH) { + AddItemToMainPool(loc->GetVanillaItem()); + } else { + // Check if current item's dungeon is vanilla or MQ, and only add if quest corresponds to it. + SceneID itemScene = loc->GetScene(); + + if (itemScene >= SCENE_DEKU_TREE && itemScene <= SCENE_GERUDO_TRAINING_GROUND) { + bool isMQ = ctx->GetDungeon(itemScene)->IsMQ(); + + if ((isMQ && currentQuest == RCQUEST_MQ) || (!isMQ && currentQuest == RCQUEST_VANILLA)) { + AddItemToMainPool(loc->GetVanillaItem()); + } + } + } + } else if (placeVanilla) { + ctx->PlaceItemInLocation(rc, loc->GetVanillaItem(), false, true); } } } @@ -841,40 +853,12 @@ void GenerateItemPool() { } // Shuffle Pots - if (ctx->GetOption(RSK_SHUFFLE_POTS).IsNot(RO_SHUFFLE_POTS_OFF)) { - bool overworldPotsActive = ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_OVERWORLD) || - ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_ALL); - bool dungeonPotsActive = ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_DUNGEONS) || + bool overworldPotsActive = ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_OVERWORLD) || ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_ALL); - - for (RandomizerCheck loc : ctx->GetLocations(ctx->allLocations, RCTYPE_POT)) { - bool overworldPot = Rando::StaticData::GetLocation(loc)->IsOverworld(); - bool dungeonPot = !overworldPot; - - // If pot is in the overworld and shuffled, add its item to the pool - if (overworldPotsActive && overworldPot) { - AddItemToMainPool(Rando::StaticData::GetLocation(loc)->GetVanillaItem()); - } else if (dungeonPotsActive && dungeonPot) { - // If pot is the same in MQ and vanilla, add. - RandomizerCheckQuest currentQuest = Rando::StaticData::GetLocation(loc)->GetQuest(); - if (currentQuest == RCQUEST_BOTH) { - AddItemToMainPool(Rando::StaticData::GetLocation(loc)->GetVanillaItem()); - } else { - // Check if current pot's dungeon is vanilla or MQ, and only add if quest corresponds to it. - SceneID potScene = Rando::StaticData::GetLocation(loc)->GetScene(); - - for (uint8_t i = SCENE_DEKU_TREE; i <= SCENE_GERUDO_TRAINING_GROUND; i++) { - if (i == potScene) { - bool isMQ = ctx->GetDungeon(SCENE_DEKU_TREE)->IsMQ(); - - if ((isMQ && currentQuest == RCQUEST_MQ) || (!isMQ && currentQuest == RCQUEST_VANILLA)) { - AddItemToMainPool(Rando::StaticData::GetLocation(loc)->GetVanillaItem()); - } - } - } - } - } - } + bool dungeonPotsActive = ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_DUNGEONS) || + ctx->GetOption(RSK_SHUFFLE_POTS).Is(RO_SHUFFLE_POTS_ALL); + if (overworldPotsActive || dungeonPotsActive) { + PlaceItemsForType(RCTYPE_POT, overworldPotsActive, dungeonPotsActive, false); } auto fsMode = ctx->GetOption(RSK_FISHSANITY); @@ -1279,7 +1263,13 @@ void GenerateItemPool() { PlaceVanillaDekuScrubItems(ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF)); } - PlaceFreestandingItems(); + bool overworldFreeStandingActive = ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_OVERWORLD) || + ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_ALL); + bool dungeonFreeStandingActive = ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_DUNGEONS) || + ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_ALL); + if (overworldFreeStandingActive || dungeonFreeStandingActive) { + PlaceItemsForType(RCTYPE_FREESTANDING, overworldFreeStandingActive, dungeonFreeStandingActive, true); + } AddItemsToPool(ItemPool, alwaysItems); AddItemsToPool(ItemPool, dungeonRewards); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index c94ea2776..af2056dcc 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -883,9 +883,22 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l uint32_t params = item00->actor.params == ITEM00_HEART_PIECE || item00->actor.params == ITEM00_SMALL_KEY ? item00->ogParams : TWO_ACTOR_PARAMS((int32_t)pos.x, (int32_t)pos.z); Rando::Location* loc = OTRGlobals::Instance->gRandomizer->GetCheckObjectFromActor(item00->actor.id, gPlayState->sceneNum, params); - if (loc && loc->GetRandomizerCheck() != RC_UNKNOWN_CHECK && (RAND_GET_OPTION(RSK_SHUFFLE_FREESTANDING) || item00->actor.params == ITEM00_HEART_PIECE || item00->actor.params == ITEM00_SMALL_KEY)) { + if (loc && loc->GetRandomizerCheck() != RC_UNKNOWN_CHECK) { + auto ctx = Rando::Context::GetInstance(); + bool freestanding_mode = ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_ALL); + if (!freestanding_mode) { + if (loc->IsOverworld()) { + freestanding_mode = ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_OVERWORLD); + } else { + freestanding_mode = ctx->GetOption(RSK_SHUFFLE_FREESTANDING).Is(RO_FREESTANDING_DUNGEONS); + } + } + // Spawn vanilla item if collected and renewable - if (loc->GetCollectionCheck().type != SPOILER_CHK_RANDOMIZER_INF || !Rando::Context::GetInstance()->GetItemLocation(loc->GetRandomizerCheck())->HasObtained()) { + if ( + (freestanding_mode || item00->actor.params == ITEM00_HEART_PIECE || item00->actor.params == ITEM00_SMALL_KEY) && + (loc->GetCollectionCheck().type != SPOILER_CHK_RANDOMIZER_INF || !Rando::Context::GetInstance()->GetItemLocation(loc->GetRandomizerCheck())->HasObtained()) + ) { item00->randoCheck = loc->GetRandomizerCheck(); item00->itemEntry = Rando::Context::GetInstance()->GetFinalGIEntry(loc->GetRandomizerCheck(), true); item00->actor.params = ITEM00_SOH_DUMMY; diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 68245757b..cb0540f36 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -221,7 +221,7 @@ void Settings::CreateOptions() { mOptions[RSK_SHUFFLE_BOSS_SOULS] = Option::U8("Shuffle Boss Souls", {"Off", "On", "On + Ganon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleBossSouls"), mOptionDescriptions[RSK_SHUFFLE_BOSS_SOULS], WidgetType::Combobox); mOptions[RSK_SHUFFLE_DEKU_STICK_BAG] = Option::Bool("Shuffle Deku Stick Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuStickBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_STICK_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF); mOptions[RSK_SHUFFLE_DEKU_NUT_BAG] = Option::Bool("Shuffle Deku Nut Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuNutBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_NUT_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF); - mOptions[RSK_SHUFFLE_FREESTANDING] = Option::U8("Shuffle Freestanding Items", {"Off", "Dungeons", "Overworld", "All Items"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleFreestanding"), mOptionDescriptions[RSK_SHUFFLE_FREESTANDING], WidgetType::Combobox, RO_TOKENSANITY_OFF); + mOptions[RSK_SHUFFLE_FREESTANDING] = Option::U8("Shuffle Freestanding Items", {"Off", "Dungeons", "Overworld", "All Items"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleFreestanding"), mOptionDescriptions[RSK_SHUFFLE_FREESTANDING], WidgetType::Combobox, RO_FREESTANDING_OFF); mOptions[RSK_FISHSANITY] = Option::U8("Fishsanity", {"Off", "Shuffle only Hyrule Loach", "Shuffle Fishing Pond", "Shuffle Overworld Fish", "Shuffle Both"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Fishsanity"), mOptionDescriptions[RSK_FISHSANITY], WidgetType::Combobox, RO_FISHSANITY_OFF); mOptions[RSK_FISHSANITY_POND_COUNT] = Option::U8("Pond Fish Count", {NumOpts(0,17,1)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FishsanityPondCount"), mOptionDescriptions[RSK_FISHSANITY_POND_COUNT], WidgetType::Slider, 0, true, IMFLAG_NONE); mOptions[RSK_FISHSANITY_AGE_SPLIT] = Option::Bool("Pond Age Split", CVAR_RANDOMIZER_SETTING("FishsanityAgeSplit"), mOptionDescriptions[RSK_FISHSANITY_AGE_SPLIT]);