mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-10 18:46:45 -04:00
197 lines
6.8 KiB
C++
197 lines
6.8 KiB
C++
#pragma once
|
|
|
|
#include "item_pool.hpp"
|
|
#include "requirement.hpp"
|
|
#include "location.hpp"
|
|
#include "../utility/log.hpp"
|
|
|
|
#include <unordered_set>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
// Forward Declarations (we have a lot here)
|
|
namespace randomizer
|
|
{
|
|
class Randomizer;
|
|
}
|
|
|
|
namespace randomizer::logic::world
|
|
{
|
|
class World;
|
|
using WorldPool = std::vector<std::unique_ptr<World>>;
|
|
} // namespace randomizer::logic::world
|
|
|
|
namespace randomizer::logic::item
|
|
{
|
|
class Item;
|
|
}
|
|
|
|
namespace randomizer::logic::area
|
|
{
|
|
class EventAccess;
|
|
class LocationAccess;
|
|
class Area;
|
|
} // namespace randomizer::logic::area
|
|
|
|
namespace randomizer::logic::entrance
|
|
{
|
|
class Entrance;
|
|
}
|
|
|
|
namespace randomizer::logic::search
|
|
{
|
|
enum class SearchMode
|
|
{
|
|
NO_SEARCH,
|
|
ACCESSIBLE_LOCATIONS,
|
|
GAME_BEATABLE,
|
|
ALL_LOCATIONS_REACHABLE,
|
|
GENERATE_PLAYTHROUGH,
|
|
SPHERE_ZERO,
|
|
TRACKER_SPHERES,
|
|
LOCATION_IMPORTANCE,
|
|
};
|
|
|
|
class Search
|
|
{
|
|
public:
|
|
Search();
|
|
Search(const SearchMode& searchMode,
|
|
world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1,
|
|
bool startingInventory = true,
|
|
location::Location* importanceLocation = nullptr);
|
|
|
|
static auto Accessible(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::ACCESSIBLE_LOCATIONS, worlds, items, worldToSearch);
|
|
}
|
|
|
|
static auto AccessibleNoStartingInventory(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::ACCESSIBLE_LOCATIONS, worlds, items, worldToSearch, false);
|
|
}
|
|
|
|
static auto AllLocationsReachable(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::ALL_LOCATIONS_REACHABLE, worlds, items, worldToSearch);
|
|
}
|
|
|
|
static auto Playthrough(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::GENERATE_PLAYTHROUGH, worlds, items, worldToSearch);
|
|
}
|
|
|
|
static auto Beatable(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::GAME_BEATABLE, worlds, items, worldToSearch);
|
|
}
|
|
|
|
static auto SphereZero(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::SPHERE_ZERO, worlds, items, worldToSearch);
|
|
}
|
|
|
|
static auto LocationImportance(world::WorldPool* worlds,
|
|
location::Location* importanceLocation,
|
|
const item_pool::ItemPool& items = {},
|
|
const int& worldToSearch = -1)
|
|
{
|
|
return Search(SearchMode::LOCATION_IMPORTANCE, worlds, items, worldToSearch, false, importanceLocation);
|
|
}
|
|
|
|
void SearchWorlds();
|
|
|
|
/**
|
|
* @brief Loop through and see if there are any events that are now accessible. Add them to the ownedEvents list if
|
|
* they are.
|
|
*
|
|
*/
|
|
void ProcessEvents();
|
|
void ProcessExits();
|
|
void ProcessLocations(std::list<area::LocationAccess*>& itemLocations);
|
|
void ProcessLocation(location::Location* location);
|
|
void Explore(area::Area* area);
|
|
void ExpandFormTimes(area::Area* area);
|
|
|
|
void AddExitToEntranceSpheres(entrance::Entrance*);
|
|
bool HasAccessibleDisconnectedExit();
|
|
void RemoveEmptySpheres();
|
|
|
|
/**
|
|
* @brief Will dump a file which can be turned into a visual graph using graphviz
|
|
* https://graphviz.org/download/
|
|
* Use this command to generate the graph: "dot -Tsvg <filename> -o world.svg"
|
|
* Then, open world.svg in a browser and CTRL + F to find the area of interest
|
|
*/
|
|
void DumpWorldGraph(const int& world = 0);
|
|
|
|
SearchMode _searchMode;
|
|
world::WorldPool* _worlds;
|
|
int _worldToSearch = -1;
|
|
|
|
// Search variables
|
|
int _sphereNum = 0;
|
|
bool _newThingsFound = true;
|
|
bool _isBeatable = false;
|
|
bool _collectItems = true;
|
|
bool _startingInventory = true;
|
|
std::unordered_set<int> _ownedEvents;
|
|
std::unordered_multiset<item::Item*> _ownedItems;
|
|
|
|
std::list<area::EventAccess*> _eventsToTry;
|
|
std::list<entrance::Entrance*> _exitsToTry;
|
|
std::unordered_set<location::Location*> _visitedLocations;
|
|
std::unordered_set<area::Area*> _visitedAreas;
|
|
std::unordered_set<entrance::Entrance*> _successfulExits;
|
|
std::unordered_set<entrance::Entrance*> _playthroughEntrances;
|
|
|
|
std::list<std::list<location::Location*>> _playthroughSpheres;
|
|
std::list<std::list<entrance::Entrance*>> _entranceSpheres;
|
|
|
|
std::unordered_map<area::Area*, int> _areaFormTime;
|
|
|
|
// Variables used for Location Importance searches
|
|
std::unordered_multiset<item::Item*> _itemsAtStart{};
|
|
bool _onlySearchWithItemsAtStart = false;
|
|
int _assumedHeartCount = 0;
|
|
requirement::Requirement _assumedFalseReq = requirement::IMPOSSIBLE_REQUIREMENT;
|
|
location::Location* _importanceLocation = nullptr;
|
|
};
|
|
|
|
/**
|
|
* @brief Verifies that necessary logic for all worlds is satisfied.
|
|
*
|
|
* @param worlds The worlds to verify logic for
|
|
* @param items The pool of items that haven't been placed yet
|
|
*
|
|
* @return An optional value that holds a string explaining why the logic was not satisfied if validation failed
|
|
*/
|
|
std::optional<std::string> VerifyLogic(world::WorldPool* worlds,
|
|
const item_pool::ItemPool& items = {});
|
|
void GeneratePlaythrough(randomizer::Randomizer* randomizer);
|
|
bool GameBeatable(world::WorldPool* worlds, const item_pool::ItemPool& items = {});
|
|
|
|
/**
|
|
* @brief Returns the pool of hint signs that the passed in location can be hinted at.
|
|
* We don't want a hint sign to hint a location which is logically required to access
|
|
* itself, as that is logically useless information.
|
|
*/
|
|
location::LocationPool GetPossibleHintSigns(location::Location* location);
|
|
} // namespace randomizer::logic::search
|