diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 08a196cefa..190017df95 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -27,6 +27,7 @@ #include "localisation/Localisation.h" #include "management/NewsItem.h" #include "network/network.h" +#include "./peep/GuestPathfinding.h" #include "platform/Platform.h" #include "profiling/Profiling.h" #include "ride/Vehicle.h" @@ -88,6 +89,9 @@ void GameState::InitAll(const TileCoordsXY& mapSize) CheatsReset(); ClearRestrictedScenery(); + // TODO: find a better place for this + gGuestPathfinder = new OriginalPathfinding(); + #ifdef ENABLE_SCRIPTING auto& scriptEngine = GetContext()->GetScriptEngine(); scriptEngine.ClearParkStorage(); diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index f95c868104..a096212f11 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -81,6 +81,7 @@ static void* _crowdSoundChannel = nullptr; static void peep_128_tick_update(Peep* peep, int32_t index); static void peep_release_balloon(Guest* peep, int16_t spawn_height); + static PeepActionSpriteType PeepSpecialSpriteToSpriteTypeMap[] = { PeepActionSpriteType::None, PeepActionSpriteType::HoldMat, @@ -2357,7 +2358,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (guest != nullptr) { - result = guest_path_finding(guest); + result = gGuestPathfinder->guest_path_finding(guest); } else { diff --git a/src/openrct2/entity/Peep.h b/src/openrct2/entity/Peep.h index b59201fc70..9ba98efbbb 100644 --- a/src/openrct2/entity/Peep.h +++ b/src/openrct2/entity/Peep.h @@ -399,7 +399,7 @@ public: // Peep bool IsActionInterruptable() const; // Reset the peep's stored goal, which means they will forget any stored pathfinding history - // on the next peep_pathfind_choose_direction call. + // on the next GuestPathfinding::peep_pathfind_choose_direction call. void ResetPathfindGoal(); void SetDestination(const CoordsXY& coords); diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index d703d79174..ae9a54904c 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -66,6 +66,8 @@ colour_t gStaffHandymanColour; colour_t gStaffMechanicColour; colour_t gStaffSecurityColour; +GuestPathfinding* gGuestPathfinder; + // Maximum manhattan distance that litter can be for a handyman to seek to it const uint16_t MAX_LITTER_DISTANCE = 3 * COORDS_XY_STEP; @@ -181,7 +183,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons } /* test_element is a path */ - if (!IsValidPathZAndDirection(test_element, adjacPos.z / COORDS_Z_STEP, adjac_dir)) + if (!GuestPathfinding::IsValidPathZAndDirection(test_element, adjacPos.z / COORDS_Z_STEP, adjac_dir)) continue; /* test_element is a connected path */ @@ -722,7 +724,7 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat PathfindLoggingEnable(this); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - Direction pathfindDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ NextLoc }, this); + Direction pathfindDirection = gGuestPathfinder->peep_pathfind_choose_direction(TileCoordsXYZ{ NextLoc }, this); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingDisable(); @@ -732,7 +734,7 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat { /* Heuristic search failed for all directions. * Reset the PathfindGoal - this means that the PathfindHistory - * will be reset in the next call to peep_pathfind_choose_direction(). + * will be reset in the next call to GuestPathfinding::peep_pathfind_choose_direction(). * This lets the heuristic search "try again" in case the player has * edited the path layout or the mechanic was already stuck in the * save game (e.g. with a worse version of the pathfinding). */ diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 3b4056ad3f..2739153716 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -289,7 +289,7 @@ static uint8_t footpath_element_next_in_direction(TileCoordsXYZ loc, PathElement continue; if (nextTileElement->GetType() != TileElementType::Path) continue; - if (!IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection)) + if (!GuestPathfinding::IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection)) continue; if (nextTileElement->AsPath()->IsWide()) return PATH_SEARCH_WIDE; @@ -382,7 +382,7 @@ static uint8_t footpath_element_dest_in_dir(TileCoordsXYZ loc, Direction chosenD break; case TileElementType::Path: { - if (!IsValidPathZAndDirection(tileElement, loc.z, chosenDirection)) + if (!GuestPathfinding::IsValidPathZAndDirection(tileElement, loc.z, chosenDirection)) continue; if (tileElement->AsPath()->IsWide()) return PATH_SEARCH_WIDE; @@ -824,7 +824,7 @@ static void peep_pathfind_heuristic_search( * queue path. * Otherwise, peeps walk on path tiles to get to the goal. */ - if (!IsValidPathZAndDirection(tileElement, loc.z, test_edge)) + if (!GuestPathfinding::IsValidPathZAndDirection(tileElement, loc.z, test_edge)) continue; // Path may be sloped, so set z to path base height. @@ -1261,7 +1261,7 @@ static void peep_pathfind_heuristic_search( * * rct2: 0x0069A5F0 */ -Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) +Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) { PROFILED_FUNCTION(); @@ -1661,7 +1661,7 @@ static std::optional GetNearestParkEntrance(const CoordsXY& loc) * * rct2: 0x006952C0 */ -static int32_t GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges) { // Send peeps to the nearest park entrance. auto chosenEntrance = GetNearestParkEntrance(peep->NextLoc); @@ -1710,7 +1710,7 @@ static uint8_t get_nearest_peep_spawn_index(uint16_t x, uint16_t y) * * rct2: 0x0069536C */ -static int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) { // Send peeps to the nearest spawn point. uint8_t chosenSpawn = get_nearest_peep_spawn_index(peep->NextLoc.x, peep->NextLoc.y); @@ -1741,7 +1741,7 @@ static int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) * * rct2: 0x00695161 */ -static int32_t GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges) { TileCoordsXYZ entranceGoal{}; if (peep->PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN) @@ -1971,7 +1971,7 @@ static StationIndex guest_pathfinding_select_random_station( * * rct2: 0x00694C35 */ -int32_t guest_path_finding(Guest* peep) +int32_t OriginalPathfinding::guest_path_finding(Guest* peep) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingEnable(peep); @@ -2266,7 +2266,7 @@ int32_t guest_path_finding(Guest* peep) return peep_move_one_tile(direction, peep); } -bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection) +bool GuestPathfinding::IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection) { if (tileElement->AsPath()->IsSloped()) { diff --git a/src/openrct2/peep/GuestPathfinding.h b/src/openrct2/peep/GuestPathfinding.h index 5c7fde32b4..3e409de77c 100644 --- a/src/openrct2/peep/GuestPathfinding.h +++ b/src/openrct2/peep/GuestPathfinding.h @@ -17,6 +17,8 @@ struct Peep; struct Guest; struct TileElement; + + // The tile position of the place the peep is trying to get to (park entrance/exit, ride // entrance/exit, or the end of the queue line for a ride). // @@ -37,19 +39,42 @@ extern RideId gPeepPathFindQueueRideIndex; // In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL. extern bool gPeepPathFindIgnoreForeignQueues; -// Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide -// the direction the peep should walk in from the current tile. -Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep); +class GuestPathfinding +{ +public: + // Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide + // the direction the peep should walk in from the current tile. + virtual Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) = 0; -// Test whether the given tile can be walked onto, if the peep is currently at height currentZ and -// moving in direction currentDirection. -bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); + // Test whether the given tile can be walked onto, if the peep is currently at height currentZ and + // moving in direction currentDirection. + static bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); -// Overall guest pathfinding AI. Sets up Peep::DestinationX/DestinationY (which they move to in a -// straight line, no pathfinding). Called whenever the guest has arrived at their previously set destination. -// -// Returns 0 if the guest has successfully had a new destination set up, nonzero otherwise. -int32_t guest_path_finding(Guest* peep); + // Overall guest pathfinding AI. Sets up Peep::DestinationX/DestinationY (which they move to in a + // straight line, no pathfinding). Called whenever the guest has arrived at their previously set destination. + // + // Returns 0 if the guest has successfully had a new destination set up, nonzero otherwise. + virtual int32_t guest_path_finding(Guest* peep) = 0; + +}; + +class OriginalPathfinding : public GuestPathfinding +{ +public: + Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep); + + int32_t guest_path_finding(Guest* peep); + +private: + int32_t GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges); + + int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges); + + int32_t GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges); +}; + +//TODO: Implement a better solution than a global variable for the utilized pathfinder +extern GuestPathfinding* gGuestPathfinder; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 # define PATHFIND_DEBUG \ diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index 8816d2a2d1..35beed443c 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -16,6 +16,7 @@ using namespace OpenRCT2; + static std::ostream& operator<<(std::ostream& os, const TileCoordsXYZ& coords) { return os << "(" << coords.x << ", " << coords.y << ", " << coords.z << ")"; @@ -84,7 +85,7 @@ protected: // Pick the direction the peep should initially move in, given the goal position. // This will also store the goal position and initialize pathfinding data for the peep. gPeepPathFindGoalPosition = goal; - const Direction moveDir = peep_pathfind_choose_direction(*pos, peep); + const Direction moveDir = gGuestPathfinder->peep_pathfind_choose_direction(*pos, peep); if (moveDir == INVALID_DIRECTION) { // Couldn't determine a direction to move off in