Pathfinding cleanup (#21407)

* Eliminate unnecessary abstraction for path finding

* Pass the goal to ChooseDirection instead of using globals

* Remove gPeepPathFindGoalPosition and pass it by parameter instead

* Remove _peepPathFindIsStaff and make ignoring banners explicit

* Code style and naming fixups

* Apply clang-format

* Add comment specifying to why it does not ignore banners

* Apply review comments
This commit is contained in:
Matt 2024-02-22 21:52:01 +02:00 committed by GitHub
parent fdbdbd405f
commit 9d9f0af0cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 2065 additions and 2114 deletions

View File

@ -70,8 +70,6 @@ uint8_t gGuestChangeModifier;
uint8_t gPeepWarningThrottle[16];
std::unique_ptr<GuestPathfinding> gGuestPathfinder = std::make_unique<OriginalPathfinding>();
static uint8_t _unk_F1AEF0;
static TileElement* _peepRideEntranceExitElement;
@ -2393,7 +2391,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result)
if (guest != nullptr)
{
result = gGuestPathfinder->CalculateNextDestination(*guest);
result = PathFinding::CalculateNextDestination(*guest);
}
else
{
@ -2853,3 +2851,20 @@ void Peep::Paint(PaintSession& session, int32_t imageDirection) const
}
}
}
/**
*
* rct2: 0x0069A98C
*/
void Peep::ResetPathfindGoal()
{
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
{
LOG_INFO("Resetting PathfindGoal for %s", _pathFindDebugPeepName);
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindGoal.SetNull();
PathfindGoal.direction = INVALID_DIRECTION;
}

View File

@ -183,7 +183,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons
}
/* test_element is a path */
if (!GuestPathfinding::IsValidPathZAndDirection(test_element, adjacPos.z / COORDS_Z_STEP, adjac_dir))
if (!PathFinding::IsValidPathZAndDirection(test_element, adjacPos.z / COORDS_Z_STEP, adjac_dir))
continue;
/* test_element is a connected path */
@ -713,10 +713,6 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat
}
}
gPeepPathFindGoalPosition.x = location.x;
gPeepPathFindGoalPosition.y = location.y;
gPeepPathFindGoalPosition.z = location.z;
gPeepPathFindIgnoreForeignQueues = false;
gPeepPathFindQueueRideIndex = RideId::GetNull();
@ -724,7 +720,8 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat
PathfindLoggingEnable(*this);
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
Direction pathfindDirection = gGuestPathfinder->ChooseDirection(TileCoordsXYZ{ NextLoc }, *this);
const auto goalPos = TileCoordsXYZ{ location };
Direction pathfindDirection = PathFinding::ChooseDirection(TileCoordsXYZ{ NextLoc }, goalPos, *this);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingDisable();

View File

