diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 5eee3541a..d33987f02 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -337,6 +337,7 @@ void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) { loc->SetCheckStatus(RCSHOW_COLLECTED); CheckTracker::SpoilAreaFromCheck(randomizerQueuedCheck); CheckTracker::RecalculateAllAreaTotals(); + CheckTracker::RecalculateAccessibleChecks(); SaveManager::Instance->SaveSection(gSaveContext.fileNum, SECTION_ID_TRACKER_DATA, true); randomizerQueuedCheck = RC_UNKNOWN_CHECK; randomizerQueuedItemEntry = GET_ITEM_NONE; diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 00e0366ab..a3560859e 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -228,5 +228,14 @@ void ItemLocation::ResetVariables() { areas = {}; status = RCSHOW_UNCHECKED; isSkipped = false; + isAccessible = false; +} + +bool ItemLocation::IsAccessible() const { + return isAccessible; +} + +void ItemLocation::SetAccessible(bool isAccessible_) { + isAccessible = isAccessible_; } } \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/item_location.h b/soh/soh/Enhancements/randomizer/item_location.h index 142ac1c0b..7a4c0b286 100644 --- a/soh/soh/Enhancements/randomizer/item_location.h +++ b/soh/soh/Enhancements/randomizer/item_location.h @@ -56,6 +56,8 @@ class ItemLocation { bool IsFoolishCandidate() const; void SetBarrenCandidate(); void ResetVariables(); + bool IsAccessible() const; + void SetAccessible(bool isAccessible_); private: RandomizerCheck rc; @@ -76,5 +78,6 @@ class ItemLocation { bool barrenCandidate = false; RandomizerCheckStatus status = RCSHOW_UNCHECKED; bool isSkipped = false; + bool isAccessible = false; }; } // namespace Rando \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h index 986d08d6a..788a1ca70 100644 --- a/soh/soh/Enhancements/randomizer/location_access.h +++ b/soh/soh/Enhancements/randomizer/location_access.h @@ -196,9 +196,15 @@ class Region { bool pastAdult = logic->IsAdult; bool pastChild = logic->IsChild; - //set age access as this areas ages - logic->IsChild = Child(); - logic->IsAdult = Adult(); + if (logic->mSaveContext != nullptr) { + logic->IsChild = logic->mSaveContext->linkAge == LinkAge::LINK_AGE_CHILD; + logic->IsAdult = logic->mSaveContext->linkAge == LinkAge::LINK_AGE_ADULT; + } + else { + //set age access as this areas ages + logic->IsChild = Child(); + logic->IsAdult = Adult(); + } //heck condition as well as having at least child or adult access bool hereVal = condition() && (logic->IsAdult || logic->IsChild); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index e3b07b672..d20d3342e 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -8,6 +8,7 @@ #include "soh/ResourceManagerHelpers.h" #include "soh/SohGui/UIWidgets.hpp" #include "dungeon.h" +#include "entrance.h" #include "location_access.h" #include @@ -821,6 +822,16 @@ void LoadFile() { SaveManager::Instance->LoadData("areasSpoiled", areasSpoiled, (uint32_t)0); UpdateAllOrdering(); UpdateAllAreas(); + + if (gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2) { + if (areaTable[RR_ROOT].regionName.empty()) { + RegionTable_Init(); + } + if (Rando::Context::GetInstance() == nullptr) { + Rando::Context::CreateInstance(); + } + RecalculateAccessibleChecks(); + } } void Teardown() { @@ -1623,7 +1634,13 @@ void DrawLocation(RandomizerCheck rc) { if (conditionStr != "true") { UIWidgets::InsertHelpHoverText(conditionStr); } - return; + if (!itemLoc->HasObtained() && itemLoc->IsAccessible()) { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f)); + ImGui::SameLine(); + ImGui::Text(" (Accessible)"); + ImGui::PopStyleColor(); + } + break; } } } @@ -1713,6 +1730,98 @@ void ImGuiDrawTwoColorPickerSection(const char* text, const char* cvarMainName, } } +void CalculateAccessibleEntrances(const Region& region, + bool isParentAccessible, + std::unordered_map& entranceAccessible, + std::vector& visitedRegions, + std::stop_token stopToken) { + for (const auto& entranceInRegion : region.exits) { + if (stopToken.stop_requested()) { + return; + } + + auto pair = entranceAccessible.find(&entranceInRegion); + bool isEntranceAccessible = true; + if (pair == entranceAccessible.end()) { + isEntranceAccessible = isParentAccessible && entranceInRegion.GetConditionsMet(); + entranceAccessible[&entranceInRegion] = isEntranceAccessible; + } else if (!pair->second) { + isEntranceAccessible = isParentAccessible && entranceInRegion.GetConditionsMet(); + pair->second = isEntranceAccessible; + } + else { + return; + } + + if (std::find(visitedRegions.begin(), visitedRegions.end(), entranceInRegion.GetConnectedRegionKey()) == visitedRegions.end()) { + visitedRegions.emplace_back(entranceInRegion.GetConnectedRegionKey()); + CalculateAccessibleEntrances(*entranceInRegion.GetConnectedRegion(), + isEntranceAccessible, + entranceAccessible, + visitedRegions, + stopToken); + visitedRegions.pop_back(); + } + } +} + +void _RecalculateAccessibleChecks(std::stop_token stopToken) { + logic->IsChild = logic->mSaveContext->linkAge == LinkAge::LINK_AGE_CHILD; + logic->IsAdult = logic->mSaveContext->linkAge == LinkAge::LINK_AGE_ADULT; + logic->AtDay = true; + logic->AtNight = true; + + for (auto& region : areaTable) { + for (auto& event : region.events) { + if (!event.GetEvent() && event.ConditionsMet()) { + event.EventOccurred(); + } + } + } + + if (stopToken.stop_requested()) { + return; + } + + std::vector visitedRegions; + visitedRegions.reserve(70); + std::unordered_map entranceAccessible; + entranceAccessible.reserve(1450); + CalculateAccessibleEntrances(areaTable[RR_ROOT], true, entranceAccessible, visitedRegions, stopToken); + + if (stopToken.stop_requested()) { + return; + } + + for (auto& region : areaTable) { + for (auto& locationInRegion : region.locations) { + auto rc = locationInRegion.GetLocation(); + auto itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc); + if (!itemLoc->HasObtained()) { + bool regionAccessible = false; + for (auto& entranceInRegion : region.entrances) { + if (entranceAccessible[entranceInRegion]) { + regionAccessible = true; + break; + } + } + bool locationAccessible = locationInRegion.GetConditionsMet(); + itemLoc->SetAccessible(regionAccessible && locationAccessible); + } + } + } +} + +std::jthread recalculateAccessibleChecksThread; + +void RecalculateAccessibleChecks() { + if (recalculateAccessibleChecksThread.joinable()) { + recalculateAccessibleChecksThread.request_stop(); + recalculateAccessibleChecksThread.join(); + } + recalculateAccessibleChecksThread = std::jthread(_RecalculateAccessibleChecks); +} + void CheckTrackerWindow::Draw() { if (!IsVisible()) { return; diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h index 851910489..57178ebed 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h @@ -60,4 +60,5 @@ void UpdateAllOrdering(); void UpdateAllAreas(); void RecalculateAllAreaTotals(); void SpoilAreaFromCheck(RandomizerCheck rc); +void RecalculateAccessibleChecks(); } // namespace CheckTracker