fix potsanity looking at deku tree MQness when dealing with pots between quests (#4773)

* fix potsanity looking at deku tree MQness when dealing with pots between dungeons

also don't need a loop for a range check

* share logic between placing freestanding & pots

* fix settings typo

* fix all freestanding items still being shuffled

this reinstates original freestanding method of filling in unused locations,
but also extend logic so that when only dungeons have freestanding shuffled
we don't render overworld freestanding as 3d versions until collected

* lift optimization check
This commit is contained in:
Philip Dubé 2025-01-01 20:26:41 +00:00 committed by GitHub
parent 21e55563b4
commit 4c6a2a4b64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 58 additions and 55 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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]);