#include "area.hpp" #include "search.hpp" #include "world.hpp" #include #include #include namespace tphdr::logic::area { int LocationAccess::_idCounter = 0; int Area::_idCounter = 0; LocationAccess::LocationAccess(tphdr::logic::location::Location* loc, const tphdr::logic::requirement::Requirement& req, Area* area): _loc(loc), _req(std::move(req)), _area(area) { this->_id = this->_idCounter++; } tphdr::logic::location::Location* LocationAccess::GetLocation() const { return this->_loc; } const tphdr::logic::requirement::Requirement& LocationAccess::GetRequirement() { return this->_req; } Area* LocationAccess::GetArea() const { return this->_area; } int LocationAccess::GetID() const { return this->_id; } EventAccess::EventAccess(const tphdr::logic::requirement::Requirement& req, Area* area, const int& eventIndex): _req(std::move(req)), _area(area), _eventIndex(eventIndex) { } const tphdr::logic::requirement::Requirement& EventAccess::GetRequirement() { return this->_req; } Area* EventAccess::GetArea() const { return this->_area; } int EventAccess::GetEventIndex() const { return this->_eventIndex; } std::string EventAccess::GetName() const { return this->_area->GetWorld()->GetEventName(this->_eventIndex); } Area::Area(const std::string& name, tphdr::logic::world::World* world): _name(name), _world(world) { this->_id = this->_idCounter++; } std::string Area::GetName() const { return this->_name; } void Area::SetHardAssignedRegion(const std::string& _hardAssignedRegion) { this->_hardAssignedRegion = _hardAssignedRegion; } std::string Area::GetHardAssignRegion() const { return this->_hardAssignedRegion; } void Area::SetEvents(std::list>& events) { this->_events = std::move(events); } std::list Area::GetEvents() const { std::list events; for (const auto& event : this->_events) { events.emplace_back(event.get()); } return events; } void Area::SetLocations(std::list>& locations) { this->_locations = std::move(locations); } std::list Area::GetLocations() const { std::list locations; for (const auto& loc : this->_locations) { locations.emplace_back(loc.get()); } return locations; } void Area::SetExits(std::list>& exits) { this->_exits = std::move(exits); } std::list Area::GetExits() const { std::list exits; for (const auto& exit : this->_exits) { exits.emplace_back(exit.get()); } return exits; } void Area::AddExit(std::unique_ptr& exit) { this->_exits.push_back(std::move(exit)); } void Area::RemoveExit(tphdr::logic::entrance::Entrance* exit) { auto removed = std::remove_if(this->_exits.begin(), this->_exits.end(), [&](const auto& e) { return e.get() == exit; }); this->_exits.erase(removed, this->_exits.end()); } void Area::AddEntrance(tphdr::logic::entrance::Entrance* entrance) { this->_entrances.emplace_back(entrance); } void Area::RemoveEntrance(tphdr::logic::entrance::Entrance* entrance) { auto removed = std::remove(this->_entrances.begin(), this->_entrances.end(), entrance); this->_entrances.erase(removed, this->_entrances.end()); } std::list Area::GetEntrances() const { return this->_entrances; } tphdr::logic::world::World* Area::GetWorld() const { return this->_world; } void Area::SetCanChangeTime(const bool& canChangeTime) { this->_canChangeTime = canChangeTime; } bool Area::CanChangeTime() const { return this->_canChangeTime; } void Area::SetCanTransform(const bool& canTransform) { this->_canTransform = canTransform; } bool Area::CanTransform() const { return this->_canTransform; } void Area::AddHintRegion(const std::string& region) { this->_hintRegions.emplace(region); } std::set Area::GetHintRegions() { return this->_hintRegions; } void Area::SetTwilightCompletedMacroIndex(const int& macroIndex) { this->_twilightCompletedMacroIndex = macroIndex; } int Area::GetTwilightCompletedMacroIndex() const { return this->_twilightCompletedMacroIndex; } bool Area::TwilightCleared(tphdr::logic::search::Search* search) const { return this->_twilightCompletedMacroIndex == -1 || tphdr::logic::requirement::EvaluateRequirementAtFormTime( this->GetWorld()->GetMacro(this->_twilightCompletedMacroIndex), search, tphdr::logic::requirement::FormTime::ALL, this->GetWorld()); } void Area::AssignHintRegionsAndDungeonLocations() { std::set hintRegions = {}; std::unordered_set alreadyChecked = {}; std::list areaQueue = {this}; while (!areaQueue.empty()) { auto area = areaQueue.back(); areaQueue.pop_back(); alreadyChecked.insert(area); // If this area has a hard assigned region, then we won't assign it any other regions auto hardAssignedRegion = area->GetHardAssignRegion(); if (hardAssignedRegion != "") { // If the region is None, then don't assign it. None is meant to be a blocker that prevents other regions // from assigning themselves through this area if (hardAssignedRegion != "None") { hintRegions.insert(hardAssignedRegion); } continue; } // If this area isn't assigned any hint regions, add its entrancs' parent areas to the queue as long as they // haven't been checked yet for (const auto& entrance : area->GetEntrances()) { if (!alreadyChecked.contains(entrance->GetParentArea())) { areaQueue.push_back(entrance->GetParentArea()); } } } // When determining which regions to assign the area to, overworld regions will take complete priority over dungeon // regions. Dungeon regions should only be assigned if dungeons are the only regions listed. So if we have any overworld // hint regions, filter out the dungeon ones. const auto& dungeons = this->GetWorld()->GetDungeonTable(); std::set dungeonRegions = {}; std::copy_if(hintRegions.begin(), hintRegions.end(), std::inserter(dungeonRegions, dungeonRegions.begin()), [&](const auto& hintRegion) { return dungeons.contains(hintRegion); }); // If we have less dungeons than total hint regions, we have at least one overworld hint region // So erase all the dungeons in that case. if (dungeonRegions.size() < hintRegions.size()) { for (const auto& dungeon : dungeonRegions) { hintRegions.erase(dungeon); } } // Assign the found hint regions to the area for (const auto& region : hintRegions) { this->AddHintRegion(region); LOG_TO_DEBUG("Assigned \"" + region + "\" as hint region to \"" + this->GetName() + "\""); // Also assign any loactions in this area to the dungeon if there are any dungeon regions if (dungeons.contains(region)) { auto locAccs = this->GetLocations(); auto dungeon = this->GetWorld()->GetDungeon(region); for (const auto& locAcc : locAccs) { auto location = locAcc->GetLocation(); dungeon->AddLocation(location); } } } } } // namespace tphdr::logic::area