From 544964c1a53cae4b6afac0227a0cdd6884928410 Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Sat, 13 Jun 2026 07:56:51 -0400 Subject: [PATCH] properly implement no logic --- .../generator/logic/requirement.cpp | 4 ++ src/dusk/randomizer/generator/logic/world.cpp | 40 ++++++++++++++++--- src/dusk/randomizer/generator/logic/world.hpp | 2 + src/dusk/randomizer/generator/randomizer.cpp | 2 + 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/dusk/randomizer/generator/logic/requirement.cpp b/src/dusk/randomizer/generator/logic/requirement.cpp index add387d88a..a567a02f74 100644 --- a/src/dusk/randomizer/generator/logic/requirement.cpp +++ b/src/dusk/randomizer/generator/logic/requirement.cpp @@ -153,6 +153,10 @@ namespace randomizer::logic::requirement world::World* world, const bool& forceLogic /* = false */) { + if (world->Setting("Logic Rules") == "No Logic" && !forceLogic) { + return NO_REQUIREMENT; + } + Requirement req; std::string logicStr(reqStr); // First, we make sure that the expression has no missing or extra parenthesis diff --git a/src/dusk/randomizer/generator/logic/world.cpp b/src/dusk/randomizer/generator/logic/world.cpp index ed21fbb4af..05bbc48eff 100644 --- a/src/dusk/randomizer/generator/logic/world.cpp +++ b/src/dusk/randomizer/generator/logic/world.cpp @@ -226,9 +226,7 @@ namespace randomizer::logic::world auto macroReqStr = macroNode.second.as(); // Process the macro - this->_macros[macroIdCounter] = requirement::ParseRequirementString(macroReqStr, - this, - /*forceLogic = */ true); + this->_macros[macroIdCounter] = requirement::ParseRequirementString(macroReqStr, this, true); // Store it this->_macroIndexes[macroName] = macroIdCounter; @@ -871,13 +869,44 @@ namespace randomizer::logic::world } } + // For no logic, we're purely going to base whether the dungeon is required on the Hyrule Castle + // Barrier requirements and Hyrule Castle Big Key chest requirements + bool World::IsNoLogicRequiredDungeon(const std::unique_ptr& dungeon) { + auto barrierRequirements = this->Setting("Hyrule Barrier Requirements"); + auto bigKeyRequirements = this->Setting("Hyrule Castle Big Key Requirements"); + + bool dungeonHasFusedShadow = std::ranges::any_of(dungeon->GetLocations(), [](const auto& location) { + return location->GetCurrentItem()->GetName() == "Progressive Fused Shadow"; + }); + bool dungeonHasMirrorShard = std::ranges::any_of(dungeon->GetLocations(), [](const auto& location) { + return location->GetCurrentItem()->GetName() == "Progressive Mirror Shard"; + }); + + if (dungeonHasFusedShadow && (barrierRequirements == "Fused Shadows" || bigKeyRequirements == "Fused Shadows")) { + return true; + } + + if (dungeonHasMirrorShard && (barrierRequirements == "Mirror Shards" || bigKeyRequirements == "Mirror Shards")) { + return true; + } + + if (barrierRequirements == "Vanilla" && (dungeon->GetName() == "Palace of Twilight" || + (this->Setting("Palace of Twilight Requirements") == "Vanilla" && dungeon->GetName() == "City in the Sky"))) + { + return true; + } + + return false; + } + void World::DetermineRequiredDungeons() { for (const auto& [dungeonName, dungeon] : this->_dungeons) { // To determine if a dungeon is required, we're going to disable all of its entrances and then check to see // that the game is still beatable. If the game is not beatable with the dungeon entrances disabled, then the - // dungeon is required. + // dungeon is required. For no logic, we determine required dungeons differently since otherwise no dungeon + // would be required. // Hyrule Castle is implicitly required if (dungeonName == "Hyrule Castle") { @@ -893,7 +922,8 @@ namespace randomizer::logic::world // Check if the game is beatable, set dungeon as required if so. If the dungeon is not required and barren // unrequired dungeons is on, then set all the locations in the unrequired dungeon as nonprogress. auto completeItemPool = item_pool::GetCompleteItemPool(this->_randomizer->GetWorlds()); - if (!search::GameBeatable(&this->_randomizer->GetWorlds(), completeItemPool)) + if (!search::GameBeatable(&this->_randomizer->GetWorlds(), completeItemPool) || + (this->Setting("Logic Rules") == "No Logic" && this->IsNoLogicRequiredDungeon(dungeon))) { dungeon->SetRequired(true); } diff --git a/src/dusk/randomizer/generator/logic/world.hpp b/src/dusk/randomizer/generator/logic/world.hpp index 425687a9c8..4b7beaacb7 100644 --- a/src/dusk/randomizer/generator/logic/world.hpp +++ b/src/dusk/randomizer/generator/logic/world.hpp @@ -102,6 +102,8 @@ namespace randomizer::logic::world */ void DetermineDungeonDependentLocations(); + bool IsNoLogicRequiredDungeon(const std::unique_ptr& dungeon); + /** * @brief Determines which dungeons are required based on placed items. Sets required dungeons as such in their * properties. If "Unrequired Dungeons Are Barren" is "On", then unrequired dungeons will have all their locations diff --git a/src/dusk/randomizer/generator/randomizer.cpp b/src/dusk/randomizer/generator/randomizer.cpp index 6d9307b3e1..ad2230cb25 100644 --- a/src/dusk/randomizer/generator/randomizer.cpp +++ b/src/dusk/randomizer/generator/randomizer.cpp @@ -60,6 +60,8 @@ namespace randomizer std::unique_ptr world = std::make_unique(1, this); world->SetSettings(this->_config.GetSettingsList().front()); + // Always use logic when building a tracker world + world->Setting("Logic Rules").SetCurrentOption("All Locations Reachable"); world->Build(); this->_worlds.emplace_back(std::move(world));