Improve pathfinder support for multiple docks
The pathfinder can now find docks other than the Manhattan closest one. Based on Cirdan commits: afc7969c13d7ca59afe4dae4bf88122ba8d27df2 4067190dedcd3e5f668ea4f49b1dd8dfed10b2a7 d9be6b712d2ae4fb1b5ae844dde4919dd24c4fb2
This commit is contained in:
@@ -160,8 +160,8 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
||||
uint dist;
|
||||
AyStarUserData *user = (AyStarUserData *)as->user_data;
|
||||
|
||||
/* for train-stations, we are going to aim for the closest station tile */
|
||||
if (user->type != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) {
|
||||
/* for stations, we are going to aim for the closest station tile */
|
||||
if (fstd->station_index != INVALID_STATION) {
|
||||
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
||||
}
|
||||
|
||||
@@ -558,16 +558,16 @@ static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current)
|
||||
AyStarNode *node = ¤t->path.node;
|
||||
TileIndex tile = node->tile;
|
||||
|
||||
if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
||||
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
assert(fstd->v->type == VEH_ROAD);
|
||||
/* Only if it is a valid station *and* we can stop there */
|
||||
if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE;
|
||||
if (fstd->station_index == INVALID_STATION) {
|
||||
return (tile == fstd->dest_coords) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
}
|
||||
|
||||
switch (fstd->v->type) {
|
||||
default: NOT_REACHED();
|
||||
case VEH_TRAIN: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
case VEH_ROAD: return (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index && GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
case VEH_SHIP: return Station::Get(fstd->station_index)->IsDockingTile(tile) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
|
||||
}
|
||||
return AYSTAR_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1099,16 +1099,12 @@ void InitializeNPF()
|
||||
|
||||
static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false)
|
||||
{
|
||||
/* Ships don't really reach their stations, but the tile in front. So don't
|
||||
* save the station id for ships. For roadvehs we don't store it either,
|
||||
* because multistop depends on vehicles actually reaching the exact
|
||||
* dest_tile, not just any stop of that station.
|
||||
* So only for train orders to stations we fill fstd->station_index, for all
|
||||
* others only dest_coords */
|
||||
if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
||||
assert(v->IsGroundVehicle());
|
||||
/* Fill station_index for station orders, else only dest_coords. */
|
||||
if (v->current_order.IsType(OT_GOTO_STATION) || (v->type != VEH_SHIP && v->current_order.IsType(OT_GOTO_WAYPOINT))) {
|
||||
fstd->station_index = v->current_order.GetDestination();
|
||||
fstd->station_type = (v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) : (RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK);
|
||||
fstd->station_type = (v->type == VEH_SHIP) ? STATION_DOCK :
|
||||
(v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) :
|
||||
(RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK);
|
||||
fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart();
|
||||
/* Let's take the closest tile of the station as our target for vehicles */
|
||||
fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type);
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "../../tunnelbridge_map.h"
|
||||
#include "../../tunnelbridge.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../station_base.h"
|
||||
#include "../../core/random_func.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
@@ -25,6 +26,7 @@ struct RememberData {
|
||||
|
||||
struct TrackPathFinder {
|
||||
TileIndex skiptile;
|
||||
StationID dest_station;
|
||||
TileIndex dest_coords;
|
||||
uint best_bird_dist;
|
||||
uint best_length;
|
||||
@@ -35,7 +37,14 @@ struct TrackPathFinder {
|
||||
static bool ShipTrackFollower(TileIndex tile, TrackPathFinder *pfs, uint length)
|
||||
{
|
||||
/* Found dest? */
|
||||
if (tile == pfs->dest_coords) {
|
||||
if (pfs->dest_station != INVALID_STATION) {
|
||||
if (Station::Get(pfs->dest_station)->IsDockingTile(tile)) {
|
||||
pfs->best_bird_dist = 0;
|
||||
|
||||
pfs->best_length = minu(pfs->best_length, length);
|
||||
return true;
|
||||
}
|
||||
} else if (tile == pfs->dest_coords) {
|
||||
pfs->best_bird_dist = 0;
|
||||
|
||||
pfs->best_length = minu(pfs->best_length, length);
|
||||
@@ -140,6 +149,7 @@ static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, Trac
|
||||
uint best_length = 0;
|
||||
byte ship_dir = v->direction & 3;
|
||||
|
||||
pfs.dest_station = v->current_order.IsType(OT_GOTO_STATION) ? v->current_order.GetDestination() : INVALID_STATION;
|
||||
pfs.dest_coords = v->dest_tile;
|
||||
pfs.skiptile = skiptile;
|
||||
|
||||
|
@@ -110,72 +110,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** YAPF destination provider base class - used when destination is single tile / multiple trackdirs */
|
||||
template <class Types>
|
||||
class CYapfDestinationTileT
|
||||
{
|
||||
public:
|
||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||||
typedef typename Node::Key Key; ///< key to hash tables
|
||||
|
||||
protected:
|
||||
TileIndex m_destTile; ///< destination tile
|
||||
TrackdirBits m_destTrackdirs; ///< destination trackdir mask
|
||||
|
||||
public:
|
||||
/** set the destination tile / more trackdirs */
|
||||
void SetDestination(TileIndex tile, TrackdirBits trackdirs)
|
||||
{
|
||||
m_destTile = tile;
|
||||
m_destTrackdirs = trackdirs;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** to access inherited path finder */
|
||||
Tpf& Yapf()
|
||||
{
|
||||
return *static_cast<Tpf *>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Called by YAPF to detect if node ends in the desired destination */
|
||||
inline bool PfDetectDestination(Node &n)
|
||||
{
|
||||
bool bDest = (n.m_key.m_tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(n.GetTrackdir())) != TRACKDIR_BIT_NONE);
|
||||
return bDest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
||||
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
||||
*/
|
||||
inline bool PfCalcEstimate(Node &n)
|
||||
{
|
||||
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
||||
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
||||
if (PfDetectDestination(n)) {
|
||||
n.m_estimate = n.m_cost;
|
||||
return true;
|
||||
}
|
||||
|
||||
TileIndex tile = n.GetTile();
|
||||
DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir());
|
||||
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
||||
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
||||
int x2 = 2 * TileX(m_destTile);
|
||||
int y2 = 2 * TileY(m_destTile);
|
||||
int dx = abs(x1 - x2);
|
||||
int dy = abs(y1 - y2);
|
||||
int dmin = min(dx, dy);
|
||||
int dxy = abs(dx - dy);
|
||||
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
||||
n.m_estimate = n.m_cost + d;
|
||||
assert(n.m_estimate >= n.m_parent->m_estimate);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* YAPF template that uses Ttypes template argument to determine all YAPF
|
||||
* components (base classes) from which the actual YAPF is composed.
|
||||
|
@@ -75,14 +75,12 @@ public:
|
||||
|
||||
/* convert origin trackdir to TrackdirBits */
|
||||
TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
|
||||
/* get available trackdirs on the destination tile */
|
||||
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
||||
|
||||
/* create pathfinder instance */
|
||||
Tpf pf;
|
||||
/* set origin and destination nodes */
|
||||
pf.SetOrigin(src_tile, trackdirs);
|
||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
||||
pf.SetDestination(v);
|
||||
/* find best path */
|
||||
path_found = pf.FindPath(v);
|
||||
|
||||
@@ -115,14 +113,11 @@ public:
|
||||
*/
|
||||
static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
|
||||
{
|
||||
/* get available trackdirs on the destination tile */
|
||||
TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
||||
|
||||
/* create pathfinder instance */
|
||||
Tpf pf;
|
||||
/* set origin and destination nodes */
|
||||
pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
|
||||
pf.SetDestination(v->dest_tile, dest_trackdirs);
|
||||
pf.SetDestination(v);
|
||||
/* find best path */
|
||||
if (!pf.FindPath(v)) return false;
|
||||
|
||||
@@ -188,6 +183,80 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** YAPF destination provider for ships */
|
||||
template <class Types>
|
||||
class CYapfDestinationShipT
|
||||
{
|
||||
public:
|
||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||
typedef typename Types::NodeList::Titem Node; ///< this will be our node type
|
||||
typedef typename Node::Key Key; ///< key to hash tables
|
||||
|
||||
protected:
|
||||
StationID m_destStation; ///< destinatin station
|
||||
TileIndex m_destTile; ///< destination tile
|
||||
|
||||
public:
|
||||
/** set the destination */
|
||||
void SetDestination(const Ship *v)
|
||||
{
|
||||
if (v->current_order.IsType(OT_GOTO_STATION)) {
|
||||
m_destStation = v->current_order.GetDestination();
|
||||
m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK);
|
||||
} else {
|
||||
m_destStation = INVALID_STATION;
|
||||
m_destTile = v->dest_tile;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** to access inherited path finder */
|
||||
Tpf& Yapf()
|
||||
{
|
||||
return *static_cast<Tpf *>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Called by YAPF to detect if node ends in the desired destination */
|
||||
inline bool PfDetectDestination(Node &n)
|
||||
{
|
||||
if (m_destStation == INVALID_STATION) {
|
||||
return n.m_key.m_tile == m_destTile;
|
||||
} else {
|
||||
return Station::Get(m_destStation)->IsDockingTile(n.m_key.m_tile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate cost estimate. Calculates distance to the destination
|
||||
* adds it to the actual cost from origin and stores the sum to the Node::m_estimate
|
||||
*/
|
||||
inline bool PfCalcEstimate(Node &n)
|
||||
{
|
||||
static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
|
||||
static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
|
||||
if (PfDetectDestination(n)) {
|
||||
n.m_estimate = n.m_cost;
|
||||
return true;
|
||||
}
|
||||
|
||||
TileIndex tile = n.GetTile();
|
||||
DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir());
|
||||
int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
|
||||
int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
|
||||
int x2 = 2 * TileX(m_destTile);
|
||||
int y2 = 2 * TileY(m_destTile);
|
||||
int dx = abs(x1 - x2);
|
||||
int dy = abs(y1 - y2);
|
||||
int dmin = min(dx, dy);
|
||||
int dxy = abs(dx - dy);
|
||||
int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
|
||||
n.m_estimate = n.m_cost + d;
|
||||
assert(n.m_estimate >= n.m_parent->m_estimate);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Config struct of YAPF for ships.
|
||||
* Defines all 6 base YAPF modules as classes providing services for CYapfBaseT.
|
||||
@@ -209,7 +278,7 @@ struct CYapfShip_TypesT
|
||||
typedef CYapfBaseT<Types> PfBase; // base pathfinder class
|
||||
typedef CYapfFollowShipT<Types> PfFollow; // node follower
|
||||
typedef CYapfOriginTileT<Types> PfOrigin; // origin provider
|
||||
typedef CYapfDestinationTileT<Types> PfDestination; // destination/distance provider
|
||||
typedef CYapfDestinationShipT<Types> PfDestination; // destination/distance provider
|
||||
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
||||
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
||||
};
|
||||
|
Reference in New Issue
Block a user