diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index a07c27600..3aef7a3b7 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -230,6 +230,10 @@ bool Entrance::DoesSpreadAreas() { return spreadsAreasWithPriority; } +std::string Entrance::GetConditionStr() const { + return condition_str; +} + EntranceShuffler::EntranceShuffler() { playthroughEntrances = {}; entranceOverrides = {}; diff --git a/soh/soh/Enhancements/randomizer/entrance.h b/soh/soh/Enhancements/randomizer/entrance.h index ba16abd6e..79f276746 100644 --- a/soh/soh/Enhancements/randomizer/entrance.h +++ b/soh/soh/Enhancements/randomizer/entrance.h @@ -82,6 +82,7 @@ class Entrance { Entrance* GetNewTarget(); Entrance* AssumeReachable(); bool DoesSpreadAreas(); + std::string GetConditionStr() const; private: RandomizerRegion parentRegion; diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index 1912ef75e..6596f2591 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -13,6 +13,7 @@ #include #include "3drando/shops.hpp" +#include extern "C" { extern PlayState* gPlayState; } @@ -796,7 +797,7 @@ void RegionTable_Init() { }, { //Locations LOCATION(RC_LINKS_POCKET, true), - LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->ship.quest.data.randomizer.triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Get() + 1;), + LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->ship.quest.data.randomizer.triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Get() + 1), LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), }, { //Exits @@ -906,6 +907,22 @@ void RegionTable_Init() { exit.GetConnectedRegion()->entrances.push_front(&exit); } } + + std::ostringstream ss; + + for (uint32_t i = RR_ROOT; i <= RR_GANONS_CASTLE; i++) { + for (EventAccess& eventAccess : areaTable[i].events) { + ss << eventAccess.GetConditionStr() << std::endl; + } + for (LocationAccess& locPair : areaTable[i].locations) { + ss << locPair.GetConditionStr() << std::endl; + } + for (Entrance& exit : areaTable[i].exits) { + ss << exit.GetConditionStr() << std::endl; + } + } + + SPDLOG_INFO("All Conditions:\n{}", ss.str()); } void ReplaceFirstInString(std::string& s, std::string const& toReplace, std::string const& replaceWith) { @@ -938,11 +955,50 @@ void ReplaceAllInString(std::string& s, std::string const& toReplace, std::strin s.swap(buf); } +static void RemoveLambdaSyntax(std::string& s) { + std::regex lambdaIntro(R"(\[\s*.*?\s*\]\s*(?:\([^)]*\)\s*)?\{\s*return\s*(.*?);\s*\})"); + s = std::regex_replace(s, lambdaIntro, "$1"); +} + +static void UpdateIsDungeonCondition(std::string& s) { + std::regex lambdaIntro(R"(GetDungeon\((\w+)\)->Is(\w+)\(\))"); + s = std::regex_replace(s, lambdaIntro, "IsDungeon$2($1)"); +} + +static void UpdateIsTrialCondition(std::string& s) { + // GetTrial(TK_FOREST_TRIAL)->IsSkipped() + std::regex lambdaIntro(R"(GetTrial\((\w+)\)->Is(\w+)\(\))"); + s = std::regex_replace(s, lambdaIntro, "IsTrial$2($1)"); +} + +static void ReplaceOptionIs(std::string& s) { + std::regex optionIs(R"(\.Is\((\w+)\))"); + s = std::regex_replace(s, optionIs, " == $1"); +} + +static void ReplaceOptionIsNot(std::string& s) { + std::regex optionIs(R"(\.IsNot\((\w+)\))"); + s = std::regex_replace(s, optionIs, " != $1"); +} + +static void ReplaceRegionAgeTime(std::string& s) { + std::regex optionIs(R"(RegionTable\((\w+)\)->(\w+))"); + s = std::regex_replace(s, optionIs, "RegionAgeTimeAccess($1, RegionAgeTime::$2)"); +} + std::string CleanCheckConditionString(std::string condition) { ReplaceAllInString(condition, "logic->", ""); ReplaceAllInString(condition, "ctx->", ""); ReplaceAllInString(condition, ".Get()", ""); ReplaceAllInString(condition, "GetSaveContext()->", ""); + ReplaceAllInString(condition, "(bool)", ""); + RemoveLambdaSyntax(condition); + ReplaceAllInString(condition, "ship.quest.data.randomizer.triforcePiecesCollected", "TriforcePiecesCollected()"); + UpdateIsDungeonCondition(condition); + UpdateIsTrialCondition(condition); + ReplaceOptionIs(condition); + ReplaceOptionIsNot(condition); + ReplaceRegionAgeTime(condition); return condition; } diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h index ffc4d970c..9fabde876 100644 --- a/soh/soh/Enhancements/randomizer/location_access.h +++ b/soh/soh/Enhancements/randomizer/location_access.h @@ -50,6 +50,14 @@ class EventAccess { return *event; } + std::string GetEventStr() const { + return event_str; + } + + std::string GetConditionStr() const { + return condition_str; + } + private: bool* event; std::string event_str; diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp index 8ae22fd83..5328af38c 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp @@ -10,8 +10,8 @@ void RegionTable_Init_BottomOfTheWell() { areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Region("Bottom of the Well Entryway", SCENE_BOTTOM_OF_THE_WELL, {}, {}, { //Exits //Technically involves an fake wall, but passing it lensless is intended in vanilla and it is well telegraphed - ENTRANCE(RR_BOTTOM_OF_THE_WELL_PERIMETER, ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA)), - ENTRANCE(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && logic->IsChild), + ENTRANCE(RR_BOTTOM_OF_THE_WELL_PERIMETER, ctx->GetDungeon(BOTTOM_OF_THE_WELL)->IsVanilla() && logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA)), + ENTRANCE(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, ctx->GetDungeon(BOTTOM_OF_THE_WELL)->IsMQ() && logic->IsChild), ENTRANCE(RR_KAK_WELL, true), }); diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp index 501076350..207dd2b41 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp @@ -574,9 +574,9 @@ void RegionTable_Init_DodongosCavern() { // Events // Blue Fire Arrows need similar accuracy as hammer trick, only put in logic when both hammer & blue fire tricks enabled EVENT_ACCESS(DodongosCavernClear, Here(RR_DODONGOS_CAVERN_BOSS_ROOM, []{return logic->HasExplosives() || - (ctx->GetTrickOption(RT_DC_HAMMER_FLOOR) ? logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_BLUE_FIRE_MUD_WALLS) && logic->BlueFire()) : - ctx->GetTrickOption(RT_BLUE_FIRE_MUD_WALLS) && logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE));}) - && logic->CanKillEnemy(RE_KING_DODONGO)), + (ctx->GetTrickOption(RT_DC_HAMMER_FLOOR) ? logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_BLUE_FIRE_MUD_WALLS) && logic->BlueFire()) : + ctx->GetTrickOption(RT_BLUE_FIRE_MUD_WALLS) && logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE));}) + && logic->CanKillEnemy(RE_KING_DODONGO)), }, { // Locations LOCATION(RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, true), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp index 3774bd8ee..faa444900 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp @@ -585,7 +585,7 @@ void RegionTable_Init_FireTemple() { areaTable[RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE] = Region("Fire Temple MQ Maze Shortcut Cage", SCENE_FIRE_TEMPLE, {}, { //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, logic->OpenedUpperFireShortcut;), + LOCATION(RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, logic->OpenedUpperFireShortcut), LOCATION(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_1, logic->OpenedUpperFireShortcut && logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_2, logic->OpenedUpperFireShortcut && logic->CanBreakCrates()), LOCATION(RC_FIRE_TEMPLE_MQ_SHORTCUT_CRATE_3, logic->OpenedUpperFireShortcut && logic->CanBreakCrates()),