mirror of https://github.com/OpenRCT2/OpenRCT2.git
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:
parent
fdbdbd405f
commit
9d9f0af0cd
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue