#pragma once #include "area.hpp" #include "dungeon.hpp" #include "item.hpp" #include "item_pool.hpp" #include "location.hpp" #include "requirement.hpp" #include "hint_types.hpp" #include "../seedgen/settings.hpp" #include "../utility/log.hpp" #include "../utility/text.hpp" #include #include #include #include // Forward Declarations namespace randomizer { class Randomizer; } namespace randomizer::logic::search { class Search; } namespace randomizer::logic::world { class World; using WorldPool = std::vector>; class World { public: World(const int& id, Randomizer* randomizer); int GetID() const; void SetSettings(const seedgen::settings::Settings& settings); const seedgen::settings::Settings& GetSettings() const; void SetRandomizer(Randomizer* randomizer); Randomizer* GetRandomizer() const; /** * @brief Resolves all remaining random settings within a specific world */ void ResolveRandomSettings(); /** * @brief Resolves settings that conflict with each other. Ideally will only resolve settings that conflict due to * having their current option randomly chosen. */ void ResolveConflictingSettings(); void Build(); void BuildItemTable(); void BuildLocationTable(); void LoadLogicMacros(); void LoadWorldGraph(); bool EvaluateSettingCondition(const std::string& condition); /** * @brief Generate the main item pool and starting item pool for this world. */ void GenerateItemPools(); /** * @brief Decides if a location should be removed depending on settings. * @param locationName The name of the location * @param originalItemName The name of the original item at the location * * @return true if the location should be removed. False otherwise */ bool ShouldRemoveLocation(const std::string& locationName, const std::string& originalItemName); /** * @brief Perform all tasks which must be complete before shuffling entrances. */ void PerformPreEntranceShuffleTasks(); void PlaceVanillaItems(); void PlacePlandomizerItems(); void SetNonProgressLocations(); void SetTrackerNonProgressLocations(); /** * @brief Perform all tasks which require shuffled entrances to be set, but before running the main item placement * algorithm. */ void PerformPostEntranceShuffleTasks(); void AssignAreaProperties(); void AssignGoalLocations(); /** * @brief Forbid items from being in certain locations depending on settings */ void SetForbiddenItems(); /** * @brief STUB: Would choose required dungeons ahead of placing any non-vanilla and non-plandomized items. Not really * required unless we let users choose a specific amount of directly required dungeons */ 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 * progression status set to false. */ void DetermineRequiredDungeons(); /** * @brief Adds junk to the main pool until the number of items in the pool matches the total number of * currently empty locations. */ void SanitizeItemPool(); void SetSearchStartingProperties(search::Search* search) const; void PerformPostFillTasks(); void FinalizeBottleContents(); void AddPlandomizedLocation(location::Location* location, item::Item* item); void AddPlandomizedEntrance(entrance::Entrance* entrance, entrance::Entrance* target); std::unordered_map GetPlandomizerEntrances(); dungeon::Dungeon* GetDungeon(const std::string& name); const std::map>& GetDungeonTable() const; item::Item* GetItem(const std::string& name, const bool& ignoreError = false); item::Item* GetItem(uint16_t id, const bool& ignoreError = false); item::Item* GetShadowCrystal(); item::Item* GetGameWinningItem() const; item_pool::ItemPool& GetItemPool(); item_pool::ItemPool& GetStartingItemPool(); location::Location* GetLocation(const std::string& name); location::LocationPool GetAllLocations(const bool& includeNonItemLocations = false); location::LocationPool GetHintSignLocations(); area::Area* GetArea(const std::string& name, const bool& createIfNotFound = false); area::Area* GetRootArea() const; const std::map>& GetAreaTable() const; entrance::Entrance* GetEntrance(const std::string& originalName); int GetNewEntranceID(); entrance::EntrancePool GetShuffleableEntrances(const entrance::Type& type, bool onlyPrimary = false); entrance::EntrancePool GetShuffledEntrances( const entrance::Type& type = entrance::Type::ALL, bool onlyPrimary = false); std::unordered_map& GetExitTimeFormCache(); int GetMacroIndex(const std::string& macroName) const; const requirement::Requirement& GetMacro(const int& macroIndex); int GetEventIndex(const std::string& eventName, bool addIfNone = true); std::string GetEventName(const int& eventIndex); seedgen::settings::Setting& Setting(const std::string& settingName); bool AnyEntranceRandomizerEnabled(); TextDatabase& GetTextDatabase() { return this->_textDatabase; } const std::string& GetText(const std::string& name, Text::Type type = Text::STANDARD, Text::Language language = Text::ENGLISH) { if (!this->_textDatabase.at(name).at(type).mText.at(language).empty()) { return this->_textDatabase.at(name).at(type).mText.at(language); } return this->_textDatabase.at(name).at(type).mText.at(Text::ENGLISH); } Text& GetTextObject(const std::string& name, Text::Type type = Text::STANDARD) { if (!this->_textDatabase.contains(name)) { throw std::runtime_error(name + " is not a text object in world " + std::to_string(this->_id)); } return this->_textDatabase[name][type]; } // Make a new custom text entry for this world specifically and return a reference to it Text& AddNewText(const std::string& name, Text::Type type = Text::STANDARD) { return this->_textDatabase[name][type]; } void AddGoalLocation(location::Location* location) { this->_goalLocations.push_back(location); } const auto& GetGoalLocations() {return this->_goalLocations;} auto& GetBarrenRegions() { return this->_barrenRegions;} auto& GetMidnaHints() { return this->_midnaHints;} auto& GetHintSignHints() { return this->_hintSignHints;} private: int _id = -1; int _entranceIdCounter = 0; seedgen::settings::Settings _settings; std::map> _itemTable = {}; std::map _itemIdTable = {}; std::map> _locationTable = {}; std::unordered_set _intentionallyRemovedLocations = {}; std::unordered_set _registeredLocationCategories = {}; std::map> _areaTable = {}; std::map> _dungeons = {}; std::map _macros = {}; std::unordered_map _macroIndexes = {}; std::unordered_map _eventIndexes = {}; std::unordered_map _eventNames = {}; item_pool::ItemPool _itemPool = {}; item_pool::ItemPool _startingItemPool = {}; std::unordered_map _exitTimeFormCache = {}; // Custom text for this world specifically TextDatabase _textDatabase = {}; // Plandomizer Data std::unordered_map _plandomizerLocations = {}; std::unordered_map _plandomizerEntrances = {}; // Hint stuff std::list _goalLocations = {}; std::map> _barrenRegions = {}; std::vector _midnaHints{}; std::unordered_map> _hintSignHints = {}; Randomizer* _randomizer = nullptr; }; } // namespace randomizer::logic::world