Merge pull request #17204 from LordOfLunacy/develop

I have picked up the task of preparing a rework of the pathfinding to allow for the addition of a new pathfinding implementation to the game. This initial pull request makes GuestPathfinding more modular by creating a GuestPathfinding base class and implementing the current pathfinding system into an OriginalPathfinding subclass.
This commit is contained in:
Ted John 2022-05-16 09:32:52 +01:00 committed by GitHub
commit 4adca3ba15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 125 deletions

View File

@ -9,6 +9,7 @@
#include "GameState.h" #include "GameState.h"
#include "./peep/GuestPathfinding.h"
#include "Context.h" #include "Context.h"
#include "Editor.h" #include "Editor.h"
#include "Game.h" #include "Game.h"

View File

@ -73,6 +73,8 @@ uint32_t gNextGuestNumber;
uint8_t gPeepWarningThrottle[16]; uint8_t gPeepWarningThrottle[16];
std::unique_ptr<GuestPathfinding> gGuestPathfinder = std::make_unique<OriginalPathfinding>();
static uint8_t _unk_F1AEF0; static uint8_t _unk_F1AEF0;
static TileElement* _peepRideEntranceExitElement; static TileElement* _peepRideEntranceExitElement;
@ -2357,7 +2359,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result)
if (guest != nullptr) if (guest != nullptr)
{ {
result = guest_path_finding(guest); result = gGuestPathfinder->CalculateNextDestination(*guest);
} }
else else
{ {

View File

@ -399,7 +399,7 @@ public: // Peep
bool IsActionInterruptable() const; bool IsActionInterruptable() const;
// Reset the peep's stored goal, which means they will forget any stored pathfinding history // 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::ChooseDirection call.
void ResetPathfindGoal(); void ResetPathfindGoal();
void SetDestination(const CoordsXY& coords); void SetDestination(const CoordsXY& coords);

View File

@ -181,7 +181,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons
} }
/* test_element is a path */ /* 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; continue;
/* test_element is a connected path */ /* test_element is a connected path */
@ -719,10 +719,10 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat
gPeepPathFindQueueRideIndex = RideId::GetNull(); gPeepPathFindQueueRideIndex = RideId::GetNull();
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingEnable(this); PathfindLoggingEnable(*this);
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
Direction pathfindDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ NextLoc }, this); Direction pathfindDirection = gGuestPathfinder->ChooseDirection(TileCoordsXYZ{ NextLoc }, *this);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingDisable(); PathfindLoggingDisable();
@ -732,7 +732,7 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat
{ {
/* Heuristic search failed for all directions. /* Heuristic search failed for all directions.
* Reset the PathfindGoal - this means that the PathfindHistory * 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::ChooseDirection().
* This lets the heuristic search "try again" in case the player has * This lets the heuristic search "try again" in case the player has
* edited the path layout or the mechanic was already stuck in the * edited the path layout or the mechanic was already stuck in the
* save game (e.g. with a worse version of the pathfinding). */ * save game (e.g. with a worse version of the pathfinding). */

View File

@ -43,7 +43,7 @@ static bool _pathFindDebug = false;
static utf8 _pathFindDebugPeepName[256]; static utf8 _pathFindDebugPeepName[256];
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
static int32_t guest_surface_path_finding(Peep* peep); static int32_t guest_surface_path_finding(Peep& peep);
/* A junction history for the peep pathfinding heuristic search /* A junction history for the peep pathfinding heuristic search
* The magic number 16 is the largest value returned by * The magic number 16 is the largest value returned by
@ -124,10 +124,10 @@ static int32_t path_get_permitted_edges(PathElement* pathElement)
* *
* rct2: 0x0069524E * rct2: 0x0069524E
*/ */
static int32_t peep_move_one_tile(Direction direction, Peep* peep) static int32_t peep_move_one_tile(Direction direction, Peep& peep)
{ {
assert(direction_valid(direction)); assert(direction_valid(direction));
auto newTile = CoordsXY{ CoordsXY{ peep->NextLoc } + CoordsDirectionDelta[direction] }.ToTileCentre(); auto newTile = CoordsXY{ CoordsXY{ peep.NextLoc } + CoordsDirectionDelta[direction] }.ToTileCentre();
if (newTile.x >= MAXIMUM_MAP_SIZE_BIG || newTile.y >= MAXIMUM_MAP_SIZE_BIG) if (newTile.x >= MAXIMUM_MAP_SIZE_BIG || newTile.y >= MAXIMUM_MAP_SIZE_BIG)
{ {
@ -135,8 +135,8 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep)
return guest_surface_path_finding(peep); return guest_surface_path_finding(peep);
} }
peep->PeepDirection = direction; peep.PeepDirection = direction;
if (peep->State != PeepState::Queuing) if (peep.State != PeepState::Queuing)
{ {
// When peeps are walking along a path, we would like them to be spread out across the width of the path, // When peeps are walking along a path, we would like them to be spread out across the width of the path,
// instead of all walking along the exact centre line of the path. // instead of all walking along the exact centre line of the path.
@ -159,19 +159,19 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep)
if (direction == 0 || direction == 2) if (direction == 0 || direction == 2)
{ {
// Peep is moving along X, so apply the offset to the X position of the destination and clamp their current Y // Peep is moving along X, so apply the offset to the X position of the destination and clamp their current Y
const int32_t centreLine = (peep->y & 0xFFE0) + COORDS_XY_HALF_TILE; const int32_t centreLine = (peep.y & 0xFFE0) + COORDS_XY_HALF_TILE;
newTile.x += offset; newTile.x += offset;
newTile.y = std::clamp<int32_t>(peep->y, centreLine - 3, centreLine + 3); newTile.y = std::clamp<int32_t>(peep.y, centreLine - 3, centreLine + 3);
} }
else else
{ {
// Peep is moving along Y, so apply the offset to the Y position of the destination and clamp their current X // Peep is moving along Y, so apply the offset to the Y position of the destination and clamp their current X
const int32_t centreLine = (peep->x & 0xFFE0) + COORDS_XY_HALF_TILE; const int32_t centreLine = (peep.x & 0xFFE0) + COORDS_XY_HALF_TILE;
newTile.x = std::clamp<int32_t>(peep->x, centreLine - 3, centreLine + 3); newTile.x = std::clamp<int32_t>(peep.x, centreLine - 3, centreLine + 3);
newTile.y += offset; newTile.y += offset;
} }
} }
peep->SetDestination(newTile, 2); peep.SetDestination(newTile, 2);
return 0; return 0;
} }
@ -180,9 +180,9 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep)
* *
* rct2: 0x00694C41 * rct2: 0x00694C41
*/ */
static int32_t guest_surface_path_finding(Peep* peep) static int32_t guest_surface_path_finding(Peep& peep)
{ {
auto pathPos = CoordsXYRangedZ{ peep->NextLoc, peep->NextLoc.z, peep->NextLoc.z + PATH_CLEARANCE }; auto pathPos = CoordsXYRangedZ{ peep.NextLoc, peep.NextLoc.z, peep.NextLoc.z + PATH_CLEARANCE };
Direction randDirection = scenario_rand() & 3; Direction randDirection = scenario_rand() & 3;
if (!fence_in_the_way(pathPos, randDirection)) if (!fence_in_the_way(pathPos, randDirection))
@ -208,8 +208,8 @@ static int32_t guest_surface_path_finding(Peep* peep)
} }
randDirection &= 3; randDirection &= 3;
pathPos.x = peep->NextLoc.x; pathPos.x = peep.NextLoc.x;
pathPos.y = peep->NextLoc.y; pathPos.y = peep.NextLoc.y;
if (!fence_in_the_way(pathPos, randDirection)) if (!fence_in_the_way(pathPos, randDirection))
{ {
pathPos.x += CoordsDirectionDelta[randDirection].x; pathPos.x += CoordsDirectionDelta[randDirection].x;
@ -228,8 +228,8 @@ static int32_t guest_surface_path_finding(Peep* peep)
randDirection -= 2; randDirection -= 2;
randDirection &= 3; randDirection &= 3;
pathPos.x = peep->NextLoc.x; pathPos.x = peep.NextLoc.x;
pathPos.y = peep->NextLoc.y; pathPos.y = peep.NextLoc.y;
if (!fence_in_the_way(pathPos, randDirection)) if (!fence_in_the_way(pathPos, randDirection))
{ {
pathPos.x += CoordsDirectionDelta[randDirection].x; pathPos.x += CoordsDirectionDelta[randDirection].x;
@ -289,7 +289,7 @@ static uint8_t footpath_element_next_in_direction(TileCoordsXYZ loc, PathElement
continue; continue;
if (nextTileElement->GetType() != TileElementType::Path) if (nextTileElement->GetType() != TileElementType::Path)
continue; continue;
if (!IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection)) if (!GuestPathfinding::IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection))
continue; continue;
if (nextTileElement->AsPath()->IsWide()) if (nextTileElement->AsPath()->IsWide())
return PATH_SEARCH_WIDE; return PATH_SEARCH_WIDE;
@ -382,7 +382,7 @@ static uint8_t footpath_element_dest_in_dir(TileCoordsXYZ loc, Direction chosenD
break; break;
case TileElementType::Path: case TileElementType::Path:
{ {
if (!IsValidPathZAndDirection(tileElement, loc.z, chosenDirection)) if (!GuestPathfinding::IsValidPathZAndDirection(tileElement, loc.z, chosenDirection))
continue; continue;
if (tileElement->AsPath()->IsWide()) if (tileElement->AsPath()->IsWide())
return PATH_SEARCH_WIDE; return PATH_SEARCH_WIDE;
@ -460,14 +460,14 @@ static uint8_t footpath_element_destination_in_direction(
* *
* rct2: 0x00695225 * rct2: 0x00695225
*/ */
static int32_t guest_path_find_aimless(Peep* peep, uint8_t edges) static int32_t guest_path_find_aimless(Peep& peep, uint8_t edges)
{ {
if (scenario_rand() & 1) if (scenario_rand() & 1)
{ {
// If possible go straight // If possible go straight
if (edges & (1 << peep->PeepDirection)) if (edges & (1 << peep.PeepDirection))
{ {
return peep_move_one_tile(peep->PeepDirection, peep); return peep_move_one_tile(peep.PeepDirection, peep);
} }
} }
@ -486,21 +486,21 @@ static int32_t guest_path_find_aimless(Peep* peep, uint8_t edges)
* *
* rct2: 0x0069A60A * rct2: 0x0069A60A
*/ */
static uint8_t peep_pathfind_get_max_number_junctions(Peep* peep) static uint8_t peep_pathfind_get_max_number_junctions(Peep& peep)
{ {
if (peep->Is<Staff>()) if (peep.Is<Staff>())
return 8; return 8;
// PEEP_FLAGS_2? It's cleared here but not set anywhere! // PEEP_FLAGS_2? It's cleared here but not set anywhere!
if ((peep->PeepFlags & PEEP_FLAGS_2)) if ((peep.PeepFlags & PEEP_FLAGS_2))
{ {
if ((scenario_rand() & 0xFFFF) <= 7281) if ((scenario_rand() & 0xFFFF) <= 7281)
peep->PeepFlags &= ~PEEP_FLAGS_2; peep.PeepFlags &= ~PEEP_FLAGS_2;
return 8; return 8;
} }
auto* guest = peep->As<Guest>(); auto* guest = peep.As<Guest>();
if (guest == nullptr) if (guest == nullptr)
return 8; return 8;
@ -687,7 +687,7 @@ static constexpr const char* pathSearchToString(uint8_t pathFindSearchResult)
* rct2: 0x0069A997 * rct2: 0x0069A997
*/ */
static void peep_pathfind_heuristic_search( static void peep_pathfind_heuristic_search(
TileCoordsXYZ loc, Peep* peep, TileElement* currentTileElement, bool inPatrolArea, uint8_t counter, uint16_t* endScore, TileCoordsXYZ loc, Peep& peep, TileElement* currentTileElement, bool inPatrolArea, uint8_t counter, uint16_t* endScore,
Direction test_edge, uint8_t* endJunctions, TileCoordsXYZ junctionList[16], uint8_t directionList[16], Direction test_edge, uint8_t* endJunctions, TileCoordsXYZ junctionList[16], uint8_t directionList[16],
TileCoordsXYZ* endXYZ, uint8_t* endSteps) TileCoordsXYZ* endXYZ, uint8_t* endSteps)
{ {
@ -696,7 +696,7 @@ static void peep_pathfind_heuristic_search(
bool currentElementIsWide = currentTileElement->AsPath()->IsWide(); bool currentElementIsWide = currentTileElement->AsPath()->IsWide();
if (currentElementIsWide) if (currentElementIsWide)
{ {
const Staff* staff = peep->As<Staff>(); const Staff* staff = peep.As<Staff>();
if (staff != nullptr && staff->CanIgnoreWideFlag(loc.ToCoordsXYZ(), currentTileElement)) if (staff != nullptr && staff->CanIgnoreWideFlag(loc.ToCoordsXYZ(), currentTileElement))
currentElementIsWide = false; currentElementIsWide = false;
} }
@ -721,7 +721,7 @@ static void peep_pathfind_heuristic_search(
} }
bool nextInPatrolArea = inPatrolArea; bool nextInPatrolArea = inPatrolArea;
auto* staff = peep->As<Staff>(); auto* staff = peep.As<Staff>();
if (staff != nullptr && staff->IsMechanic()) if (staff != nullptr && staff->IsMechanic())
{ {
nextInPatrolArea = staff->IsLocationInPatrol(loc.ToCoordsXY()); nextInPatrolArea = staff->IsLocationInPatrol(loc.ToCoordsXY());
@ -824,7 +824,7 @@ static void peep_pathfind_heuristic_search(
* queue path. * queue path.
* Otherwise, peeps walk on path tiles to get to the goal. */ * 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; continue;
// Path may be sloped, so set z to path base height. // Path may be sloped, so set z to path base height.
@ -1075,14 +1075,14 @@ static void peep_pathfind_heuristic_search(
/* First check if going through the junction would be /* First check if going through the junction would be
* a loop. If so, the current search path ends here. * a loop. If so, the current search path ends here.
* Path finding loop detection can take advantage of both the * Path finding loop detection can take advantage of both the
* peep->PathfindHistory - loops through remembered junctions * peep.PathfindHistory - loops through remembered junctions
* the peep has already passed through getting to its * the peep has already passed through getting to its
* current position while on the way to its current goal; * current position while on the way to its current goal;
* _peepPathFindHistory - loops in the current search path. */ * _peepPathFindHistory - loops in the current search path. */
bool pathLoop = false; bool pathLoop = false;
/* Check the peep->PathfindHistory to see if this junction has /* Check the peep.PathfindHistory to see if this junction has
* already been visited by the peep while heading for this goal. */ * already been visited by the peep while heading for this goal. */
for (auto& pathfindHistory : peep->PathfindHistory) for (auto& pathfindHistory : peep.PathfindHistory)
{ {
if (pathfindHistory == loc) if (pathfindHistory == loc)
{ {
@ -1261,7 +1261,7 @@ static void peep_pathfind_heuristic_search(
* *
* rct2: 0x0069A5F0 * rct2: 0x0069A5F0
*/ */
Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& peep)
{ {
PROFILED_FUNCTION(); PROFILED_FUNCTION();
@ -1270,9 +1270,9 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
/* The max number of tiles to check - a whole-search limit. /* The max number of tiles to check - a whole-search limit.
* Mainly to limit the performance impact of the path finding. */ * Mainly to limit the performance impact of the path finding. */
int32_t maxTilesChecked = (peep->Is<Staff>()) ? 50000 : 15000; int32_t maxTilesChecked = (peep.Is<Staff>()) ? 50000 : 15000;
// Used to allow walking through no entry banners // Used to allow walking through no entry banners
_peepPathFindIsStaff = peep->Is<Staff>(); _peepPathFindIsStaff = peep.Is<Staff>();
TileCoordsXYZ goal = gPeepPathFindGoalPosition; TileCoordsXYZ goal = gPeepPathFindGoalPosition;
@ -1322,7 +1322,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
} }
/* Check if this path element is a thin junction. /* Check if this path element is a thin junction.
* Only 'thin' junctions are remembered in peep->PathfindHistory. * Only 'thin' junctions are remembered in peep.PathfindHistory.
* NO attempt is made to merge the overlaid path elements and * NO attempt is made to merge the overlaid path elements and
* check if the combination is 'thin'! * check if the combination is 'thin'!
* The junction is considered 'thin' simply if any of the * The junction is considered 'thin' simply if any of the
@ -1338,9 +1338,9 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
permitted_edges &= 0xF; permitted_edges &= 0xF;
uint8_t edges = permitted_edges; uint8_t edges = permitted_edges;
if (isThin && peep->PathfindGoal == goal) if (isThin && peep.PathfindGoal == goal)
{ {
/* Use of peep->PathfindHistory[]: /* Use of peep.PathfindHistory[]:
* When walking to a goal, the peep PathfindHistory stores * When walking to a goal, the peep PathfindHistory stores
* the last 4 thin junctions that the peep walked through. * the last 4 thin junctions that the peep walked through.
* For each of these 4 thin junctions the peep remembers * For each of these 4 thin junctions the peep remembers
@ -1355,7 +1355,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
/* If the peep remembers walking through this junction /* If the peep remembers walking through this junction
* previously while heading for its goal, retrieve the * previously while heading for its goal, retrieve the
* directions it has not yet tried. */ * directions it has not yet tried. */
for (auto& pathfindHistory : peep->PathfindHistory) for (auto& pathfindHistory : peep.PathfindHistory)
{ {
if (pathfindHistory == loc) if (pathfindHistory == loc)
{ {
@ -1405,15 +1405,15 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
/* If this is a new goal for the peep. Store it and reset the peep's /* If this is a new goal for the peep. Store it and reset the peep's
* PathfindHistory. */ * PathfindHistory. */
if (!direction_valid(peep->PathfindGoal.direction) || peep->PathfindGoal != goal) if (!direction_valid(peep.PathfindGoal.direction) || peep.PathfindGoal != goal)
{ {
peep->PathfindGoal = { goal, 0 }; peep.PathfindGoal = { goal, 0 };
// Clear pathfinding history // Clear pathfinding history
TileCoordsXYZD nullPos; TileCoordsXYZD nullPos;
nullPos.SetNull(); nullPos.SetNull();
std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), nullPos); std::fill(std::begin(peep.PathfindHistory), std::end(peep.PathfindHistory), nullPos);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
@ -1504,13 +1504,13 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
uint8_t endDirectionList[16] = { 0 }; uint8_t endDirectionList[16] = { 0 };
bool inPatrolArea = false; bool inPatrolArea = false;
auto* staff = peep->As<Staff>(); auto* staff = peep.As<Staff>();
if (staff != nullptr && staff->IsMechanic()) if (staff != nullptr && staff->IsMechanic())
{ {
/* Mechanics are the only staff type that /* Mechanics are the only staff type that
* pathfind to a destination. Determine if the * pathfind to a destination. Determine if the
* mechanic is in their patrol area. */ * mechanic is in their patrol area. */
inPatrolArea = staff->IsLocationInPatrol(peep->NextLoc); inPatrolArea = staff->IsLocationInPatrol(peep.NextLoc);
} }
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2 #if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
@ -1592,20 +1592,20 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
{ {
for (int32_t i = 0; i < 4; ++i) for (int32_t i = 0; i < 4; ++i)
{ {
if (peep->PathfindHistory[i] == loc) if (peep.PathfindHistory[i] == loc)
{ {
/* Peep remembers this junction, so remove the /* Peep remembers this junction, so remove the
* chosen_edge from those left to try. */ * chosen_edge from those left to try. */
peep->PathfindHistory[i].direction &= ~(1 << chosen_edge); peep.PathfindHistory[i].direction &= ~(1 << chosen_edge);
/* Also remove the edge through which the peep /* Also remove the edge through which the peep
* entered the junction from those left to try. */ * entered the junction from those left to try. */
peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); peep.PathfindHistory[i].direction &= ~(1 << direction_reverse(peep.PeepDirection));
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_verbose( log_verbose(
"Updating existing pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, "Updating existing pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i,
loc.x, loc.y, loc.z, direction_reverse(peep->PeepDirection), chosen_edge); loc.x, loc.y, loc.z, direction_reverse(peep.PeepDirection), chosen_edge);
} }
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
return chosen_edge; return chosen_edge;
@ -1614,20 +1614,20 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep)
/* Peep does not remember this junction, so forget a junction /* Peep does not remember this junction, so forget a junction
* and remember this junction. */ * and remember this junction. */
int32_t i = peep->PathfindGoal.direction++; int32_t i = peep.PathfindGoal.direction++;
peep->PathfindGoal.direction &= 3; peep.PathfindGoal.direction &= 3;
peep->PathfindHistory[i] = { loc, permitted_edges }; peep.PathfindHistory[i] = { loc, permitted_edges };
/* Remove the chosen_edge from those left to try. */ /* Remove the chosen_edge from those left to try. */
peep->PathfindHistory[i].direction &= ~(1 << chosen_edge); peep.PathfindHistory[i].direction &= ~(1 << chosen_edge);
/* Also remove the edge through which the peep /* Also remove the edge through which the peep
* entered the junction from those left to try. */ * entered the junction from those left to try. */
peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); peep.PathfindHistory[i].direction &= ~(1 << direction_reverse(peep.PeepDirection));
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_verbose( log_verbose(
"Storing new pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, loc.x, loc.y, "Storing new pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, loc.x, loc.y,
loc.z, direction_reverse(peep->PeepDirection), chosen_edge); loc.z, direction_reverse(peep.PeepDirection), chosen_edge);
} }
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
} }
@ -1661,10 +1661,10 @@ static std::optional<CoordsXYZ> GetNearestParkEntrance(const CoordsXY& loc)
* *
* rct2: 0x006952C0 * 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. // Send peeps to the nearest park entrance.
auto chosenEntrance = GetNearestParkEntrance(peep->NextLoc); auto chosenEntrance = GetNearestParkEntrance(peep.NextLoc);
// If no defined park entrances are found, walk aimlessly. // If no defined park entrances are found, walk aimlessly.
if (!chosenEntrance.has_value()) if (!chosenEntrance.has_value())
@ -1674,7 +1674,7 @@ static int32_t GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges)
gPeepPathFindIgnoreForeignQueues = true; gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull(); gPeepPathFindQueueRideIndex = RideId::GetNull();
Direction chosenDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
if (chosenDirection == INVALID_DIRECTION) if (chosenDirection == INVALID_DIRECTION)
return guest_path_find_aimless(peep, edges); return guest_path_find_aimless(peep, edges);
@ -1710,10 +1710,10 @@ static uint8_t get_nearest_peep_spawn_index(uint16_t x, uint16_t y)
* *
* rct2: 0x0069536C * 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. // Send peeps to the nearest spawn point.
uint8_t chosenSpawn = get_nearest_peep_spawn_index(peep->NextLoc.x, peep->NextLoc.y); uint8_t chosenSpawn = get_nearest_peep_spawn_index(peep.NextLoc.x, peep.NextLoc.y);
// If no defined spawns were found, walk aimlessly. // If no defined spawns were found, walk aimlessly.
if (chosenSpawn == 0xFF) if (chosenSpawn == 0xFF)
@ -1723,14 +1723,14 @@ static int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges)
Direction direction = peepSpawnLoc.direction; Direction direction = peepSpawnLoc.direction;
gPeepPathFindGoalPosition = TileCoordsXYZ(peepSpawnLoc); gPeepPathFindGoalPosition = TileCoordsXYZ(peepSpawnLoc);
if (peepSpawnLoc.x == peep->NextLoc.x && peepSpawnLoc.y == peep->NextLoc.y) if (peepSpawnLoc.x == peep.NextLoc.x && peepSpawnLoc.y == peep.NextLoc.y)
{ {
return peep_move_one_tile(direction, peep); return peep_move_one_tile(direction, peep);
} }
gPeepPathFindIgnoreForeignQueues = true; gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull(); gPeepPathFindQueueRideIndex = RideId::GetNull();
direction = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
if (direction == INVALID_DIRECTION) if (direction == INVALID_DIRECTION)
return guest_path_find_aimless(peep, edges); return guest_path_find_aimless(peep, edges);
@ -1741,28 +1741,28 @@ static int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges)
* *
* rct2: 0x00695161 * rct2: 0x00695161
*/ */
static int32_t GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges) int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges)
{ {
TileCoordsXYZ entranceGoal{}; TileCoordsXYZ entranceGoal{};
if (peep->PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN) if (peep.PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)
{ {
entranceGoal = peep->PathfindGoal; entranceGoal = peep.PathfindGoal;
auto* entranceElement = map_get_park_entrance_element_at(entranceGoal.ToCoordsXYZ(), false); auto* entranceElement = map_get_park_entrance_element_at(entranceGoal.ToCoordsXYZ(), false);
// If entrance no longer exists, choose a new one // If entrance no longer exists, choose a new one
if (entranceElement == nullptr) if (entranceElement == nullptr)
{ {
peep->PeepFlags &= ~(PEEP_FLAGS_PARK_ENTRANCE_CHOSEN); peep.PeepFlags &= ~(PEEP_FLAGS_PARK_ENTRANCE_CHOSEN);
} }
} }
if (!(peep->PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)) if (!(peep.PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN))
{ {
auto chosenEntrance = GetNearestParkEntrance(peep->NextLoc); auto chosenEntrance = GetNearestParkEntrance(peep.NextLoc);
if (!chosenEntrance.has_value()) if (!chosenEntrance.has_value())
return guest_path_find_aimless(peep, edges); return guest_path_find_aimless(peep, edges);
peep->PeepFlags |= PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; peep.PeepFlags |= PEEP_FLAGS_PARK_ENTRANCE_CHOSEN;
entranceGoal = TileCoordsXYZ(*chosenEntrance); entranceGoal = TileCoordsXYZ(*chosenEntrance);
} }
@ -1774,7 +1774,7 @@ static int32_t GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges)
PathfindLoggingEnable(peep); PathfindLoggingEnable(peep);
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
Direction chosenDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingDisable(); PathfindLoggingDisable();
@ -1942,9 +1942,9 @@ static void get_ride_queue_end(TileCoordsXYZ& loc)
* appropriate. * appropriate.
*/ */
static StationIndex guest_pathfinding_select_random_station( static StationIndex guest_pathfinding_select_random_station(
const Guest* guest, int32_t numEntranceStations, BitSet<OpenRCT2::Limits::MaxStationsPerRide>& entranceStations) const Guest& guest, int32_t numEntranceStations, BitSet<OpenRCT2::Limits::MaxStationsPerRide>& entranceStations)
{ {
int32_t select = guest->GuestNumRides % numEntranceStations; int32_t select = guest.GuestNumRides % numEntranceStations;
while (select > 0) while (select > 0)
{ {
for (StationIndex::UnderlyingType i = 0; i < OpenRCT2::Limits::MaxStationsPerRide; i++) for (StationIndex::UnderlyingType i = 0; i < OpenRCT2::Limits::MaxStationsPerRide; i++)
@ -1971,22 +1971,22 @@ static StationIndex guest_pathfinding_select_random_station(
* *
* rct2: 0x00694C35 * rct2: 0x00694C35
*/ */
int32_t guest_path_finding(Guest* peep) int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
{ {
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingEnable(peep); PathfindLoggingEnable(peep);
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Starting guest_path_finding for %s", _pathFindDebugPeepName); log_info("Starting CalculateNextDestination for %s", _pathFindDebugPeepName);
} }
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (peep->GetNextIsSurface()) if (peep.GetNextIsSurface())
{ {
return guest_surface_path_finding(peep); return guest_surface_path_finding(peep);
} }
TileCoordsXYZ loc{ peep->NextLoc }; TileCoordsXYZ loc{ peep.NextLoc };
auto* pathElement = map_get_path_element_at(loc); auto* pathElement = map_get_path_element_at(loc);
if (pathElement == nullptr) if (pathElement == nullptr)
@ -2002,7 +2002,7 @@ int32_t guest_path_finding(Guest* peep)
return guest_surface_path_finding(peep); return guest_surface_path_finding(peep);
} }
if (!peep->OutsideOfPark && peep->HeadingForRideOrParkExit()) if (!peep.OutsideOfPark && peep.HeadingForRideOrParkExit())
{ {
/* If this tileElement is adjacent to any non-wide paths, /* If this tileElement is adjacent to any non-wide paths,
* remove all of the edges to wide paths. */ * remove all of the edges to wide paths. */
@ -2024,14 +2024,14 @@ int32_t guest_path_finding(Guest* peep)
edges = adjustedEdges; edges = adjustedEdges;
} }
int32_t direction = direction_reverse(peep->PeepDirection); int32_t direction = direction_reverse(peep.PeepDirection);
// Check if in a dead end (i.e. only edge is where the peep came from) // Check if in a dead end (i.e. only edge is where the peep came from)
if (!(edges & ~(1 << direction))) if (!(edges & ~(1 << direction)))
{ {
// In a dead end. Check if peep is lost, etc. // In a dead end. Check if peep is lost, etc.
peep->CheckIfLost(); peep.CheckIfLost();
peep->CheckCantFindRide(); peep.CheckCantFindRide();
peep->CheckCantFindExit(); peep.CheckCantFindExit();
} }
else else
{ {
@ -2048,7 +2048,7 @@ int32_t guest_path_finding(Guest* peep)
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info( log_info(
"Completed guest_path_finding for %s - taking only direction available: %d.", _pathFindDebugPeepName, "Completed CalculateNextDestination for %s - taking only direction available: %d.", _pathFindDebugPeepName,
direction); direction);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
@ -2060,16 +2060,16 @@ int32_t guest_path_finding(Guest* peep)
// Peep is outside the park. // Peep is outside the park.
// loc_694F19: // loc_694F19:
if (peep->OutsideOfPark) if (peep.OutsideOfPark)
{ {
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Completed guest_path_finding for %s - peep is outside the park.", _pathFindDebugPeepName); log_info("Completed CalculateNextDestination for %s - peep is outside the park.", _pathFindDebugPeepName);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
switch (peep->State) switch (peep.State)
{ {
case PeepState::EnteringPark: case PeepState::EnteringPark:
return GuestPathFindParkEntranceEntering(peep, edges); return GuestPathFindParkEntranceEntering(peep, edges);
@ -2086,7 +2086,7 @@ int32_t guest_path_finding(Guest* peep)
* In principle, peeps with food are not paying as much attention to * In principle, peeps with food are not paying as much attention to
* where they are going and are consequently more like to walk up * where they are going and are consequently more like to walk up
* dead end paths, paths to ride exits, etc. */ * dead end paths, paths to ride exits, etc. */
if (!peep->HasFoodOrDrink() && (scenario_rand() & 0xFFFF) >= 2184) if (!peep.HasFoodOrDrink() && (scenario_rand() & 0xFFFF) >= 2184)
{ {
uint8_t adjustedEdges = edges; uint8_t adjustedEdges = edges;
for (Direction chosenDirection : ALL_DIRECTIONS) for (Direction chosenDirection : ALL_DIRECTIONS)
@ -2113,41 +2113,41 @@ int32_t guest_path_finding(Guest* peep)
/* If there are still multiple directions to choose from, /* If there are still multiple directions to choose from,
* peeps with maps will randomly read the map: probability of doing so * peeps with maps will randomly read the map: probability of doing so
* is much higher when heading for a ride or the park exit. */ * is much higher when heading for a ride or the park exit. */
if (peep->HasItem(ShopItem::Map)) if (peep.HasItem(ShopItem::Map))
{ {
// If at least 2 directions consult map // If at least 2 directions consult map
if (bitcount(edges) >= 2) if (bitcount(edges) >= 2)
{ {
uint16_t probability = 1638; uint16_t probability = 1638;
if (peep->HeadingForRideOrParkExit()) if (peep.HeadingForRideOrParkExit())
{ {
probability = 9362; probability = 9362;
} }
if ((scenario_rand() & 0xFFFF) < probability) if ((scenario_rand() & 0xFFFF) < probability)
{ {
peep->ReadMap(); peep.ReadMap();
} }
} }
} }
if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) if (peep.PeepFlags & PEEP_FLAGS_LEAVING_PARK)
{ {
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Completed guest_path_finding for %s - peep is leaving the park.", _pathFindDebugPeepName); log_info("Completed CalculateNextDestination for %s - peep is leaving the park.", _pathFindDebugPeepName);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
return GuestPathFindParkEntranceLeaving(peep, edges); return GuestPathFindParkEntranceLeaving(peep, edges);
} }
if (peep->GuestHeadingToRideId.IsNull()) if (peep.GuestHeadingToRideId.IsNull())
{ {
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Completed guest_path_finding for %s - peep is aimless.", _pathFindDebugPeepName); log_info("Completed CalculateNextDestination for %s - peep is aimless.", _pathFindDebugPeepName);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
@ -2155,7 +2155,7 @@ int32_t guest_path_finding(Guest* peep)
} }
// Peep is heading for a ride. // Peep is heading for a ride.
RideId rideIndex = peep->GuestHeadingToRideId; RideId rideIndex = peep.GuestHeadingToRideId;
auto ride = get_ride(rideIndex); auto ride = get_ride(rideIndex);
if (ride == nullptr || ride->status != RideStatus::Open) if (ride == nullptr || ride->status != RideStatus::Open)
{ {
@ -2163,7 +2163,8 @@ int32_t guest_path_finding(Guest* peep)
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info( log_info(
"Completed guest_path_finding for %s - peep is heading to closed ride == aimless.", _pathFindDebugPeepName); "Completed CalculateNextDestination for %s - peep is heading to closed ride == aimless.",
_pathFindDebugPeepName);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
@ -2194,7 +2195,7 @@ int32_t guest_path_finding(Guest* peep)
entranceStations[stationIndex.ToUnderlying()] = true; entranceStations[stationIndex.ToUnderlying()] = true;
TileCoordsXYZD entranceLocation = station.Entrance; TileCoordsXYZD entranceLocation = station.Entrance;
auto score = CalculateHeuristicPathingScore(entranceLocation, TileCoordsXYZ{ peep->NextLoc }); auto score = CalculateHeuristicPathingScore(entranceLocation, TileCoordsXYZ{ peep.NextLoc });
if (score < bestScore) if (score < bestScore)
{ {
bestScore = score; bestScore = score;
@ -2234,22 +2235,23 @@ int32_t guest_path_finding(Guest* peep)
gPeepPathFindGoalPosition = loc; gPeepPathFindGoalPosition = loc;
gPeepPathFindIgnoreForeignQueues = true; gPeepPathFindIgnoreForeignQueues = true;
direction = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
if (direction == INVALID_DIRECTION) if (direction == INVALID_DIRECTION)
{ {
/* Heuristic search failed for all directions. /* Heuristic search failed for all directions.
* Reset the PathfindGoal - this means that the PathfindHistory * 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 ChooseDirection().
* This lets the heuristic search "try again" in case the player has * This lets the heuristic search "try again" in case the player has
* edited the path layout or the mechanic was already stuck in the * edited the path layout or the mechanic was already stuck in the
* save game (e.g. with a worse version of the pathfinding). */ * save game (e.g. with a worse version of the pathfinding). */
peep->ResetPathfindGoal(); peep.ResetPathfindGoal();
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Completed guest_path_finding for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName); log_info(
"Completed CalculateNextDestination for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
@ -2259,14 +2261,14 @@ int32_t guest_path_finding(Guest* peep)
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug) if (_pathFindDebug)
{ {
log_info("Completed guest_path_finding for %s - direction chosen: %d.", _pathFindDebugPeepName, direction); log_info("Completed CalculateNextDestination for %s - direction chosen: %d.", _pathFindDebugPeepName, direction);
} }
PathfindLoggingDisable(); PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
return peep_move_one_tile(direction, 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()) if (tileElement->AsPath()->IsSloped())
{ {
@ -2311,18 +2313,18 @@ void Peep::ResetPathfindGoal()
} }
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
void PathfindLoggingEnable([[maybe_unused]] Peep* peep) void PathfindLoggingEnable([[maybe_unused]] Peep& peep)
{ {
# if defined(PATHFIND_DEBUG) && PATHFIND_DEBUG # if defined(PATHFIND_DEBUG) && PATHFIND_DEBUG
/* Determine if the pathfinding debugging is wanted for this peep. */ /* Determine if the pathfinding debugging is wanted for this peep. */
format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep->name_string_idx, &(peep->Id)); format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep.name_string_idx, &(peep.Id));
/* For guests, use the existing PEEP_FLAGS_TRACKING flag to /* For guests, use the existing PEEP_FLAGS_TRACKING flag to
* determine for which guest(s) the pathfinding debugging will * determine for which guest(s) the pathfinding debugging will
* be output for. */ * be output for. */
if (peep->type == PEEP_TYPE_GUEST) if (peep.type == PEEP_TYPE_GUEST)
{ {
gPathFindDebug = peep->PeepFlags & PEEP_FLAGS_TRACKING; gPathFindDebug = peep.PeepFlags & PEEP_FLAGS_TRACKING;
} }
/* For staff, there is no tracking button (any other similar /* For staff, there is no tracking button (any other similar
* suitable existing mechanism?), so fall back to a crude * suitable existing mechanism?), so fall back to a crude

View File

@ -37,19 +37,58 @@ extern RideId gPeepPathFindQueueRideIndex;
// In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL. // In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL.
extern bool gPeepPathFindIgnoreForeignQueues; extern bool gPeepPathFindIgnoreForeignQueues;
// Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide class GuestPathfinding
// the direction the peep should walk in from the current tile. {
Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep); public:
virtual ~GuestPathfinding() = default;
// Test whether the given tile can be walked onto, if the peep is currently at height currentZ and /**
// moving in direction currentDirection. * Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide the direction the peep
bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); * should walk in from the current tile.
*
* @param loc Reference to the peep's current tile location
* @param peep Reference to the current peep struct
* @return The direction the peep should walk in
*/
virtual Direction ChooseDirection(const TileCoordsXYZ& loc, Peep& peep) = 0;
// 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. * Test whether the given tile can be walked onto, if the peep is currently at height currentZ and
// * moving in direction currentDirection
// Returns 0 if the guest has successfully had a new destination set up, nonzero otherwise. *
int32_t guest_path_finding(Guest* peep); * @param tileElement A pointer to the tile that is being tested
* @param currentZ The height coord the peep is at
* @param currentDirection The direction the peep is facing in
* @return True if the given tile can be walked onto, false otherwise
*/
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.
*
* @param peep A reference to a guest struct
* @returns 0 if the guest has successfully had a new destination set up, nonzero otherwise.
*/
virtual int32_t CalculateNextDestination(Guest& peep) = 0;
};
class OriginalPathfinding : public GuestPathfinding
{
public:
Direction ChooseDirection(const TileCoordsXYZ& loc, Peep& peep) final override;
int32_t CalculateNextDestination(Guest& peep) final override;
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);
};
extern std::unique_ptr<GuestPathfinding> gGuestPathfinder;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
# define PATHFIND_DEBUG \ # define PATHFIND_DEBUG \
@ -60,6 +99,6 @@ int32_t guest_path_finding(Guest* peep);
// The following calls configure debug logging for the given peep // The following calls configure debug logging for the given peep
// If they're a guest, pathfinding will be logged if they have PEEP_FLAGS_TRACKING set // If they're a guest, pathfinding will be logged if they have PEEP_FLAGS_TRACKING set
// If they're staff, pathfinding will be logged if their name is "Mechanic Debug" // If they're staff, pathfinding will be logged if their name is "Mechanic Debug"
void PathfindLoggingEnable(Peep* peep); void PathfindLoggingEnable(Peep& peep);
void PathfindLoggingDisable(); void PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1

View File

@ -84,7 +84,7 @@ protected:
// Pick the direction the peep should initially move in, given the goal position. // 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. // This will also store the goal position and initialize pathfinding data for the peep.
gPeepPathFindGoalPosition = goal; gPeepPathFindGoalPosition = goal;
const Direction moveDir = peep_pathfind_choose_direction(*pos, peep); const Direction moveDir = gGuestPathfinder->ChooseDirection(*pos, *peep);
if (moveDir == INVALID_DIRECTION) if (moveDir == INVALID_DIRECTION)
{ {
// Couldn't determine a direction to move off in // Couldn't determine a direction to move off in