1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Merge pull request #22866 from ZehMatt/pathfinding-cleanup-2

Refactor work for pathfinding
This commit is contained in:
Matt
2024-09-30 22:46:59 +03:00
committed by GitHub
6 changed files with 149 additions and 159 deletions

View File

@@ -183,7 +183,8 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons
}
/* test_element is a path */
if (!PathFinding::IsValidPathZAndDirection(test_element, adjacPos.z / kCoordsZStep, adjac_dir))
const auto* adjacentPathElement = test_element->AsPath();
if (!FootpathIsZAndDirectionValid(*adjacentPathElement, adjacPos.z / kCoordsZStep, adjac_dir))
continue;
/* test_element is a connected path */
@@ -193,7 +194,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons
pathcount++;
}
if (test_element->AsPath()->IsWide())
if (adjacentPathElement->IsWide())
{
if (!widefound)
{
@@ -713,11 +714,9 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat
}
}
gPeepPathFindIgnoreForeignQueues = false;
gPeepPathFindQueueRideIndex = RideId::GetNull();
const auto goalPos = TileCoordsXYZ{ location };
Direction pathfindDirection = PathFinding::ChooseDirection(TileCoordsXYZ{ NextLoc }, goalPos, *this);
Direction pathfindDirection = PathFinding::ChooseDirection(
TileCoordsXYZ{ NextLoc }, goalPos, *this, false, RideId::GetNull());
if (pathfindDirection == INVALID_DIRECTION)
{
/* Heuristic search failed for all directions.

View File

@@ -28,27 +28,37 @@
#include <cassert>
#include <cstring>
bool gPeepPathFindIgnoreForeignQueues;
RideId gPeepPathFindQueueRideIndex;
namespace OpenRCT2::PathFinding
{
static int8_t _peepPathFindNumJunctions;
static int8_t _peepPathFindMaxJunctions;
static int32_t _peepPathFindTilesChecked;
// The search limits the maximum junctions by certain conditions.
static constexpr uint8_t kMaxJunctionsStaff = 8;
static constexpr uint8_t kMaxJunctionsGuest = 5;
static constexpr uint8_t kMaxJunctionsGuestWithMap = 7;
static constexpr uint8_t kMaxJunctionsGuestLeavingPark = 7;
static constexpr uint8_t kMaxJunctionsGuestLeavingParkLost = 8;
// Maximum amount of junctions.
static constexpr uint8_t kMaxJunctions = std::max({ kMaxJunctionsStaff, kMaxJunctionsGuest, kMaxJunctionsGuestWithMap,
kMaxJunctionsGuestLeavingPark, kMaxJunctionsGuestLeavingParkLost });
struct PathFindingState
{
int8_t junctionCount;
int8_t maxJunctions;
int32_t countTilesChecked;
// TODO: Move them, those are query parameters not really state, but for now its easier to pass it down.
bool ignoreForeignQueues;
RideId queueRideIndex;
// A junction history for the peep path finding heuristic search.
struct
{
TileCoordsXYZ location;
Direction direction;
} history[kMaxJunctions + 1];
};
static int32_t GuestSurfacePathFinding(Peep& peep);
/* A junction history for the peep pathfinding heuristic search
* The magic number 16 is the largest value returned by
* PeepPathfindGetMaxNumberJunctions() which should eventually
* be declared properly. */
static struct
{
TileCoordsXYZ location;
Direction direction;
} _peepPathFindHistory[16];
enum class PathSearchResult
{
DeadEnd, // Path is a dead end, i.e. < 2 edges.
@@ -130,14 +140,14 @@ namespace OpenRCT2::PathFinding
}
#pragma endregion
static TileElement* GetBannerOnPath(TileElement* pathElement)
static const TileElement* GetBannerOnPath(const TileElement* pathElement)
{
// This is an improved version of original.
// That only checked for one fence in the way.
if (pathElement->IsLastForTile())
return nullptr;
TileElement* bannerElement = pathElement + 1;
const TileElement* bannerElement = pathElement + 1;
do
{
// Path on top, so no banners
@@ -155,11 +165,11 @@ namespace OpenRCT2::PathFinding
return nullptr;
}
static int32_t BannerClearPathEdges(bool ignoreBanners, PathElement* pathElement, int32_t edges)
static int32_t BannerClearPathEdges(bool ignoreBanners, const PathElement* pathElement, int32_t edges)
{
if (ignoreBanners)
return edges;
TileElement* bannerElement = GetBannerOnPath(reinterpret_cast<TileElement*>(pathElement));
const TileElement* bannerElement = GetBannerOnPath(reinterpret_cast<const TileElement*>(pathElement));
if (bannerElement != nullptr)
{
do
@@ -173,7 +183,7 @@ namespace OpenRCT2::PathFinding
/**
* Gets the connected edges of a path that are permitted (i.e. no 'no entry' signs)
*/
static int32_t PathGetPermittedEdges(bool ignoreBanners, PathElement* pathElement)
static int32_t PathGetPermittedEdges(bool ignoreBanners, const PathElement* pathElement)
{
return BannerClearPathEdges(ignoreBanners, pathElement, pathElement->GetEdgesAndCorners()) & 0x0F;
}
@@ -348,12 +358,13 @@ namespace OpenRCT2::PathFinding
continue;
if (nextTileElement->GetType() != TileElementType::Path)
continue;
if (!IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection))
const auto* nextPathElement = nextTileElement->AsPath();
if (!FootpathIsZAndDirectionValid(*nextPathElement, loc.z, chosenDirection))
continue;
if (nextTileElement->AsPath()->IsWide())
if (nextPathElement->IsWide())
return PathSearchResult::Wide;
// Only queue tiles that are connected to a ride are returned as ride queues.
if (nextTileElement->AsPath()->IsQueue() && !nextTileElement->AsPath()->GetRideIndex().IsNull())
if (nextPathElement->IsQueue() && !nextPathElement->GetRideIndex().IsNull())
return PathSearchResult::RideQueue;
return PathSearchResult::Other;
@@ -442,12 +453,13 @@ namespace OpenRCT2::PathFinding
break;
case TileElementType::Path:
{
if (!IsValidPathZAndDirection(tileElement, loc.z, chosenDirection))
const auto* pathElement = tileElement->AsPath();
if (!FootpathIsZAndDirectionValid(*pathElement, loc.z, chosenDirection))
continue;
if (tileElement->AsPath()->IsWide())
return PathSearchResult::Wide;
uint8_t edges = PathGetPermittedEdges(ignoreBanners, tileElement->AsPath());
uint8_t edges = PathGetPermittedEdges(ignoreBanners, pathElement);
edges &= ~(1 << DirectionReverse(chosenDirection));
loc.z = tileElement->BaseHeight;
@@ -550,24 +562,25 @@ namespace OpenRCT2::PathFinding
static uint8_t PeepPathfindGetMaxNumberJunctions(Peep& peep)
{
if (peep.Is<Staff>())
return 8;
return kMaxJunctionsStaff;
auto* guest = peep.As<Guest>();
if (guest == nullptr)
return 8;
return kMaxJunctionsStaff;
if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK && guest->GuestIsLostCountdown < 90)
bool isLeavingPark = (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK) != 0;
if (isLeavingPark && guest->GuestIsLostCountdown < 90)
{
return 8;
return kMaxJunctionsGuestLeavingParkLost;
}
if (isLeavingPark)
return kMaxJunctionsGuestLeavingPark;
if (guest->HasItem(ShopItem::Map))
return 7;
return kMaxJunctionsGuestWithMap;
if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK)
return 7;
return 5;
return kMaxJunctionsGuest;
}
/**
@@ -704,9 +717,10 @@ namespace OpenRCT2::PathFinding
* rct2: 0x0069A997
*/
static void PeepPathfindHeuristicSearch(
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)
PathFindingState& state, 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)
{
PathSearchResult searchResult = PathSearchResult::Failed;
@@ -721,12 +735,12 @@ namespace OpenRCT2::PathFinding
loc += TileDirectionDelta[testEdge];
++numSteps;
_peepPathFindTilesChecked--;
state.countTilesChecked--;
/* If this is where the search started this is a search loop and the
* current search path ends here.
* Return without updating the parameters (best result so far). */
if (_peepPathFindHistory[0].location == loc)
if (state.history[0].location == loc)
{
LogPathfinding(&peep, "Return from %d,%d,%d; Steps: %u; At start", loc.x >> 5, loc.y >> 5, loc.z, numSteps);
return;
@@ -828,17 +842,17 @@ namespace OpenRCT2::PathFinding
break;
case TileElementType::Path:
{
const auto* pathElement = tileElement->AsPath();
/* For peeps heading for a ride with a queue, the goal is the last
* queue path.
* Otherwise, peeps walk on path tiles to get to the goal. */
if (!IsValidPathZAndDirection(tileElement, loc.z, testEdge))
if (!FootpathIsZAndDirectionValid(*pathElement, loc.z, testEdge))
continue;
// Path may be sloped, so set z to path base height.
loc.z = tileElement->BaseHeight;
if (tileElement->AsPath()->IsWide())
if (pathElement->IsWide())
{
/* Check if staff can ignore this wide flag. */
if (staff == nullptr || !staff->CanIgnoreWideFlag(loc.ToCoordsXYZ(), tileElement))
@@ -851,7 +865,7 @@ namespace OpenRCT2::PathFinding
searchResult = PathSearchResult::Thin;
uint8_t numEdges = std::popcount(tileElement->AsPath()->GetEdges());
uint8_t numEdges = std::popcount(pathElement->GetEdges());
if (numEdges < 2)
{
@@ -863,15 +877,14 @@ namespace OpenRCT2::PathFinding
}
else
{ // numEdges == 2
if (tileElement->AsPath()->IsQueue()
&& tileElement->AsPath()->GetRideIndex() != gPeepPathFindQueueRideIndex)
if (pathElement->IsQueue() && pathElement->GetRideIndex() != state.queueRideIndex)
{
if (gPeepPathFindIgnoreForeignQueues && !tileElement->AsPath()->GetRideIndex().IsNull())
if (state.ignoreForeignQueues && !pathElement->GetRideIndex().IsNull())
{
// Path is a queue we aren't interested in
/* The rideIndex will be useful for
* adding transport rides later. */
rideIndex = tileElement->AsPath()->GetRideIndex();
rideIndex = pathElement->GetRideIndex();
searchResult = PathSearchResult::RideQueue;
}
}
@@ -910,14 +923,14 @@ namespace OpenRCT2::PathFinding
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
*endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions;
*endJunctions = state.maxJunctions - state.junctionCount;
for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++)
{
uint8_t histIdx = _peepPathFindMaxJunctions - junctInd;
junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x;
junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y;
junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z;
directionList[junctInd] = _peepPathFindHistory[histIdx].direction;
uint8_t histIdx = state.maxJunctions - junctInd;
junctionList[junctInd].x = state.history[histIdx].location.x;
junctionList[junctInd].y = state.history[histIdx].location.y;
junctionList[junctInd].z = state.history[histIdx].location.z;
directionList[junctInd] = state.history[histIdx].direction;
}
}
LogPathfinding(
@@ -961,14 +974,14 @@ namespace OpenRCT2::PathFinding
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
*endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions;
*endJunctions = state.maxJunctions - state.junctionCount;
for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++)
{
uint8_t histIdx = _peepPathFindMaxJunctions - junctInd;
junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x;
junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y;
junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z;
directionList[junctInd] = _peepPathFindHistory[histIdx].direction;
uint8_t histIdx = state.maxJunctions - junctInd;
junctionList[junctInd].x = state.history[histIdx].location.x;
junctionList[junctInd].y = state.history[histIdx].location.y;
junctionList[junctInd].z = state.history[histIdx].location.z;
directionList[junctInd] = state.history[histIdx].direction;
}
}
LogPathfinding(
@@ -1004,7 +1017,7 @@ namespace OpenRCT2::PathFinding
/* Check if either of the search limits has been reached:
* - max number of steps or max tiles checked. */
if (numSteps >= 200 || _peepPathFindTilesChecked <= 0)
if (numSteps >= 200 || state.countTilesChecked <= 0)
{
/* The current search ends here.
* The path continues, so the goal could still be reachable from here.
@@ -1018,14 +1031,14 @@ namespace OpenRCT2::PathFinding
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
*endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions;
*endJunctions = state.maxJunctions - state.junctionCount;
for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++)
{
uint8_t histIdx = _peepPathFindMaxJunctions - junctInd;
junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x;
junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y;
junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z;
directionList[junctInd] = _peepPathFindHistory[histIdx].direction;
uint8_t histIdx = state.maxJunctions - junctInd;
junctionList[junctInd].x = state.history[histIdx].location.x;
junctionList[junctInd].y = state.history[histIdx].location.y;
junctionList[junctInd].z = state.history[histIdx].location.z;
directionList[junctInd] = state.history[histIdx].direction;
}
}
LogPathfinding(
@@ -1083,10 +1096,9 @@ namespace OpenRCT2::PathFinding
/* Check the _peepPathFindHistory to see if this junction has been
* previously passed through in the current search path.
* i.e. this is a loop in the current search path. */
for (int32_t junctionNum = _peepPathFindNumJunctions + 1; junctionNum <= _peepPathFindMaxJunctions;
junctionNum++)
for (int32_t junctionNum = state.junctionCount + 1; junctionNum <= state.maxJunctions; junctionNum++)
{
if (_peepPathFindHistory[junctionNum].location == loc)
if (state.history[junctionNum].location == loc)
{
pathLoop = true;
break;
@@ -1107,7 +1119,7 @@ namespace OpenRCT2::PathFinding
* 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 (_peepPathFindNumJunctions <= 0)
if (state.junctionCount <= 0)
{
if (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps))
{
@@ -1117,12 +1129,12 @@ namespace OpenRCT2::PathFinding
// Update the end x,y,z
*endXYZ = loc;
// Update the telemetry
*endJunctions = _peepPathFindMaxJunctions; // - _peepPathFindNumJunctions;
*endJunctions = state.maxJunctions; // - _peepPathFindNumJunctions;
for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++)
{
uint8_t histIdx = _peepPathFindMaxJunctions - junctInd;
junctionList[junctInd] = _peepPathFindHistory[histIdx].location;
directionList[junctInd] = _peepPathFindHistory[histIdx].direction;
uint8_t histIdx = state.maxJunctions - junctInd;
junctionList[junctInd] = state.history[histIdx].location;
directionList[junctInd] = state.history[histIdx].direction;
}
}
LogPathfinding(
@@ -1133,10 +1145,10 @@ namespace OpenRCT2::PathFinding
/* This junction was NOT previously visited in the current
* search path, so add the junction to the history. */
_peepPathFindHistory[_peepPathFindNumJunctions].location = loc;
state.history[state.junctionCount].location = loc;
// .direction take is added below.
_peepPathFindNumJunctions--;
state.junctionCount--;
}
}
@@ -1145,7 +1157,7 @@ namespace OpenRCT2::PathFinding
do
{
edges &= ~(1 << nextTestEdge);
uint8_t savedNumJunctions = _peepPathFindNumJunctions;
uint8_t savedNumJunctions = state.junctionCount;
uint8_t height = loc.z;
if (tileElement->AsPath()->IsSloped() && tileElement->AsPath()->GetSlopeDirection() == nextTestEdge)
@@ -1177,13 +1189,13 @@ namespace OpenRCT2::PathFinding
if (isThinJunction)
{
/* Add the current test_edge to the history. */
_peepPathFindHistory[_peepPathFindNumJunctions + 1].direction = nextTestEdge;
state.history[state.junctionCount + 1].direction = nextTestEdge;
}
PeepPathfindHeuristicSearch(
{ loc.x, loc.y, height }, goal, peep, tileElement, nextInPatrolArea, numSteps, endScore, nextTestEdge,
endJunctions, junctionList, directionList, endXYZ, endSteps);
_peepPathFindNumJunctions = savedNumJunctions;
state, { loc.x, loc.y, height }, goal, peep, tileElement, nextInPatrolArea, numSteps, endScore,
nextTestEdge, endJunctions, junctionList, directionList, endXYZ, endSteps);
state.junctionCount = savedNumJunctions;
LogPathfinding(
&peep, "Returned to %d,%d,%d; Steps: %u; edge: %d; Score: %d", loc.x >> 5, loc.y >> 5, loc.z, numSteps,
@@ -1214,12 +1226,18 @@ namespace OpenRCT2::PathFinding
*
* rct2: 0x0069A5F0
*/
Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep)
Direction ChooseDirection(
const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep, bool ignoreForeignQueues, RideId queueRideIndex)
{
PROFILED_FUNCTION();
PathFindingState state{};
state.ignoreForeignQueues = ignoreForeignQueues;
state.queueRideIndex = queueRideIndex;
// The max number of thin junctions searched - a per-search-path limit.
_peepPathFindMaxJunctions = PeepPathfindGetMaxNumberJunctions(peep);
state.maxJunctions = PeepPathfindGetMaxNumberJunctions(peep);
/* The max number of tiles to check - a whole-search limit.
* Mainly to limit the performance impact of the path finding. */
@@ -1388,12 +1406,12 @@ namespace OpenRCT2::PathFinding
/* Divide the maxTilesChecked global search limit
* between the remaining edges to ensure the search
* covers all of the remaining edges. */
_peepPathFindTilesChecked = maxTilesChecked / numEdges;
_peepPathFindNumJunctions = _peepPathFindMaxJunctions;
state.countTilesChecked = maxTilesChecked / numEdges;
state.junctionCount = state.maxJunctions;
// Initialise _peepPathFindHistory.
for (auto& entry : _peepPathFindHistory)
for (auto& entry : state.history)
{
entry.location.SetNull();
entry.direction = INVALID_DIRECTION;
@@ -1402,8 +1420,8 @@ namespace OpenRCT2::PathFinding
/* The pathfinding will only use elements
* 1.._peepPathFindMaxJunctions, so the starting point
* is placed in element 0 */
_peepPathFindHistory[0].location = loc;
_peepPathFindHistory[0].direction = 0xF;
state.history[0].location = loc;
state.history[0].direction = 0xF;
uint16_t score = 0xFFFF;
/* Variable endXYZ contains the end location of the
@@ -1440,8 +1458,8 @@ namespace OpenRCT2::PathFinding
&peep, "Pathfind searching in direction: %d from %d,%d,%d", testEdge, loc.x >> 5, loc.y >> 5, loc.z);
PeepPathfindHeuristicSearch(
{ loc.x, loc.y, height }, goal, peep, firstTileElement, inPatrolArea, 0, &score, testEdge, &endJunctions,
endJunctionList, endDirectionList, &endXYZ, &endSteps);
state, { loc.x, loc.y, height }, goal, peep, firstTileElement, inPatrolArea, 0, &score, testEdge,
&endJunctions, endJunctionList, endDirectionList, &endXYZ, &endSteps);
if constexpr (kLogPathfinding)
{
@@ -1576,11 +1594,8 @@ namespace OpenRCT2::PathFinding
if (!chosenEntrance.has_value())
return GuestPathfindAimless(peep, edges);
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
const auto goalPos = TileCoordsXYZ(chosenEntrance.value());
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep);
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep, true, RideId::GetNull());
if (chosenDirection == INVALID_DIRECTION)
return GuestPathfindAimless(peep, edges);
@@ -1633,11 +1648,8 @@ namespace OpenRCT2::PathFinding
return PeepMoveOneTile(direction, peep);
}
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
const auto goalPos = TileCoordsXYZ(peepSpawnLoc);
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep);
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep, true, RideId::GetNull());
if (direction == INVALID_DIRECTION)
return GuestPathfindAimless(peep, edges);
@@ -1673,10 +1685,7 @@ namespace OpenRCT2::PathFinding
entranceGoal = TileCoordsXYZ(*chosenEntrance);
}
gPeepPathFindIgnoreForeignQueues = true;
gPeepPathFindQueueRideIndex = RideId::GetNull();
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, entranceGoal, peep);
Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, entranceGoal, peep, true, RideId::GetNull());
if (chosenDirection == INVALID_DIRECTION)
return GuestPathfindAimless(peep, edges);
@@ -2035,9 +2044,6 @@ namespace OpenRCT2::PathFinding
return GuestPathfindAimless(peep, edges);
}
// The ride is open.
gPeepPathFindQueueRideIndex = rideIndex;
/* Find the ride's closest entrance station to the peep.
* At the same time, count how many entrance stations there are and
* which stations are entrance stations. */
@@ -2096,9 +2102,7 @@ namespace OpenRCT2::PathFinding
GetRideQueueEnd(loc);
gPeepPathFindIgnoreForeignQueues = true;
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, loc, peep);
direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, loc, peep, true, rideIndex);
if (direction == INVALID_DIRECTION)
{
@@ -2120,31 +2124,4 @@ namespace OpenRCT2::PathFinding
return PeepMoveOneTile(direction, peep);
}
bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection)
{
if (tileElement->AsPath()->IsSloped())
{
int32_t slopeDirection = tileElement->AsPath()->GetSlopeDirection();
if (slopeDirection == currentDirection)
{
if (currentZ != tileElement->BaseHeight)
return false;
}
else
{
slopeDirection = DirectionReverse(slopeDirection);
if (slopeDirection != currentDirection)
return false;
if (currentZ != tileElement->BaseHeight + 2)
return false;
}
}
else
{
if (currentZ != tileElement->BaseHeight)
return false;
}
return true;
}
} // namespace OpenRCT2::PathFinding

View File

@@ -18,22 +18,10 @@ struct Peep;
struct Guest;
struct TileElement;
// 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.
extern RideId gPeepPathFindQueueRideIndex;
// Furthermore, staff members don't care about this stuff; even if they are e.g. a mechanic headed
// to a particular ride, they have no issues with walking over queues for other rides to get there.
// This bool controls that behaviour - if true, the peep will not path over queues for rides other
// than their target ride, and if false, they will treat it like a regular path.
//
// In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL.
extern bool gPeepPathFindIgnoreForeignQueues;
namespace OpenRCT2::PathFinding
{
Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep);
Direction ChooseDirection(
const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep, bool ignoreForeignQueues, RideId queueRideIndex);
int32_t CalculateNextDestination(Guest& peep);
@@ -43,6 +31,4 @@ namespace OpenRCT2::PathFinding
int32_t GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges);
bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection);
}; // namespace OpenRCT2::PathFinding

View File

@@ -2328,3 +2328,30 @@ bool PathElement::IsLevelCrossing(const CoordsXY& coords) const
return ride->GetRideTypeDescriptor().HasFlag(RtdFlag::supportsLevelCrossings);
}
bool FootpathIsZAndDirectionValid(const PathElement& pathElement, int32_t currentZ, int32_t currentDirection)
{
if (pathElement.IsSloped())
{
int32_t slopeDirection = pathElement.GetSlopeDirection();
if (slopeDirection == currentDirection)
{
if (currentZ != pathElement.BaseHeight)
return false;
}
else
{
slopeDirection = DirectionReverse(slopeDirection);
if (slopeDirection != currentDirection)
return false;
if (currentZ != pathElement.BaseHeight + 2)
return false;
}
}
else
{
if (currentZ != pathElement.BaseHeight)
return false;
}
return true;
}

View File

@@ -186,3 +186,4 @@ const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex);
void FootpathQueueChainReset();
void FootpathQueueChainPush(RideId rideIndex);
bool FootpathIsZAndDirectionValid(const PathElement& tileElement, int32_t currentZ, int32_t currentDirection);

View File

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