update hyrule castle settings

This commit is contained in:
gymnast86
2026-04-11 19:37:45 -07:00
parent 796a67f207
commit 461d59984f
29 changed files with 393 additions and 82 deletions
+14 -5
View File
@@ -236,11 +236,20 @@ Can Complete All Dungeons: "'Can_Complete_Forest_Temple' and 'Can_Complete_Goron
'Can_Complete_Arbiters_Grounds' and 'Can_Complete_Snowpeak_Ruins' and 'Can_Complete_Temple_of_Time' and
'Can_Complete_City_in_the_Sky' and 'Can_Complete_Palace_of_Twilight'"
Can Break Hyrule Castle Barrier: Hyrule_Castle_Requirements == Open or
(Hyrule_Castle_Requirements == Vanilla and 'Can_Complete_Palace_of_Twilight') or
(Hyrule_Castle_Requirements == Fused_Shadows and count(Progressive_Fused_Shadow, 3)) or
(Hyrule_Castle_Requirements == Mirror_Shards and count(Progressive_Mirror_Shard, 4)) or
(Hyrule_Castle_Requirements == All_Dungeons and Can_Complete_All_Dungeons)
Can Break Hyrule Castle Barrier: Hyrule_Barrier_Requirements == Open or
(Hyrule_Barrier_Requirements == Vanilla and 'Can_Complete_Palace_of_Twilight') or
(Hyrule_Barrier_Requirements == Fused_Shadows and count(Progressive_Fused_Shadow, Hyrule_Barrier_Fused_Shadows)) or
(Hyrule_Barrier_Requirements == Mirror_Shards and count(Progressive_Mirror_Shard, Hyrule_Barrier_Mirror_Shards)) or
(Hyrule_Barrier_Requirements == Dungeons and dungeons_completed(Hyrule_Barrier_Dungeons)) or
(Hyrule_Barrier_Requirements == Poe_Souls and count(Poe_Soul, Hyrule_Barrier_Poe_Souls)) or
(Hyrule_Barrier_Requirements == Hearts and hearts(Hyrule_Barrier_Hearts))
Can Open Hyrule Castle Big Key Gate: Hyrule_Castle_Big_Key_Requirements == None or
(Hyrule_Castle_Big_Key_Requirements == Fused_Shadows and count(Progressive_Fused_Shadow, Hyrule_Castle_Big_Key_Fused_Shadows)) or
(Hyrule_Castle_Big_Key_Requirements == Mirror_Shards and count(Progressive_Fused_Shadow, Hyrule_Castle_Big_Key_Mirror_Shards)) or
(Hyrule_Castle_Big_Key_Requirements == Dungeons and dungeons_completed(Hyrule_Castle_Big_Key_Dungeons)) or
(Hyrule_Castle_Big_Key_Requirements == Poe_Souls and count(Poe_Soul, Hyrule_Castle_Big_Key_Poe_Souls)) or
(Hyrule_Castle_Big_Key_Requirements == Hearts and hearts(Hyrule_Castle_Big_Key_Hearts))
# WARP PORTALS
+78 -5
View File
@@ -16,14 +16,46 @@
## Access Options ##
######################
- Name: Hyrule Castle Requirements
- Name: Hyrule Barrier Requirements
Default Option: Vanilla
Options:
- Open: "The barrier around Hyrule Castle is dispelled from the beginning."
- Fused Shadows: "The player must collect all 3 Fused Shadows."
- Mirror Shards: "The player must collect all 4 Mirror Shards."
- All Dungeons: "The player must complete all dungeons."
- Vanilla: "The player must complete Palace of Twilight."
- Vanilla: "The barrier will be dispelled once Palace of Twilight is cleared."
- Fused Shadows: "The barrier will be dispelled once the required number of Fused Shadows have been collected."
- Mirror Shards: "The barrier will be dispelled once the required number of Mirror Shards have been collected."
- Dungeons: "The barrier will be dispelled once the required number of Dungeons have been cleared."
- Poe Souls: "The barrier will be dispelled once the required number of Poe Souls have been collected."
- Hearts: "The barrier will be dispelled once the required number of Hearts have been reached."
- Name: Hyrule Barrier Fused Shadows
Tracker Important: True
Default Option: 1
Options:
- 1-3: description
- Name: Hyrule Barrier Mirror Shards
Tracker Important: True
Default Option: 1
Options:
- 1-4: description
- Name: Hyrule Barrier Dungeons
Tracker Important: True
Default Option: 1
Options:
- 1-8: description
- Name: Hyrule Barrier Poe Souls
Tracker Important: True
Default Option: 1
Options:
- 1-60: description
- Name: Hyrule Barrier Hearts
Tracker Important: True
Default Option: 4
Options:
- 4-20: description # Hehe 420
- Name: Palace of Twilight Requirements
Default Option: Vanilla
@@ -150,6 +182,47 @@
- Anywhere: "Maps and Compasses can appear anywhere."
- Start With: "The player starts with all Maps and Compasses."
- Name: Hyrule Castle Big Key Requirements
Tracker Important: True
Default Option: None
Options:
- None: "The gate is opened and the key is randomized according to the respective Big Key settings."
- Fused Shadows: "The gate will open once the required number of Fused Shadows have been collected."
- Mirror Shards: "The gate will open once the required number of Mirror Shards have been collected."
- Dungeons: "The gate will open once the required number of Dungeons have been cleared."
- Poe Souls: "The gate will open once the required number of Poe Souls have been collected."
- Hearts: "The gate will open once the required number of Hearts have been reached."
- Name: Hyrule Castle Big Key Fused Shadows
Tracker Important: True
Default Option: 1
Options:
- 1-3: description
- Name: Hyrule Castle Big Key Mirror Shards
Tracker Important: True
Default Option: 1
Options:
- 1-4: description
- Name: Hyrule Castle Big Key Dungeons
Tracker Important: True
Default Option: 1
Options:
- 1-8: description
- Name: Hyrule Castle Big Key Poe Souls
Tracker Important: True
Default Option: 1
Options:
- 1-60: description
- Name: Hyrule Castle Big Key Hearts
Tracker Important: True
Default Option: 4
Options:
- 4-20: description # Hehe 420
- Name: Dungeon Rewards Can Be Anywhere
Default Option: "Off"
Options:
+6 -2
View File
@@ -85,7 +85,7 @@ EventFlags:
- 0x0003 # Yeto put pumpkin and cheese in soup.
- 0x1460 # Snowpeak Ruins North and West doors unlocked.
- 0x0120 # Told Yeta about cheese
- Hyrule_Castle_Requirements == Open:
- Hyrule_Barrier_Requirements == Open:
- 0x4208 # Remove Castle Barrier
- Palace_of_Twilight_Requirements == Open:
- 0x2B08 # Mirror of Twilight Repaired.
@@ -592,6 +592,9 @@ RegionFlags:
- 0x93 # Unlock door outside 3F.
- 0xB0 # Unlock treasure room door.
- 0xA3 # Unlock door in south garden.
- Big_Keys == Keysy and Hyrule_Castle_Big_Key_Requirements == None:
- 0xA1 # Unlocked Hyrule Castle Boss Door.
- 0xED # Got Hyrule Castle Big Key.
- Maps_and_Compasses == Start_With:
- 0xEE # Got Hyrule Castle Compass.
- 0xEF # Got Hyrule Castle Dungeon Map.
@@ -601,4 +604,5 @@ RegionFlags:
- 0x85 # watched focus on lowered chandelier cs
- 0x9D # lower the main hall chandelier
- 0xAF # defeated double Dinalfos (opens gates both sides)
- Hyrule_Castle_Big_Key_Requirements == None:
- 0x94 # Open HC BK gate
@@ -17,7 +17,7 @@ Gifts From NPCs: Random
Golden Bugs: Random
Goron Mines Entrance: Random
Hidden Skills: Random
Hyrule Castle Requirements: Random
Hyrule Barrier Requirements: Random
Increase Spinner Speed: Random
Increase Wallet Capacity: Random
Instant Message Text: Random
@@ -0,0 +1,3 @@
Seed: TESTTESTTEST
Hyrule Barrier Requirements: Dungeons
Hyrule Barrier Dungeons: 8
@@ -0,0 +1,2 @@
Seed: TESTTESTTEST
Hyrule Barrier Requirements: Fused Shadows
@@ -0,0 +1,3 @@
seed: TESTTESTTEST
Hyrule Barrier Requirements: Hearts
Hyrule Barrier Hearts: 13
@@ -0,0 +1,2 @@
Seed: TESTTESTTEST
Hyrule Barrier Requirements: Mirror Shards
@@ -0,0 +1,2 @@
Seed: TESTTESTTEST
Hyrule Barrier Requirements: Open
@@ -0,0 +1,3 @@
seed: TESTTESTTEST
Hyrule Barrier Requirements: Poe Souls
Hyrule Barrier Poe Souls: 30
@@ -1,2 +0,0 @@
Seed: TESTTESTTEST
Hyrule Castle Requirements: All Dungeons
@@ -1,2 +0,0 @@
Seed: TESTTESTTEST
Hyrule Castle Requirements: Fused Shadows
@@ -1,2 +0,0 @@
Seed: TESTTESTTEST
Hyrule Castle Requirements: Mirror Shards
@@ -1,2 +0,0 @@
Seed: TESTTESTTEST
Hyrule Castle Requirements: Open
@@ -1,3 +1,3 @@
Seed: TESTTESTTEST
Unrequired Dungeons Are Barren: On
Hyrule Castle Requirements: Mirror Shards
Hyrule Barrier Requirements: Mirror Shards
@@ -161,7 +161,7 @@
Region: Hyrule Castle
Locations:
Hyrule Castle Southeast Balcony Tower Chest: Can_Defeat_Aerolfos
Hyrule Castle Big Key Chest: Nothing
Hyrule Castle Big Key Chest: Can_Open_Hyrule_Castle_Big_Key_Gate
Exits:
Hyrule Castle Final Climb Near Outside Balcony: Can_Open_Doors and (count(Hyrule_Castle_Small_Key, 2) or Small_Keys == Keysy)
Hyrule Castle Double Darknut Room: Can_Open_Doors and 'Can_Defeat_Hyrule_Castle_Double_Darknuts'
@@ -747,11 +747,11 @@ namespace randomizer::logic::entrance_shuffle
foundLocations.end(),
[](const auto& location) { return location->IsProgression(); });
// If there are no sphere zero locations available and we didn't find a disconnected exit, then this world will not
// be valid. Often times when many entrances are randomized we won't find any locations, but will find disconnected
// If there are no sphere zero locations available and we didn't find an accessible disconnected exit, then this world will not
// be valid. Often times when many entrances are randomized we won't find any locations, but will find accessible disconnected
// exits that haven't been shuffled yet. In this case we can usually wait until these exits are connected and more often
// than not this will lead us to sphere zero locations.
if (numSphereZeroLocations == 0 && !sphereZeroSearch._foundDisconnectedExit)
if (numSphereZeroLocations == 0 && !sphereZeroSearch.HasAccessibleDisconnectedExit())
{
throw EntranceShuffleError("No sphere 0 locations reachable at the start!");
}
+24 -12
View File
@@ -243,18 +243,6 @@ int BitIndex::reqBit(const randomizer::logic::requirement::Requirement& req)
reverseIndex.push_back(req);
return bump();
}
// case randomizer::logic::requirement::Type::HEALTH:
// key = std::to_string(std::get<int>(req._args[0]));
// if (heartCount.contains(key))
// {
// return heartCount[key];
// }
// else
// {
// heartCount[key] = counter;
// reverseIndex.push_back(req);
// return bump();
// }
case randomizer::logic::requirement::Type::GOLDEN_BUGS:
key = std::to_string(std::get<int>(req._args[0]));
if (goldenBugCount.contains(key))
@@ -267,6 +255,30 @@ int BitIndex::reqBit(const randomizer::logic::requirement::Requirement& req)
reverseIndex.push_back(req);
return bump();
}
case randomizer::logic::requirement::Type::HEARTS:
key = std::to_string(std::get<int>(req._args[0]));
if (heartCount.contains(key))
{
return heartCount[key];
}
else
{
heartCount[key] = counter;
reverseIndex.push_back(req);
return bump();
}
case randomizer::logic::requirement::Type::DUNGEONS_COMPLETED:
key = std::to_string(std::get<int>(req._args[0]));
if (dungeonCompletedCount.contains(key))
{
return dungeonCompletedCount[key];
}
else
{
dungeonCompletedCount[key] = counter;
reverseIndex.push_back(req);
return bump();
}
default:
// Not a flattening requirement
return -1;
+2 -1
View File
@@ -64,8 +64,9 @@ class BitIndex
int reqBit(const randomizer::logic::requirement::Requirement& req);
std::unordered_map<std::string, int> itemBits = {};
// std::unordered_map<std::string, int> heartCount = {};
std::unordered_map<std::string, int> heartCount = {};
std::unordered_map<std::string, int> goldenBugCount = {};
std::unordered_map<std::string, int> dungeonCompletedCount = {};
std::vector<randomizer::logic::requirement::Requirement> reverseIndex = {};
int counter = 0;
};
@@ -426,12 +426,14 @@ DNF evaluatePartialRequirement(BitIndex& bitIndex,
formTime));
}
return d;
case randomizer::logic::requirement::Type::ITEM:
[[fallthrough]];
case randomizer::logic::requirement::Type::GOLDEN_BUGS:
[[fallthrough]];
case randomizer::logic::requirement::Type::ITEM:
// [[fallthrough]];
// case randomizer::logic::requirement::Type::HEALTH:
case randomizer::logic::requirement::Type::HEARTS:
[[fallthrough]];
case randomizer::logic::requirement::Type::DUNGEONS_COMPLETED:
bits[bitIndex.reqBit(req)] = 1;
return DNF({bits});
+7
View File
@@ -54,6 +54,13 @@ namespace randomizer::logic::item
{
this->_stamp = true;
}
// Make hearts major items if they're required for anything
else if ((name == "Piece of Heart" || name == "Heart Container") &&
((world->Setting("Hyrule Barrier Requirements") == "Hearts") ||
(world->Setting("Hyrule Castle Big Key Requirements") == "Hearts")))
{
this->_importance = Importance::MAJOR;
}
}
int Item::GetID() const
+6 -1
View File
@@ -291,8 +291,13 @@ namespace randomizer::logic::item_pool
{"Temple of Time Big Key"},
{"City in the Sky Big Key"},
{"Palace of Twilight Big Key"},
{"Hyrule Castle Big Key"},
};
if (world->Setting("Hyrule Castle Big Key Requirements") == "None")
{
bigKeys.emplace_back("Hyrule Castle Big Key");
}
for (const auto& key : bigKeys)
{
itemPool.at(key) = 0;
+177 -13
View File
@@ -3,6 +3,7 @@
#include "search.hpp"
#include "world.hpp"
#include "../utility/container.hpp"
#include "../utility/general.hpp"
#include "../utility/log.hpp"
#include "../utility/string.hpp"
@@ -135,6 +136,15 @@ namespace randomizer::logic::requirement
case Type::GOLDEN_BUGS:
count = std::get<int>(this->_args[0]);
return "golden_bugs(" + std::to_string(count) + ")";
case Type::HEARTS:
count = std::get<int>(this->_args[0]);
return "hearts(" + std::to_string(count) + ")";
case Type::DUNGEONS_COMPLETED:
count = std::get<int>(this->_args[0]);
return "dungeons_completed(" + std::to_string(count) + ")";
default:
return reqStr;
}
@@ -334,9 +344,16 @@ namespace randomizer::logic::requirement
}
splitLogicStr.push_back(countArgs);
// For the count, if a setting is passed in, use the setting's value instead
auto& countStr = splitLogicStr[1];
if (seedgen::settings::GetAllSettingsInfo()->contains(countStr))
{
countStr = world->Setting(countStr).GetCurrentOption();
}
// Get the arguments
auto& itemName = splitLogicStr[0];
int count = std::stoi(splitLogicStr[1]);
int count = std::stoi(countStr);
auto item = world->GetItem(itemName);
req._args.emplace_back(count);
req._args.emplace_back(item);
@@ -357,24 +374,31 @@ namespace randomizer::logic::requirement
return req;
}
// And finally a health check
// else if (argStr.find("health") != std::string::npos)
// {
// req._type = randomizer::logic::requirement::Type::HEALTH;
// std::string numHeartsStr(argStr.begin() + argStr.find('(') + 1, argStr.end() - 1);
// int numHearts = std::stoi(numHeartsStr);
// req._args.emplace_back(numHearts);
// return req;
// }
// Then health
else if (argStr.find("hearts") != std::string::npos)
{
req._type = randomizer::logic::requirement::Type::HEARTS;
std::string numHeartsStr(argStr.begin() + argStr.find('(') + 1, argStr.end() - 1);
// If the string for the count is a setting, use the settings current option instead
if (seedgen::settings::GetAllSettingsInfo()->contains(numHeartsStr))
{
numHeartsStr = world->Setting(numHeartsStr).GetCurrentOption();
}
// Check Impossible down here since it's very unlikely
int numHearts = std::stoi(numHeartsStr);
req._args.emplace_back(numHearts);
return req;
}
// Then Impossible...
else if (argStr == "Impossible")
{
req._type = randomizer::logic::requirement::Type::IMPOSSIBLE;
return req;
}
// Check golden bugs last since it's least likely
// Then golden bugs...
else if (argStr.find("golden bugs") != std::string::npos)
{
req._type = randomizer::logic::requirement::Type::GOLDEN_BUGS;
@@ -385,6 +409,24 @@ namespace randomizer::logic::requirement
return req;
}
// Then dungeons completed
else if (argStr.find("dungeons completed") != std::string::npos)
{
req._type = Type::DUNGEONS_COMPLETED;
// Get rid of parenthesis
std::string countStr(argStr.begin() + argStr.find('(') + 1, argStr.end() - 1);
// For the count, if a setting is passed in, use the setting's value instead
if (seedgen::settings::GetAllSettingsInfo()->contains(countStr))
{
countStr = world->Setting(countStr).GetCurrentOption();
}
int count = std::stoi(countStr);
req._args.emplace_back(count);
return req;
}
throw std::runtime_error("Unrecognized logic symbol: \"" + reqStr + "\"");
}
@@ -445,12 +487,73 @@ namespace randomizer::logic::requirement
return req;
}
bool EvaluateSimpleRequirement(const randomizer::logic::requirement::Requirement& req, randomizer::logic::world::World* world)
{
randomizer::logic::item::Item* item;
randomizer::logic::item::Item* heartPiece;
randomizer::logic::item::Item* heartContainer;
int count;
int macroIndex;
switch (req._type)
{
case Type::NOTHING:
return true;
case Type::IMPOSSIBLE:
return false;
case Type::OR:
return std::any_of(
req._args.begin(),
req._args.end(),
[&](const auto& arg)
{ return EvaluateSimpleRequirement(std::get<Requirement>(arg), world); });
case Type::AND:
return std::all_of(
req._args.begin(),
req._args.end(),
[&](const auto& arg)
{ return EvaluateSimpleRequirement(std::get<Requirement>(arg), world); });
case Type::ITEM:
item = std::get<randomizer::logic::item::Item*>(req._args[0]);
return randomizer::utility::container::ElementInContainer(world->GetStartingItemPool(), item);
case Type::COUNT:
count = std::get<int>(req._args[0]);
item = std::get<randomizer::logic::item::Item*>(req._args[1]);
return std::ranges::count(world->GetStartingItemPool(), item) >= count;
case Type::MACRO:
macroIndex = std::get<int>(req._args[0]);
return EvaluateSimpleRequirement(world->GetMacro(macroIndex), world);
case Type::GOLDEN_BUGS:
count = std::get<int>(req._args[0]);
return std::ranges::count_if(world->GetStartingItemPool(),
[](const auto& item) { return item->IsGoldenBug(); }) >= count;
case Type::HEARTS:
count = std::get<int>(req._args[0]);
heartPiece = world->GetItem("Piece of Heart");
heartContainer = world->GetItem("Heart Container");
return std::ranges::count(world->GetStartingItemPool(), heartPiece) +
std::ranges::count(world->GetStartingItemPool(), heartContainer) * 5 >= count * 5;
default:
return false;
}
return false;
}
bool EvaluateRequirementAtFormTime(const randomizer::logic::requirement::Requirement& req,
randomizer::logic::search::Search* search,
const int& formTime,
randomizer::logic::world::World* world)
{
randomizer::logic::item::Item* item;
randomizer::logic::item::Item* heartPiece;
randomizer::logic::item::Item* heartContainer;
int count;
int eventIndex;
int macroIndex;
@@ -513,6 +616,37 @@ namespace randomizer::logic::requirement
return std::count_if(search->_ownedItems.begin(),
search->_ownedItems.end(),
[](const auto& item) { return item->IsGoldenBug(); }) >= count;
case Type::HEARTS:
count = std::get<int>(req._args[0]);
heartPiece = world->GetItem("Piece of Heart");
heartContainer = world->GetItem("Heart Container");
return search->_ownedItems.count(heartPiece) +
(search->_ownedItems.count(heartContainer) + 3) * 5 >= count * 5;
case Type::DUNGEONS_COMPLETED:
count = std::get<int>(req._args[0]);
return std::ranges::count_if(search->_ownedEvents, [&](int eventId){
std::list<std::string> dungeonCompletionEvents = {
"Can Complete Forest Temple",
"Can Complete Goron Mines",
"Can Complete Lakebed Temple",
"Can Complete Arbiters Grounds",
"Can Complete Snowpeak Ruins",
"Can Complete Temple of Time",
"Can Complete City in the Sky",
"Can Complete Palace of Twilight"
};
for (const auto& eventName : dungeonCompletionEvents)
{
if (world->GetEventIndex(eventName) == eventId)
{
return true;
}
}
return false;
}) >= count;
default:
return false;
}
@@ -534,7 +668,7 @@ namespace randomizer::logic::requirement
// Some exits in the middle of entrance shuffling will not have a connected area. Ignore these
if (exit->GetConnectedArea() == nullptr)
{
return EvalSuccess::UNNECESSARY;
return EvalSuccess::DISCONNECTED;
}
// If the exit is currently disabled, don't try it
@@ -621,6 +755,36 @@ namespace randomizer::logic::requirement
return evalSuccess;
}
EvalSuccess EvaluateDisconnectedExitRequiremrnt(randomizer::logic::search::Search* search, randomizer::logic::entrance::Entrance* exit)
{
// If the exit is currently disabled, don't try it
if (exit->IsDisabled())
{
return EvalSuccess::NONE;
}
auto& exitFormTimeCache = exit->GetWorld()->GetExitTimeFormCache();
auto parentArea = exit->GetParentArea();
auto parentAreaFormTime = search->_areaFormTime[parentArea];
// Check each form time individually and spread the ones which succeed. If any of them pass, set the evaluation success
// to partial.
auto evalSuccess = EvalSuccess::NONE;
const auto& formTimes = FormTime::ALL_FORM_TIMES;
for (const auto& formTime : formTimes)
{
if (formTime & parentAreaFormTime)
{
if (EvaluateRequirementAtFormTime(exit->GetRequirement(), search, formTime, exit->GetWorld()))
{
return EvalSuccess::PARTIAL;
}
}
}
return EvalSuccess::NONE;
}
EvalSuccess EvaluateLocationRequirement(randomizer::logic::search::Search* search, randomizer::logic::area::LocationAccess* locAccess)
{
auto& formTime = search->_areaFormTime[locAccess->GetArea()];
+13 -1
View File
@@ -51,6 +51,8 @@ namespace randomizer::logic::requirement
WOLF_LINK,
TWILIGHT,
GOLDEN_BUGS,
HEARTS,
DUNGEONS_COMPLETED,
};
enum class EvalSuccess
@@ -58,7 +60,7 @@ namespace randomizer::logic::requirement
NONE,
PARTIAL,
COMPLETE,
UNNECESSARY,
DISCONNECTED,
};
// FormTime is a set of flags that cover all the possible cases of human-wolf/day-night combinations that are needed
@@ -101,12 +103,22 @@ namespace randomizer::logic::requirement
randomizer::logic::world::World* world,
const bool& forceLogic = false);
/**
* @brief Evaluates a requirement assuming it meets a simplistic criteria. This is used
* for checking settings when reading them in from, for example, startflags.yaml
*
* @param req - The simple requirement
* @return true if the requirment holds, false otherwise
*/
bool EvaluateSimpleRequirement(const randomizer::logic::requirement::Requirement& req, randomizer::logic::world::World* world);
bool EvaluateRequirementAtFormTime(const randomizer::logic::requirement::Requirement& req,
randomizer::logic::search::Search* search,
const int& formTime,
randomizer::logic::world::World*);
EvalSuccess EvaluateEventRequirement(randomizer::logic::search::Search* search, randomizer::logic::area::EventAccess* event);
EvalSuccess EvaluateExitRequirement(randomizer::logic::search::Search* search, randomizer::logic::entrance::Entrance* exit);
EvalSuccess EvaluateDisconnectedExitRequiremrnt(randomizer::logic::search::Search* search, randomizer::logic::entrance::Entrance* exit);
EvalSuccess EvaluateLocationRequirement(randomizer::logic::search::Search* search,
randomizer::logic::area::LocationAccess* locAccess);
+17 -8
View File
@@ -140,13 +140,9 @@ namespace randomizer::logic::search
continue;
}
// If the exit is unnecessary, we'll just consider it successful and move on
// If the exit is successful
auto evalSuccess = randomizer::logic::requirement::EvaluateExitRequirement(this, exit);
if (evalSuccess == randomizer::logic::requirement::EvalSuccess::UNNECESSARY)
{
this->_successfulExits.insert(exit);
}
else if (randomizer::utility::general::IsAnyOf(evalSuccess,
if (randomizer::utility::general::IsAnyOf(evalSuccess,
randomizer::logic::requirement::EvalSuccess::COMPLETE,
randomizer::logic::requirement::EvalSuccess::PARTIAL))
{
@@ -305,9 +301,9 @@ namespace randomizer::logic::search
this->Explore(exit->GetConnectedArea());
}
case randomizer::logic::requirement::EvalSuccess::NONE:
[[fallthrough]];
case randomizer::logic::requirement::EvalSuccess::DISCONNECTED:
this->_exitsToTry.push_back(exit);
case randomizer::logic::requirement::EvalSuccess::UNNECESSARY:
this->_foundDisconnectedExit = true;
}
}
}
@@ -376,6 +372,19 @@ namespace randomizer::logic::search
}
}
bool Search::HasAccessibleDisconnectedExit()
{
for (const auto& exit : this->_exitsToTry)
{
if (exit->GetConnectedArea() == nullptr &&
randomizer::logic::requirement::EvaluateDisconnectedExitRequiremrnt(this, exit) != requirement::EvalSuccess::NONE)
{
return true;
}
}
return false;
}
void Search::RemoveEmptySpheres()
{
// Get rid of any empty spheres in both the item playthrough and entrance playthrough
+1 -1
View File
@@ -115,6 +115,7 @@ namespace randomizer::logic::search
void ExpandFormTimes(randomizer::logic::area::Area* area);
void AddExitToEntranceSpheres(randomizer::logic::entrance::Entrance*);
bool HasAccessibleDisconnectedExit();
void RemoveEmptySpheres();
/**
@@ -143,7 +144,6 @@ namespace randomizer::logic::search
std::unordered_set<randomizer::logic::area::Area*> _visitedAreas;
std::unordered_set<randomizer::logic::entrance::Entrance*> _successfulExits;
std::unordered_set<randomizer::logic::entrance::Entrance*> _playthroughEntrances;
bool _foundDisconnectedExit = false;
std::list<std::list<randomizer::logic::location::Location*>> _playthroughSpheres;
std::list<std::list<randomizer::logic::entrance::Entrance*>> _entranceSpheres;
+19 -13
View File
@@ -493,11 +493,7 @@ namespace randomizer::logic::world
bool World::EvaluateSettingCondition(const std::string& condition)
{
auto req = randomizer::logic::requirement::ParseRequirementString(condition, this, true);
if (req._type == requirement::Type::NOTHING)
{
return true;
}
return false;
return requirement::EvaluateSimpleRequirement(req, this);
}
void World::GenerateItemPools()
@@ -540,11 +536,14 @@ namespace randomizer::logic::world
if ((this->Setting("Small Keys") == "Vanilla" &&
(originalItem->IsDungeonSmallKey() ||
randomizer::utility::str::Contains(originalItemName, "Ordon Pumpkin", "Ordon Cheese"))) ||
// Vanilla Big Keys
(this->Setting("Big Keys") == "Vanilla" && originalItem->IsBigKey()) ||
// Vanilla Big Keys (only include Hyrule Castle Big Key if it has no requirements)
(this->Setting("Big Keys") == "Vanilla" && originalItem->IsBigKey() &&
(originalItemName != "Hyrule Castle Big Key" || this->Setting("Hyrule Castle Big Key Requirements") == "None")) ||
// Vanilla Maps and Compasses
(this->Setting("Maps and Compasses") == "Vanilla" &&
(originalItem->IsDungeonMap() || originalItem->IsCompass())) ||
// Hyrule Castle Big Key
(originalItemName == "Hyrule Castle Big Key" && this->Setting("Hyrule Castle Big Key Requirements") != "None") ||
// Vanilla Poe Souls
(originalItemName == "Poe Soul" &&
(this->Setting("Poe Souls") == "Vanilla" ||
@@ -1134,15 +1133,22 @@ namespace randomizer::logic::world
return this->_macros.at(macroIndex);
}
int World::GetEventIndex(const std::string& eventName)
int World::GetEventIndex(const std::string& eventName, bool addIfNone /*= true*/)
{
// Add the event if it doesn't exist yet
// If the event doesn't exist
if (!this->_eventIndexes.contains(eventName))
{
auto index = this->_randomizer->GetNewEventID();
this->_eventIndexes.emplace(eventName, index);
this->_eventNames.emplace(index, eventName);
LOG_TO_DEBUG("Event \"" + eventName + "\" was assigned eventIndex " + std::to_string(index));
if (addIfNone)
{
auto index = this->_randomizer->GetNewEventID();
this->_eventIndexes.emplace(eventName, index);
this->_eventNames.emplace(index, eventName);
LOG_TO_DEBUG("Event \"" + eventName + "\" was assigned eventIndex " + std::to_string(index));
}
else
{
throw std::runtime_error("Event \"" + eventName + "\" does not exist");
}
}
return this->_eventIndexes.at(eventName);
+1 -1
View File
@@ -136,7 +136,7 @@ namespace randomizer::logic::world
int GetMacroIndex(const std::string& macroName) const;
const randomizer::logic::requirement::Requirement& GetMacro(const int& macroIndex);
int GetEventIndex(const std::string& eventName);
int GetEventIndex(const std::string& eventName, bool addIfNone = true);
std::string GetEventName(const int& eventIndex);
randomizer::seedgen::settings::Setting& Setting(const std::string& settingName);
+1 -1
View File
@@ -27,7 +27,7 @@ namespace randomizer::test::test
}
catch(const std::exception& e) {
std::cout << "Test \"" << testName << "\" failed! Failed settings saved to " << SETTINGS_PATH << std::endl;
std::cout << "Error Message: " << std::endl;
std::cout << "Error Message: " << e.what() << std::endl;
throw e;
}