@ -25,17 +25,15 @@
#include <bitset>
#include <cstring>
using namespace OpenRCT2;
bool gPeepPathFindIgnoreForeignQueues;
RideId gPeepPathFindQueueRideIndex;
static bool _peepPathFindIsStaff;
namespace OpenRCT2::PathFinding
{
static int8_t _peepPathFindNumJunctions;
static int8_t _peepPathFindMaxJunctions;
static int32_t _peepPathFindTilesChecked;
TileCoordsXYZ gPeepPathFindGoalPosition;
bool gPeepPathFindIgnoreForeignQueues;
RideId gPeepPathFindQueueRideIndex;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
// Use to guard calls to log messages
static bool _pathFindDebug = false;
@ -72,14 +70,14 @@ enum
PATH_SEARCH_FAILED
};
static TileElement* GetBannerOnPath(TileElement* path_element)
static TileElement* GetBannerOnPath(TileElement* pathElement)
{
// This is an improved version of original.
// That only checked for one fence in the way.
if (path_element->IsLastForTile())
if (pathElement->IsLastForTile())
return nullptr;
TileElement* bannerElement = path_element + 1;
TileElement* bannerElement = pathElement + 1;
do
{
// Path on top, so no banners
@ -97,9 +95,9 @@ static TileElement* GetBannerOnPath(TileElement* path_element)
return nullptr;
}
static int32_t BannerClearPathEdges(PathElement* pathElement, int32_t edges)
static int32_t BannerClearPathEdges(bool ignoreBanners, PathElement* pathElement, int32_t edges)
{
if (_peepPathFindIsStaff)
if (ignoreBanners)
return edges;
TileElement* bannerElement = GetBannerOnPath(reinterpret_cast<TileElement*>(pathElement));
if (bannerElement != nullptr)
@ -115,9 +113,9 @@ static int32_t BannerClearPathEdges(PathElement* pathElement, int32_t edges)
/**
* Gets the connected edges of a path that are permitted (i.e. no 'no entry' signs)
*/
static int32_t PathGetPermittedEdges(PathElement* pathElement)
static int32_t PathGetPermittedEdges(bool ignoreBanners, PathElement* pathElement)
{
return BannerClearPathEdges(pathElement, pathElement->GetEdgesAndCorners()) & 0x0F;
return BannerClearPathEdges(ignoreBanners, pathElement, pathElement->GetEdgesAndCorners()) & 0x0F;
}
/**
@ -289,7 +287,7 @@ static uint8_t FootpathElementNextInDirection(TileCoordsXYZ loc, PathElement* pa
continue;
if (nextTileElement->GetType() != TileElementType::Path)
continue;
if (!GuestPathfinding::IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection))
if (!IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection))
continue;
if (nextTileElement->AsPath()->IsWide())
return PATH_SEARCH_WIDE;
@ -321,7 +319,8 @@ static uint8_t FootpathElementNextInDirection(TileCoordsXYZ loc, PathElement* pa
*
* This is the recursive portion of FootpathElementDestinationInDirection().
*/
static uint8_t FootpathElementDestInDir(TileCoordsXYZ loc, Direction chosenDirection, RideId* outRideIndex, int32_t level)
static uint8_t FootpathElementDestInDir(
bool ignoreBanners, TileCoordsXYZ loc, Direction chosenDirection, RideId* outRideIndex, int32_t level)
{
TileElement* tileElement;
Direction direction;
@ -382,12 +381,12 @@ static uint8_t FootpathElementDestInDir(TileCoordsXYZ loc, Direction chosenDirec
break;
case TileElementType::Path:
{
if (!GuestPathfinding::IsValidPathZAndDirection(tileElement, loc.z, chosenDirection))
if (!IsValidPathZAndDirection(tileElement, loc.z, chosenDirection))
continue;
if (tileElement->AsPath()->IsWide())
return PATH_SEARCH_WIDE;
uint8_t edges = PathGetPermittedEdges(tileElement->AsPath());
uint8_t edges = PathGetPermittedEdges(ignoreBanners, tileElement->AsPath());
edges &= ~(1 << DirectionReverse(chosenDirection));
loc.z = tileElement->BaseHeight;
@ -407,7 +406,7 @@ static uint8_t FootpathElementDestInDir(TileCoordsXYZ loc, Direction chosenDirec
loc.z += 2;
}
}
return FootpathElementDestInDir(loc, dir, outRideIndex, level + 1);
return FootpathElementDestInDir(ignoreBanners, loc, dir, outRideIndex, level + 1);
}
return PATH_SEARCH_DEAD_END;
}
@ -453,7 +452,8 @@ static uint8_t FootpathElementDestinationInDirection(
}
}
return FootpathElementDestInDir(loc, chosenDirection, outRideIndex, 0);
// This function is only called for guests, never ignore the banners.
return FootpathElementDestInDir(false, loc, chosenDirection, outRideIndex, 0);
}
/**
@ -532,32 +532,33 @@ static bool PathIsThinJunction(PathElement* path, const TileCoordsXYZ& loc)
uint8_t edges = path->GetEdges();
int32_t test_edge = UtilBitScanForward(edges);
if (test_edge == -1)
int32_t testEdge = UtilBitScanForward(edges);
if (testEdge == -1)
return false;
bool thin_junction = false;
int32_t thin_count = 0;
bool isThinJunction = false;
int32_t thinCount = 0;
do
{
int32_t fp_result = FootpathElementNextInDirection(loc, path, test_edge);
auto nextFootpathResult = FootpathElementNextInDirection(loc, path, testEdge);
/* Ignore non-paths (e.g. ride entrances, shops), wide paths
* and ride queues (per ignoreQueues) when counting
* neighbouring tiles. */
if (fp_result != PATH_SEARCH_FAILED && fp_result != PATH_SEARCH_WIDE && fp_result != PATH_SEARCH_RIDE_QUEUE)
if (nextFootpathResult != PATH_SEARCH_FAILED && nextFootpathResult != PATH_SEARCH_WIDE
&& nextFootpathResult != PATH_SEARCH_RIDE_QUEUE)
{
thin_count++;
thinCount++;
}
if (thin_count > 2)
if (thinCount > 2)
{
thin_junction = true;
isThinJunction = true;
break;
}
edges &= ~(1 << test_edge);
} while ((test_edge = UtilBitScanForward(edges)) != -1);
return thin_junction;
edges &= ~(1 << testEdge);
} while ((testEdge = UtilBitScanForward(edges)) != -1);
return isThinJunction;
}
static int32_t CalculateHeuristicPathingScore(const TileCoordsXYZ& loc1, const TileCoordsXYZ& loc2)
@ -687,9 +688,9 @@ static constexpr const char* PathSearchToString(uint8_t pathFindSearchResult)
* rct2: 0x0069A997
*/
static void PeepPathfindHeuristicSearch(
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],
TileCoordsXYZ* endXYZ, uint8_t* endSteps)
TileCoordsXYZ loc, const TileCoordsXYZ& goal, const Peep& peep, TileElement* currentTileElement,
const bool inPatrolArea, uint8_t numSteps, uint16_t* endScore, Direction testEdge, uint8_t* endJunctions,
TileCoordsXYZ junctionList[16], uint8_t directionList[16], TileCoordsXYZ* endXYZ, uint8_t* endSteps)
{
uint8_t searchResult = PATH_SEARCH_FAILED;
@ -701,9 +702,9 @@ static void PeepPathfindHeuristicSearch(
currentElementIsWide = false;
}
loc += TileDirectionDelta[test_edge];
loc += TileDirectionDelta[testEdge];
++counter;
++numSteps;
_peepPathFindTilesChecked--;
/* If this is where the search started this is a search loop and the
@ -714,7 +715,7 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Return from %d,%d,%d; At start", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO("[%03d] Return from %d,%d,%d; At start", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
return;
@ -733,14 +734,14 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Return from %d,%d,%d; Left patrol area", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO("[%03d] Return from %d,%d,%d; Left patrol area", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
return;
}
}
/* Get the next map element of interest in the direction of test_edge. */
/* Get the next map element of interest in the direction of testEdge. */
bool found = false;
TileElement* tileElement = MapGetFirstElementAt(loc);
if (tileElement == nullptr)
@ -787,7 +788,7 @@ static void PeepPathfindHeuristicSearch(
* (in the case when the station has no exit),
* the goal is the ride entrance tile. */
direction = tileElement->GetDirection();
if (direction == test_edge)
if (direction == testEdge)
{
/* The rideIndex will be useful for
* adding transport rides later. */
@ -807,7 +808,7 @@ static void PeepPathfindHeuristicSearch(
/* For mechanics heading for the ride exit, the
* goal is the ride exit tile. */
direction = tileElement->GetDirection();
if (direction == test_edge)
if (direction == testEdge)
{
searchResult = PATH_SEARCH_RIDE_EXIT;
found = true;
@ -824,7 +825,7 @@ static void PeepPathfindHeuristicSearch(
* queue path.
* Otherwise, peeps walk on path tiles to get to the goal. */
if (!GuestPathfinding::IsValidPathZAndDirection(tileElement, loc.z, test_edge))
if (!IsValidPathZAndDirection(tileElement, loc.z, testEdge))
continue;
// Path may be sloped, so set z to path base height.
@ -880,7 +881,7 @@ static void PeepPathfindHeuristicSearch(
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Checking map element at %d,%d,%d; Type: %s", counter, loc.x >> 5, loc.y >> 5, loc.z,
"[%03d] Checking map element at %d,%d,%d; Type: %s", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
PathSearchToString(searchResult));
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
@ -893,18 +894,18 @@ static void PeepPathfindHeuristicSearch(
* Ignore for now. */
// Calculate the heuristic score of this map element.
uint16_t new_score = CalculateHeuristicPathingScore(loc, gPeepPathFindGoalPosition);
uint16_t newScore = CalculateHeuristicPathingScore(loc, goal);
/* If this map element is the search goal the current search path ends here. */
if (new_score == 0)
if (newScore == 0)
{
/* If the search result is better than the best so far (in the parameters),
* then update the parameters with this search before continuing to the next map element. */
if (new_score < *endScore || (new_score == *endScore && counter < *endSteps))
if (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps))
{
// Update the search results
*endScore = new_score;
*endSteps = counter;
*endScore = newScore;
*endSteps = numSteps;
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
@ -922,8 +923,8 @@ static void PeepPathfindHeuristicSearch(
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Search path ends at %d,%d,%d; At goal; Score: %d", counter, loc.x >> 5, loc.y >> 5, loc.z,
new_score);
"[%03d] Search path ends at %d,%d,%d; At goal; Score: %d", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
newScore);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -939,7 +940,7 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Search path ends at %d,%d,%d; Not a path", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO("[%03d] Search path ends at %d,%d,%d; Not a path", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -960,11 +961,11 @@ static void PeepPathfindHeuristicSearch(
* If the search result is better than the best so far
* (in the parameters), then update the parameters with
* this search before continuing to the next map element. */
if (currentElementIsWide && (new_score < *endScore || (new_score == *endScore && counter < *endSteps)))
if (currentElementIsWide && (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps)))
{
// Update the search results
*endScore = new_score;
*endSteps = counter;
*endScore = newScore;
*endSteps = numSteps;
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
@ -982,8 +983,8 @@ static void PeepPathfindHeuristicSearch(
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Search path ends at %d,%d,%d; Wide path; Score: %d", counter, loc.x >> 5, loc.y >> 5, loc.z,
new_score);
"[%03d] Search path ends at %d,%d,%d; Wide path; Score: %d", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
newScore);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -993,30 +994,31 @@ static void PeepPathfindHeuristicSearch(
/* Get all the permitted_edges of the map element. */
Guard::Assert(tileElement->AsPath() != nullptr);
uint8_t edges = PathGetPermittedEdges(tileElement->AsPath());
uint8_t edges = PathGetPermittedEdges(staff != nullptr, tileElement->AsPath());
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Path element at %d,%d,%d; Edges (0123):%d%d%d%d; Reverse: %d", counter, loc.x >> 5, loc.y >> 5, loc.z,
edges & 1, (edges & 2) >> 1, (edges & 4) >> 2, (edges & 8) >> 3, test_edge ^ 2);
"[%03d] Path element at %d,%d,%d; Edges (0123):%d%d%d%d; Reverse: %d", numSteps, loc.x >> 5, loc.y >> 5,
loc.z, edges & 1, (edges & 2) >> 1, (edges & 4) >> 2, (edges & 8) >> 3, testEdge ^ 2);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
/* Remove the reverse edge (i.e. the edge back to the previous map element.) */
edges &= ~(1 << DirectionReverse(test_edge));
edges &= ~(1 << DirectionReverse(testEdge));
int32_t next_test_edge = UtilBitScanForward(edges);
int32_t nextTestEdge = UtilBitScanForward(edges);
/* If there are no other edges the current search ends here.
* Continue to the next map element without updating the parameters (best result so far). */
if (next_test_edge == -1)
if (nextTestEdge == -1)
{
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Search path ends at %d,%d,%d; No more edges/dead end", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO(
"[%03d] Search path ends at %d,%d,%d; No more edges/dead end", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -1024,17 +1026,17 @@ static void PeepPathfindHeuristicSearch(
/* Check if either of the search limits has been reached:
* - max number of steps or max tiles checked. */
if (counter >= 200 || _peepPathFindTilesChecked <= 0)
if (numSteps >= 200 || _peepPathFindTilesChecked <= 0)
{
/* The current search ends here.
* The path continues, so the goal could still be reachable from here.
* If the search result is better than the best so far (in the parameters),
* then update the parameters with this search before continuing to the next map element. */
if (new_score < *endScore || (new_score == *endScore && counter < *endSteps))
if (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps))
{
// Update the search results
*endScore = new_score;
*endSteps = counter;
*endScore = newScore;
*endSteps = numSteps;
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
@ -1052,21 +1054,21 @@ static void PeepPathfindHeuristicSearch(
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Search path ends at %d,%d,%d; Search limit reached; Score: %d", counter, loc.x >> 5, loc.y >> 5,
loc.z, new_score);
"[%03d] Search path ends at %d,%d,%d; Search limit reached; Score: %d", numSteps, loc.x >> 5,
loc.y >> 5, loc.z, newScore);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
}
bool thin_junction = false;
bool isThinJunction = false;
if (searchResult == PATH_SEARCH_JUNCTION)
{
/* Check if this is a thin junction. And perform additional
* necessary checks. */
thin_junction = PathIsThinJunction(tileElement->AsPath(), loc);
isThinJunction = PathIsThinJunction(tileElement->AsPath(), loc);
if (thin_junction)
if (isThinJunction)
{
/* The current search path is passing through a thin
* junction on this map element. Only 'thin' junctions
@ -1125,7 +1127,7 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Search path ends at %d,%d,%d; Loop", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO("[%03d] Search path ends at %d,%d,%d; Loop", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -1138,11 +1140,11 @@ static void PeepPathfindHeuristicSearch(
* then update the parameters with this search before continuing to the next map element. */
if (_peepPathFindNumJunctions <= 0)
{
if (new_score < *endScore || (new_score == *endScore && counter < *endSteps))
if (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps))
{
// Update the search results
*endScore = new_score;
*endSteps = counter;
*endScore = newScore;
*endSteps = numSteps;
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
@ -1158,8 +1160,8 @@ static void PeepPathfindHeuristicSearch(
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Search path ends at %d,%d,%d; NumJunctions < 0; Score: %d", counter, loc.x >> 5, loc.y >> 5,
loc.z, new_score);
"[%03d] Search path ends at %d,%d,%d; NumJunctions < 0; Score: %d", numSteps, loc.x >> 5,
loc.y >> 5, loc.z, newScore);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
continue;
@ -1178,11 +1180,11 @@ static void PeepPathfindHeuristicSearch(
* (recursive call). */
do
{
edges &= ~(1 << next_test_edge);
edges &= ~(1 << nextTestEdge);
uint8_t savedNumJunctions = _peepPathFindNumJunctions;
uint8_t height = loc.z;
if (tileElement->AsPath()->IsSloped() && tileElement->AsPath()->GetSlopeDirection() == next_test_edge)
if (tileElement->AsPath()->IsSloped() && tileElement->AsPath()->GetSlopeDirection() == nextTestEdge)
{
height += 2;
}
@ -1191,44 +1193,44 @@ static void PeepPathfindHeuristicSearch(
{
if (searchResult == PATH_SEARCH_JUNCTION)
{
if (thin_junction)
if (isThinJunction)
LOG_INFO(
"[%03d] Recurse from %d,%d,%d edge: %d; Thin-Junction", counter, loc.x >> 5, loc.y >> 5, loc.z,
next_test_edge);
"[%03d] Recurse from %d,%d,%d edge: %d; Thin-Junction", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
nextTestEdge);
else
LOG_INFO(
"[%03d] Recurse from %d,%d,%d edge: %d; Wide-Junction", counter, loc.x >> 5, loc.y >> 5, loc.z,
next_test_edge);
"[%03d] Recurse from %d,%d,%d edge: %d; Wide-Junction", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
nextTestEdge);
}
else
{
LOG_INFO(
"[%03d] Recurse from %d,%d,%d edge: %d; Segment", counter, loc.x >> 5, loc.y >> 5, loc.z,
next_test_edge);
"[%03d] Recurse from %d,%d,%d edge: %d; Segment", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
nextTestEdge);
}
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (thin_junction)
if (isThinJunction)
{
/* Add the current test_edge to the history. */
_peepPathFindHistory[_peepPathFindNumJunctions + 1].direction = next_test_edge;
_peepPathFindHistory[_peepPathFindNumJunctions + 1].direction = nextTestEdge;
}
PeepPathfindHeuristicSearch(
{ loc.x, loc.y, height }, peep, tileElement, nextInPatrolArea, counter, endScore, next_test_edge, endJunctions,
junctionList, directionList, endXYZ, endSteps);
{ loc.x, loc.y, height }, goal, peep, tileElement, nextInPatrolArea, numSteps, endScore, nextTestEdge,
endJunctions, junctionList, directionList, endXYZ, endSteps);
_peepPathFindNumJunctions = savedNumJunctions;
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO(
"[%03d] Returned to %d,%d,%d edge: %d; Score: %d", counter, loc.x >> 5, loc.y >> 5, loc.z, next_test_edge,
*endScore);
"[%03d] Returned to %d,%d,%d edge: %d; Score: %d", numSteps, loc.x >> 5, loc.y >> 5, loc.z,
nextTestEdge, *endScore);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
} while ((next_test_edge = UtilBitScanForward(edges)) != -1);
} while ((nextTestEdge = UtilBitScanForward(edges)) != -1);
} while (!(tileElement++)->IsLastForTile());
@ -1239,7 +1241,8 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Returning from %d,%d,%d; No relevant map element found", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO(
"[%03d] Returning from %d,%d,%d; No relevant map element found", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
}
@ -1248,7 +1251,7 @@ static void PeepPathfindHeuristicSearch(
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_INFO("[%03d] Returning from %d,%d,%d; All map elements checked", counter, loc.x >> 5, loc.y >> 5, loc.z);
LOG_INFO("[%03d] Returning from %d,%d,%d; All map elements checked", numSteps, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
}
@ -1261,7 +1264,7 @@ static void PeepPathfindHeuristicSearch(
*
* rct2: 0x0069A5F0
*/
Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& peep)
Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep)
{
PROFILED_FUNCTION();
@ -1271,22 +1274,18 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
/* The max number of tiles to check - a whole-search limit.
* Mainly to limit the performance impact of the path finding. */
int32_t maxTilesChecked = (peep.Is<Staff>()) ? 50000 : 15000;
// Used to allow walking through no entry banners
_peepPathFindIsStaff = peep.Is<Staff>();
TileCoordsXYZ goal = gPeepPathFindGoalPosition;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
{
LOG_VERBOSE(
"Choose direction for %s for goal %d,%d,%d from %d,%d,%d", _pathFindDebugPeepName, goal.x, goal.y, goal.z, loc.x,
loc.y, loc.z);
"Choose direction for %s for goal %d,%d,%d from %d,%d,%d", _pathFindDebugPeepName, goal.x, goal.y, goal.z,
loc.x, loc.y, loc.z);
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
// Get the path element at this location
TileElement* dest_tile_element = MapGetFirstElementAt(loc);
TileElement* destTileElement = MapGetFirstElementAt(loc);
/* Where there are multiple matching map elements placed with zero
* clearance, save the first one for later use to determine the path
* slope - this maintains the original behaviour (which only processes
@ -1302,23 +1301,23 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* EXPECT to experience path finding irregularities due to those paths!
* In particular common edges at different heights will not work
* in a useful way. Simply do not do it! :-) */
TileElement* first_tile_element = nullptr;
TileElement* firstTileElement = nullptr;
bool found = false;
uint8_t permitted_edges = 0;
uint8_t permittedEdges = 0;
bool isThin = false;
do
{
if (dest_tile_element == nullptr)
if (destTileElement == nullptr)
break;
if (dest_tile_element->BaseHeight != loc.z)
if (destTileElement->BaseHeight != loc.z)
continue;
if (dest_tile_element->GetType() != TileElementType::Path)
if (destTileElement->GetType() != TileElementType::Path)
continue;
found = true;
if (first_tile_element == nullptr)
if (firstTileElement == nullptr)
{
first_tile_element = dest_tile_element;
firstTileElement = destTileElement;
}
/* Check if this path element is a thin junction.
@ -1327,17 +1326,17 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* check if the combination is 'thin'!
* The junction is considered 'thin' simply if any of the
* overlaid path elements there is a 'thin junction'. */
isThin = isThin || PathIsThinJunction(dest_tile_element->AsPath(), loc);
isThin = isThin || PathIsThinJunction(destTileElement->AsPath(), loc);
// Collect the permitted edges of ALL matching path elements at this location.
permitted_edges |= PathGetPermittedEdges(dest_tile_element->AsPath());
} while (!(dest_tile_element++)->IsLastForTile());
permittedEdges |= PathGetPermittedEdges(peep.Is<Staff>(), destTileElement->AsPath());
} while (!(destTileElement++)->IsLastForTile());
// Peep is not on a path.
if (!found)
return INVALID_DIRECTION;
permitted_edges &= 0xF;
uint8_t edges = permitted_edges;
permittedEdges &= 0xF;
uint8_t edges = permittedEdges;
if (isThin && peep.PathfindGoal == goal)
{
/* Use of peep.PathfindHistory[]:
@ -1365,7 +1364,7 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* changes or in earlier code .directions was
* initialised to 0xF rather than the permitted
* edges. */
pathfindHistory.direction &= permitted_edges;
pathfindHistory.direction &= permittedEdges;
edges = pathfindHistory.direction;
@ -1388,7 +1387,7 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* the paths or the pathfinding itself
* has changed (been fixed) since
* the game was saved. */
pathfindHistory.direction = permitted_edges;
pathfindHistory.direction = permittedEdges;
edges = pathfindHistory.direction;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
@ -1426,13 +1425,13 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
if (edges == 0)
return INVALID_DIRECTION;
int32_t chosen_edge = UtilBitScanForward(edges);
int32_t chosenEdge = UtilBitScanForward(edges);
// Peep has multiple edges still to try.
if (edges & ~(1 << chosen_edge))
if (edges & ~(1 << chosenEdge))
{
uint16_t best_score = 0xFFFF;
uint8_t best_sub = 0xFF;
uint16_t bestScore = 0xFFFF;
uint8_t bestSub = 0xFF;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
uint8_t bestJunctions = 0;
@ -1451,12 +1450,12 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* or for different edges with equal value, the edge with the
* least steps (best_sub). */
int32_t numEdges = BitCount(edges);
for (int32_t test_edge = chosen_edge; test_edge != -1; test_edge = UtilBitScanForward(edges))
for (int32_t testEdge = chosenEdge; testEdge != -1; testEdge = UtilBitScanForward(edges))
{
edges &= ~(1 << test_edge);
edges &= ~(1 << testEdge);
uint8_t height = loc.z;
if (first_tile_element->AsPath()->IsSloped() && first_tile_element->AsPath()->GetSlopeDirection() == test_edge)
if (firstTileElement->AsPath()->IsSloped() && firstTileElement->AsPath()->GetSlopeDirection() == testEdge)
{
height += 0x2;
}
@ -1515,19 +1514,19 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
#if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
if (gPathFindDebug)
{
LOG_VERBOSE("Pathfind searching in direction: %d from %d,%d,%d", test_edge, loc.x >> 5, loc.y >> 5, loc.z);
LOG_VERBOSE("Pathfind searching in direction: %d from %d,%d,%d", testEdge, loc.x >> 5, loc.y >> 5, loc.z);
}
#endif // defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2
PeepPathfindHeuristicSearch(
{ loc.x, loc.y, height }, peep, first_tile_element, inPatrolArea, 0, &score, test_edge, &endJunctions,
{ loc.x, loc.y, height }, goal, peep, firstTileElement, inPatrolArea, 0, &score, testEdge, &endJunctions,
endJunctionList, endDirectionList, &endXYZ, &endSteps);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
{
LOG_VERBOSE(
"Pathfind test edge: %d score: %d steps: %d end: %d,%d,%d junctions: %d", test_edge, score, endSteps,
"Pathfind test edge: %d score: %d steps: %d end: %d,%d,%d junctions: %d", testEdge, score, endSteps,
endXYZ.x, endXYZ.y, endXYZ.z, endJunctions);
for (uint8_t listIdx = 0; listIdx < endJunctions; listIdx++)
{
@ -1538,11 +1537,11 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (score < best_score || (score == best_score && endSteps < best_sub))
if (score < bestScore || (score == bestScore && endSteps < bestSub))
{
chosen_edge = test_edge;
best_score = score;
best_sub = endSteps;
chosenEdge = testEdge;
bestScore = score;
bestSub = endSteps;
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
bestJunctions = endJunctions;
for (uint8_t index = 0; index < endJunctions; index++)
@ -1562,7 +1561,7 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
/* Check if the heuristic search failed. e.g. all connected
* paths are within the search limits and none reaches the
* goal. */
if (best_score == 0xFFFF)
if (bestScore == 0xFFFF)
{
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
@ -1575,12 +1574,12 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
{
LOG_VERBOSE("Pathfind best edge %d with score %d steps %d", chosen_edge, best_score, best_sub);
LOG_VERBOSE("Pathfind best edge %d with score %d steps %d", chosenEdge, bestScore, bestSub);
for (uint8_t listIdx = 0; listIdx < bestJunctions; listIdx++)
{
LOG_VERBOSE(
"Junction#%d %d,%d,%d Direction %d", listIdx + 1, bestJunctionList[listIdx].x, bestJunctionList[listIdx].y,
bestJunctionList[listIdx].z, bestDirectionList[listIdx]);
"Junction#%d %d,%d,%d Direction %d", listIdx + 1, bestJunctionList[listIdx].x,
bestJunctionList[listIdx].y, bestJunctionList[listIdx].z, bestDirectionList[listIdx]);
}
LOG_VERBOSE("End at %d,%d,%d", bestXYZ.x, bestXYZ.y, bestXYZ.z);
}
@ -1595,7 +1594,7 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
{
/* Peep remembers this junction, so remove the
* chosen_edge from those left to try. */
peep.PathfindHistory[i].direction &= ~(1 << chosen_edge);
peep.PathfindHistory[i].direction &= ~(1 << chosenEdge);
/* Also remove the edge through which the peep
* entered the junction from those left to try. */
peep.PathfindHistory[i].direction &= ~(1 << DirectionReverse(peep.PeepDirection));
@ -1604,10 +1603,10 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
{
LOG_VERBOSE(
"Updating existing pf_history (in index: %u) for %d,%d,%d without entry edge %d & exit edge %d.", i,
loc.x, loc.y, loc.z, DirectionReverse(peep.PeepDirection), chosen_edge);
loc.x, loc.y, loc.z, DirectionReverse(peep.PeepDirection), chosenEdge);
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
return chosen_edge;
return chosenEdge;
}
}
@ -1615,9 +1614,9 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
* and remember this junction. */
int32_t i = peep.PathfindGoal.direction++;
peep.PathfindGoal.direction &= 3;
peep.PathfindHistory[i] = { loc, permitted_edges };
peep.PathfindHistory[i] = { loc, permittedEdges };
/* Remove the chosen_edge from those left to try. */
peep.PathfindHistory[i].direction &= ~(1 << chosen_edge);
peep.PathfindHistory[i].direction &= ~(1 << chosenEdge);
/* Also remove the edge through which the peep
* entered the junction from those left to try. */
peep.PathfindHistory[i].direction &= ~(1 << DirectionReverse(peep.PeepDirection));
@ -1626,12 +1625,12 @@ Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& p
{
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,
loc.z, DirectionReverse(peep.PeepDirection), chosen_edge);
loc.z, DirectionReverse(peep.PeepDirection), chosenEdge);
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
}
return chosen_edge;
return chosenEdge;
}
/**
@ -1660,7 +1659,7 @@ static std::optional<CoordsXYZ> GetNearestParkEntrance(const CoordsXY& loc)
*
* rct2: 0x006952C0
*/
int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep& peep, uint8_t edges)
int32_t GuestPathFindParkEntranceEntering(Peep& peep, uint8_t edges)
{
// Send peeps to the nearest park entrance.
auto chosenEntrance = GetNearestParkEntrance(peep.NextLoc);
@ -1669,11 +1668,11 @@ int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep& peep, uint8
if (!chosenEntrance.has_value())
return GuestPathfindAimless(peep, edges);
gPeepPathFindGoalPosition = TileCoordsXYZ(chosenEntrance.value());
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
const auto goalPos = TileCoordsXYZ(chosenEntrance.value());
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep);
if (chosenDirection == INVALID_DIRECTION)
return GuestPathfindAimless(peep, edges);
@ -1709,7 +1708,7 @@ static uint8_t GetNearestPeepSpawnIndex(uint16_t x, uint16_t y)
*
* rct2: 0x0069536C
*/
int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep& peep, uint8_t edges)
int32_t GuestPathFindPeepSpawn(Peep& peep, uint8_t edges)
{
// Send peeps to the nearest spawn point.
uint8_t chosenSpawn = GetNearestPeepSpawnIndex(peep.NextLoc.x, peep.NextLoc.y);
@ -1721,7 +1720,6 @@ int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep& peep, uint8_t edges)
const auto peepSpawnLoc = gPeepSpawns[chosenSpawn].ToTileStart();
Direction direction = peepSpawnLoc.direction;
gPeepPathFindGoalPosition = TileCoordsXYZ(peepSpawnLoc);
if (peepSpawnLoc.x == peep.NextLoc.x && peepSpawnLoc.y == peep.NextLoc.y)
{
return PeepMoveOneTile(direction, peep);
@ -1729,7 +1727,9 @@ int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep& peep, uint8_t edges)
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
const auto goalPos = TileCoordsXYZ(peepSpawnLoc);
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep);
if (direction == INVALID_DIRECTION)
return GuestPathfindAimless(peep, edges);
@ -1740,7 +1740,7 @@ int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep& peep, uint8_t edges)
*
* rct2: 0x00695161
*/
int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges)
int32_t GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges)
{
TileCoordsXYZ entranceGoal{};
if (peep.PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)
@ -1765,7 +1765,6 @@ int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep& peep, uint8_
entranceGoal = TileCoordsXYZ(*chosenEntrance);
}
gPeepPathFindGoalPosition = entranceGoal;
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
@ -1773,7 +1772,7 @@ int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep& peep, uint8_
PathfindLoggingEnable(peep);
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, entranceGoal, peep);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingDisable();
@ -1970,7 +1969,7 @@ static StationIndex GuestPathfindingSelectRandomStation(
*
* rct2: 0x00694C35
*/
int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
int32_t CalculateNextDestination(Guest& peep)
{
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindLoggingEnable(peep);
@ -1993,8 +1992,8 @@ int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
return 1;
}
_peepPathFindIsStaff = false;
uint8_t edges = PathGetPermittedEdges(pathElement);
// Because this function is called for guests only, never ignore banners.
uint8_t edges = PathGetPermittedEdges(false, pathElement);
if (edges == 0)
{
@ -2231,10 +2230,9 @@ int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
GetRideQueueEnd(loc);
gPeepPathFindGoalPosition = loc;
gPeepPathFindIgnoreForeignQueues = true;
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep);
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, loc, peep);
if (direction == INVALID_DIRECTION)
{
@ -2250,7 +2248,8 @@ int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
if (_pathFindDebug)
{
LOG_INFO(
"Completed CalculateNextDestination for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName);
"Completed CalculateNextDestination for %s - failed to choose a direction == aimless.",
_pathFindDebugPeepName);
}
PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
@ -2267,7 +2266,7 @@ int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep)
return PeepMoveOneTile(direction, peep);
}
bool GuestPathfinding::IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection)
bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection)
{
if (tileElement->AsPath()->IsSloped())
{
@ -2294,23 +2293,6 @@ bool GuestPathfinding::IsValidPathZAndDirection(TileElement* tileElement, int32_
return true;
}
/**
*
* rct2: 0x0069A98C
*/
void Peep::ResetPathfindGoal()
{
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
if (_pathFindDebug)
{
LOG_INFO("Resetting PathfindGoal for %s", _pathFindDebugPeepName);
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
PathfindGoal.SetNull();
PathfindGoal.direction = INVALID_DIRECTION;
}
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
void PathfindLoggingEnable([[maybe_unused]] Peep& peep)
{
@ -2342,3 +2324,5 @@ void PathfindLoggingDisable()
# endif // defined(PATHFIND_DEBUG) && PATHFIND_DEBUG
}
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
} // namespace OpenRCT2::PathFinding

View File

@ -19,13 +19,6 @@ 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).
//
// This gets copied into Peep::PathfindGoal. The two separate variables are needed because
// when the goal changes the peep's pathfind history needs to be reset.
extern TileCoordsXYZ gPeepPathFindGoalPosition;
// When the heuristic pathfinder is examining neighboring tiles, one possibility is that it finds a
// queue tile; furthermore, this queue tile may or may not be for the ride that the peep is trying
// to get to, if any. This first var is used to store the ride that the peep is currently headed to.
@ -39,58 +32,19 @@ extern RideId gPeepPathFindQueueRideIndex;
// In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL.
extern bool gPeepPathFindIgnoreForeignQueues;
class GuestPathfinding
namespace OpenRCT2::PathFinding
{
public:
virtual ~GuestPathfinding() = default;
Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep);
/**
* 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.
*
* @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;
int32_t CalculateNextDestination(Guest& peep);
/**
* Test whether the given tile can be walked onto, if the peep is currently at height currentZ and
* moving in direction currentDirection
*
* @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 final : 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;
bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection);
#if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
# define PATHFIND_DEBUG \
@ -104,3 +58,5 @@ extern std::unique_ptr<GuestPathfinding> gGuestPathfinder;
void PathfindLoggingEnable(Peep& peep);
void PathfindLoggingDisable();
#endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1
}; // namespace OpenRCT2::PathFinding

View File

@ -85,8 +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 = gGuestPathfinder->ChooseDirection(*pos, *peep);
const Direction moveDir = PathFinding::ChooseDirection(*pos, goal, *peep);
if (moveDir == INVALID_DIRECTION)
{
// Couldn't determine a direction to move off in