Update to 1.10.0-beta1
This commit is contained in:
@@ -32,7 +32,7 @@ struct CFollowTrackT
|
||||
enum ErrorCode {
|
||||
EC_NONE,
|
||||
EC_OWNER,
|
||||
EC_RAIL_TYPE,
|
||||
EC_RAIL_ROAD_TYPE,
|
||||
EC_90DEG,
|
||||
EC_NO_WAY,
|
||||
EC_RESERVED,
|
||||
@@ -53,27 +53,28 @@ struct CFollowTrackT
|
||||
CPerformanceTimer *m_pPerf;
|
||||
RailTypes m_railtypes;
|
||||
|
||||
inline CFollowTrackT(const VehicleType *v = NULL, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL)
|
||||
inline CFollowTrackT(const VehicleType *v = nullptr, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr)
|
||||
{
|
||||
Init(v, railtype_override, pPerf);
|
||||
}
|
||||
|
||||
inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL)
|
||||
inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr)
|
||||
{
|
||||
m_veh = NULL;
|
||||
assert(IsRailTT());
|
||||
m_veh = nullptr;
|
||||
Init(o, railtype_override, pPerf);
|
||||
}
|
||||
|
||||
inline void Init(const VehicleType *v, RailTypes railtype_override, CPerformanceTimer *pPerf)
|
||||
{
|
||||
assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN));
|
||||
assert(!IsRailTT() || (v != nullptr && v->type == VEH_TRAIN));
|
||||
m_veh = v;
|
||||
Init(v != NULL ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf);
|
||||
Init(v != nullptr ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf);
|
||||
}
|
||||
|
||||
inline void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf)
|
||||
{
|
||||
assert(!IsRoadTT() || m_veh != NULL);
|
||||
assert(!IsRoadTT() || m_veh != nullptr);
|
||||
assert(!IsRailTT() || railtype_override != INVALID_RAILTYPES);
|
||||
m_veh_owner = o;
|
||||
m_pPerf = pPerf;
|
||||
@@ -92,7 +93,7 @@ struct CFollowTrackT
|
||||
inline static TransportType TT() { return Ttr_type_; }
|
||||
inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; }
|
||||
inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; }
|
||||
inline bool IsTram() { return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM); }
|
||||
inline bool IsTram() { return IsRoadTT() && RoadTypeIsTram(RoadVehicle::From(m_veh)->roadtype); }
|
||||
inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; }
|
||||
inline static bool Allow90degTurns() { return T90deg_turns_allowed_; }
|
||||
inline static bool DoTrackMasking() { return Tmask_reserved_tracks; }
|
||||
@@ -103,7 +104,7 @@ struct CFollowTrackT
|
||||
assert(IsTram()); // this function shouldn't be called in other cases
|
||||
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
|
||||
RoadBits rb = GetRoadBits(tile, RTT_TRAM);
|
||||
switch (rb) {
|
||||
case ROAD_NW: return DIAGDIR_NW;
|
||||
case ROAD_SW: return DIAGDIR_SW;
|
||||
@@ -126,7 +127,7 @@ struct CFollowTrackT
|
||||
m_err = EC_NONE;
|
||||
assert(
|
||||
((TrackStatusToTrackdirBits(
|
||||
GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != NULL) ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)
|
||||
GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != nullptr) ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0)
|
||||
) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
|
||||
(IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR) // Disable the assertion for single tram bits
|
||||
);
|
||||
@@ -151,13 +152,13 @@ struct CFollowTrackT
|
||||
if (IsRoadTT() && !IsTram() && TryReverse()) return true;
|
||||
|
||||
/* CanEnterNewTile already set a reason.
|
||||
* Do NOT overwrite it (important for example for EC_RAIL_TYPE).
|
||||
* Do NOT overwrite it (important for example for EC_RAIL_ROAD_TYPE).
|
||||
* Only set a reason if CanEnterNewTile was not called */
|
||||
if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY;
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!Allow90degTurns()) {
|
||||
if ((!IsRailTT() && !Allow90degTurns()) || (IsRailTT() && Rail90DegTurnDisallowed(GetTileRailType(m_old_tile), GetTileRailType(m_new_tile), !Allow90degTurns()))) {
|
||||
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
|
||||
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
|
||||
m_err = EC_90DEG;
|
||||
@@ -241,7 +242,7 @@ protected:
|
||||
if (IsRailTT() && IsPlainRailTile(m_new_tile)) {
|
||||
m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101);
|
||||
} else {
|
||||
m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0));
|
||||
m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0));
|
||||
|
||||
if (IsTram() && m_new_td_bits == TRACKDIR_BIT_NONE) {
|
||||
/* GetTileTrackStatus() returns 0 for single tram bits.
|
||||
@@ -350,7 +351,18 @@ protected:
|
||||
RailType rail_type = GetTileRailType(m_new_tile);
|
||||
if (!HasBit(m_railtypes, rail_type)) {
|
||||
/* incompatible rail type */
|
||||
m_err = EC_RAIL_TYPE;
|
||||
m_err = EC_RAIL_ROAD_TYPE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* road transport is possible only on compatible road types */
|
||||
if (IsRoadTT()) {
|
||||
const RoadVehicle *v = RoadVehicle::From(m_veh);
|
||||
RoadType roadtype = GetRoadType(m_new_tile, GetRoadTramType(v->roadtype));
|
||||
if (!HasBit(v->compatible_roadtypes, roadtype)) {
|
||||
/* incompatible road type */
|
||||
m_err = EC_RAIL_ROAD_TYPE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -447,7 +459,7 @@ protected:
|
||||
|
||||
public:
|
||||
/** Helper for pathfinders - get min/max speed on the m_old_tile/m_old_td */
|
||||
int GetSpeedLimit(int *pmin_speed = NULL) const
|
||||
int GetSpeedLimit(int *pmin_speed = nullptr) const
|
||||
{
|
||||
int min_speed = 0;
|
||||
int max_speed = INT_MAX; // no limit
|
||||
@@ -465,7 +477,7 @@ public:
|
||||
}
|
||||
|
||||
/* if min speed was requested, return it */
|
||||
if (pmin_speed != NULL) *pmin_speed = min_speed;
|
||||
if (pmin_speed != nullptr) *pmin_speed = min_speed;
|
||||
return max_speed;
|
||||
}
|
||||
};
|
||||
@@ -474,8 +486,6 @@ typedef CFollowTrackT<TRANSPORT_WATER, Ship, true > CFollowTrackWater;
|
||||
typedef CFollowTrackT<TRANSPORT_ROAD, RoadVehicle, true > CFollowTrackRoad;
|
||||
typedef CFollowTrackT<TRANSPORT_RAIL, Train, true > CFollowTrackRail;
|
||||
|
||||
typedef CFollowTrackT<TRANSPORT_WATER, Ship, false> CFollowTrackWaterNo90;
|
||||
typedef CFollowTrackT<TRANSPORT_ROAD, RoadVehicle, false> CFollowTrackRoadNo90;
|
||||
typedef CFollowTrackT<TRANSPORT_RAIL, Train, false> CFollowTrackRailNo90;
|
||||
|
||||
typedef CFollowTrackT<TRANSPORT_RAIL, Train, true, true > CFollowTrackFreeRail;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
/**
|
||||
* This looks in the hash whether a node exists in the closed list.
|
||||
* @param node Node to search.
|
||||
* @return The #PathNode if it is available, else \c NULL
|
||||
* @return The #PathNode if it is available, else \c nullptr
|
||||
*/
|
||||
PathNode *AyStar::ClosedListIsInList(const AyStarNode *node)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ void AyStar::ClosedListAdd(const PathNode *node)
|
||||
/**
|
||||
* Check whether a node is in the open list.
|
||||
* @param node Node to search.
|
||||
* @return If the node is available, it is returned, else \c NULL is returned.
|
||||
* @return If the node is available, it is returned, else \c nullptr is returned.
|
||||
*/
|
||||
OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node)
|
||||
{
|
||||
@@ -65,13 +65,13 @@ OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node)
|
||||
/**
|
||||
* Gets the best node from the open list.
|
||||
* It deletes the returned node from the open list.
|
||||
* @returns the best node available, or \c NULL of none is found.
|
||||
* @returns the best node available, or \c nullptr of none is found.
|
||||
*/
|
||||
OpenListNode *AyStar::OpenListPop()
|
||||
{
|
||||
/* Return the item the Queue returns.. the best next OpenList item. */
|
||||
OpenListNode *res = (OpenListNode*)this->openlist_queue.Pop();
|
||||
if (res != NULL) {
|
||||
if (res != nullptr) {
|
||||
this->openlist_hash.DeleteValue(res->path.node.tile, res->path.node.direction);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent)
|
||||
OpenListNode *check;
|
||||
|
||||
/* Check the new node against the ClosedList */
|
||||
if (this->ClosedListIsInList(current) != NULL) return;
|
||||
if (this->ClosedListIsInList(current) != nullptr) return;
|
||||
|
||||
/* Calculate the G-value for this node */
|
||||
new_g = this->CalculateG(this, current, parent);
|
||||
@@ -131,7 +131,7 @@ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent)
|
||||
|
||||
/* Check if this item is already in the OpenList */
|
||||
check = this->OpenListIsInList(current);
|
||||
if (check != NULL) {
|
||||
if (check != nullptr) {
|
||||
uint i;
|
||||
/* Yes, check if this g value is lower.. */
|
||||
if (new_g > check->g) return;
|
||||
@@ -167,11 +167,11 @@ int AyStar::Loop()
|
||||
/* Get the best node from OpenList */
|
||||
OpenListNode *current = this->OpenListPop();
|
||||
/* If empty, drop an error */
|
||||
if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
|
||||
if (current == nullptr) return AYSTAR_EMPTY_OPENLIST;
|
||||
|
||||
/* Check for end node and if found, return that code */
|
||||
if (this->EndNodeCheck(this, current) == AYSTAR_FOUND_END_NODE && !CheckIgnoreFirstTile(¤t->path)) {
|
||||
if (this->FoundEndNode != NULL) {
|
||||
if (this->FoundEndNode != nullptr) {
|
||||
this->FoundEndNode(this, current);
|
||||
}
|
||||
free(current);
|
||||
@@ -285,7 +285,7 @@ void AyStar::AddStartNode(AyStarNode *start_node, uint g)
|
||||
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
|
||||
TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
|
||||
#endif
|
||||
this->OpenListAdd(NULL, start_node, 0, g);
|
||||
this->OpenListAdd(nullptr, start_node, 0, g);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+90
-46
@@ -14,6 +14,7 @@
|
||||
#include "../../viewport_func.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../roadstop_base.h"
|
||||
#include "../../vehicle_func.h"
|
||||
#include "../pathfinder_func.h"
|
||||
#include "../pathfinder_type.h"
|
||||
#include "../follow_track.hpp"
|
||||
@@ -43,6 +44,7 @@ struct AyStarUserData {
|
||||
TransportType type;
|
||||
RailTypes railtypes;
|
||||
RoadTypes roadtypes;
|
||||
uint subtype;
|
||||
};
|
||||
|
||||
/** Indices into AyStarNode.userdata[] */
|
||||
@@ -103,7 +105,7 @@ static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value)
|
||||
|
||||
bool CheckIgnoreFirstTile(const PathNode *node)
|
||||
{
|
||||
return (node->parent == NULL && HasBit(node->node.user_data[NPF_NODE_FLAGS], NPF_FLAG_IGNORE_START_TILE));
|
||||
return (node->parent == nullptr && HasBit(node->node.user_data[NPF_NODE_FLAGS], NPF_FLAG_IGNORE_START_TILE));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,8 +166,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) {
|
||||
/* aim for the closest station tile */
|
||||
if (fstd->station_index != INVALID_STATION) {
|
||||
to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type);
|
||||
}
|
||||
|
||||
@@ -192,7 +194,7 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open
|
||||
* choice */
|
||||
static void NPFFillTrackdirChoice(AyStarNode *current, OpenListNode *parent)
|
||||
{
|
||||
if (parent->path.parent == NULL) {
|
||||
if (parent->path.parent == nullptr) {
|
||||
Trackdir trackdir = current->direction;
|
||||
/* This is a first order decision, so we'd better save the
|
||||
* direction we chose */
|
||||
@@ -302,6 +304,15 @@ static void NPFMarkTile(TileIndex tile)
|
||||
}
|
||||
}
|
||||
|
||||
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||
{
|
||||
uint *count = (uint *)data;
|
||||
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
|
||||
{
|
||||
/* TileIndex tile = current->tile; */
|
||||
@@ -318,6 +329,13 @@ static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *par
|
||||
cost += _settings_game.pf.npf.npf_water_curve_penalty;
|
||||
}
|
||||
|
||||
if (IsDockingTile(current->tile)) {
|
||||
/* Check docking tile for occupancy */
|
||||
uint count = 1;
|
||||
HasVehicleOnPos(current->tile, &count, &CountShipProc);
|
||||
cost += count * 3 * _trackdir_length[trackdir];
|
||||
}
|
||||
|
||||
/* @todo More penalties? */
|
||||
|
||||
return cost;
|
||||
@@ -562,6 +580,12 @@ static int32 NPFFindStationOrTile(const AyStar *as, const OpenListNode *current)
|
||||
|
||||
if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
if (fstd->v->type == VEH_SHIP) {
|
||||
/* Ships do not actually reach the destination station, so we check for a docking tile instead. */
|
||||
if (IsDockingTile(tile) && IsShipDestinationTile(tile, fstd->station_index)) return AYSTAR_FOUND_END_NODE;
|
||||
return AYSTAR_DONE;
|
||||
}
|
||||
|
||||
if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) {
|
||||
if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE;
|
||||
|
||||
@@ -584,7 +608,7 @@ static const PathNode *FindSafePosition(PathNode *path, const Train *v)
|
||||
/* If there is no signal, reserve the whole path. */
|
||||
PathNode *sig = path;
|
||||
|
||||
for (; path->parent != NULL; path = path->parent) {
|
||||
for (; path->parent != nullptr; path = path->parent) {
|
||||
if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) {
|
||||
sig = path;
|
||||
}
|
||||
@@ -625,7 +649,7 @@ static void NPFSaveTargetData(AyStar *as, OpenListNode *current)
|
||||
ftd->node = current->path.node;
|
||||
ftd->res_okay = false;
|
||||
|
||||
if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && user->type == TRANSPORT_RAIL) {
|
||||
if (as->user_target != nullptr && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && user->type == TRANSPORT_RAIL) {
|
||||
/* Path reservation is requested. */
|
||||
const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v);
|
||||
|
||||
@@ -647,7 +671,7 @@ static void NPFSaveTargetData(AyStar *as, OpenListNode *current)
|
||||
if (!IsWaitingPositionFree(v, target->node.tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return;
|
||||
}
|
||||
|
||||
for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) {
|
||||
for (const PathNode *cur = target; cur->parent != nullptr; cur = cur->parent) {
|
||||
if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack(cur->node.direction))) {
|
||||
/* Reservation failed, undo. */
|
||||
ClearPathReservation(target, cur);
|
||||
@@ -719,7 +743,7 @@ static DiagDirection GetDepotDirection(TileIndex tile, TransportType type)
|
||||
static DiagDirection GetSingleTramBit(TileIndex tile)
|
||||
{
|
||||
if (IsNormalRoadTile(tile)) {
|
||||
RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
|
||||
RoadBits rb = GetRoadBits(tile, RTT_TRAM);
|
||||
switch (rb) {
|
||||
case ROAD_NW: return DIAGDIR_NW;
|
||||
case ROAD_SW: return DIAGDIR_SW;
|
||||
@@ -747,7 +771,7 @@ static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint
|
||||
|
||||
if (type == TRANSPORT_ROAD) {
|
||||
if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile);
|
||||
if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile);
|
||||
if ((RoadTramType)subtype == RTT_TRAM) return GetSingleTramBit(tile);
|
||||
}
|
||||
|
||||
return INVALID_DIAGDIR;
|
||||
@@ -785,13 +809,24 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user
|
||||
if (!CanEnterTileOwnerCheck(user->owner, tile, dir)) return false;
|
||||
|
||||
/* check correct rail type (mono, maglev, etc) */
|
||||
if (user->type == TRANSPORT_RAIL) {
|
||||
RailType rail_type = GetTileRailType(tile);
|
||||
if (!HasBit(user->railtypes, rail_type)) return false;
|
||||
switch (user->type) {
|
||||
case TRANSPORT_RAIL: {
|
||||
RailType rail_type = GetTileRailType(tile);
|
||||
if (!HasBit(user->railtypes, rail_type)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case TRANSPORT_ROAD: {
|
||||
RoadType road_type = GetRoadType(tile, (RoadTramType)user->subtype);
|
||||
if (!HasBit(user->roadtypes, road_type)) return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* Depots, standard roadstops and single tram bits can only be entered from one direction */
|
||||
DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->roadtypes);
|
||||
DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->subtype);
|
||||
if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false;
|
||||
|
||||
return true;
|
||||
@@ -803,16 +838,17 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user
|
||||
* One-way-roads are taken into account. Signals are not tested.
|
||||
*
|
||||
* @param dst_tile The tile of interest.
|
||||
* @param src_tile The originating tile.
|
||||
* @param src_trackdir The direction the vehicle is currently moving.
|
||||
* @param type The transporttype of the vehicle.
|
||||
* @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle.
|
||||
* @return The Trackdirs the vehicle can continue moving on.
|
||||
*/
|
||||
static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype)
|
||||
static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, TileIndex src_tile, Trackdir src_trackdir, TransportType type, uint subtype)
|
||||
{
|
||||
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype));
|
||||
|
||||
if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) {
|
||||
if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && (RoadTramType)subtype == RTT_TRAM) {
|
||||
/* GetTileTrackStatus() returns 0 for single tram bits.
|
||||
* As we cannot change it there (easily) without breaking something, change it here */
|
||||
switch (GetSingleTramBit(dst_tile)) {
|
||||
@@ -836,7 +872,9 @@ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_tr
|
||||
trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);
|
||||
|
||||
/* Filter out trackdirs that would make 90 deg turns for trains */
|
||||
if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
|
||||
if (type == TRANSPORT_RAIL && Rail90DegTurnDisallowed(GetTileRailType(src_tile), GetTileRailType(dst_tile))) {
|
||||
trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);
|
||||
}
|
||||
|
||||
DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);
|
||||
|
||||
@@ -860,7 +898,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
|
||||
|
||||
/* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */
|
||||
TransportType type = user->type;
|
||||
uint subtype = user->roadtypes;
|
||||
uint subtype = user->subtype;
|
||||
|
||||
/* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
|
||||
aystar->num_neighbours = 0;
|
||||
@@ -877,7 +915,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
|
||||
if (CheckIgnoreFirstTile(¤t->path)) {
|
||||
/* Do not perform any checks that involve src_tile */
|
||||
dst_tile = src_tile + TileOffsByDiagDir(src_exitdir);
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
|
||||
} else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) {
|
||||
/* We drive through the wormhole and arrive on the other side */
|
||||
dst_tile = GetOtherTunnelBridgeEnd(src_tile);
|
||||
@@ -891,26 +929,26 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
|
||||
/* We leave src_tile in src_exitdir and reach dst_tile */
|
||||
dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir));
|
||||
|
||||
if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE;
|
||||
if (dst_tile != INVALID_TILE && IsNormalRoadTile(dst_tile) && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE;
|
||||
|
||||
if (dst_tile == INVALID_TILE) {
|
||||
/* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */
|
||||
if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
|
||||
if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return;
|
||||
|
||||
dst_tile = src_tile;
|
||||
src_trackdir = ReverseTrackdir(src_trackdir);
|
||||
}
|
||||
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
|
||||
|
||||
if (trackdirbits == TRACKDIR_BIT_NONE) {
|
||||
/* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */
|
||||
if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return;
|
||||
if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return;
|
||||
|
||||
dst_tile = src_tile;
|
||||
src_trackdir = ReverseTrackdir(src_trackdir);
|
||||
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype);
|
||||
trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,13 +992,13 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current)
|
||||
|
||||
/*
|
||||
* Plan a route to the specified target (which is checked by target_proc),
|
||||
* from start1 and if not NULL, from start2 as well. The type of transport we
|
||||
* from start1 and if not nullptr, from start2 as well. The type of transport we
|
||||
* are checking is in type. reverse_penalty is applied to all routes that
|
||||
* originate from the second start node.
|
||||
* When we are looking for one specific target (optionally multiple tiles), we
|
||||
* should use a good heuristic to perform aystar search. When we search for
|
||||
* multiple targets that are spread around, we should perform a breadth first
|
||||
* search by specifiying CalcZero as our heuristic.
|
||||
* search by specifying CalcZero as our heuristic.
|
||||
*/
|
||||
static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start_tile1, AyStarNode *start2, bool ignore_start_tile2, NPFFindStationOrTileData *target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, AyStarUserData *user, uint reverse_penalty, bool ignore_reserved = false, int max_penalty = 0)
|
||||
{
|
||||
@@ -986,7 +1024,7 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start
|
||||
NPFSetFlag(start1, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile1);
|
||||
NPFSetFlag(start1, NPF_FLAG_IGNORE_RESERVED, ignore_reserved);
|
||||
_npf_aystar.AddStartNode(start1, 0);
|
||||
if (start2 != NULL) {
|
||||
if (start2 != nullptr) {
|
||||
start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
|
||||
start2->user_data[NPF_NODE_FLAGS] = 0;
|
||||
NPFSetFlag(start2, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile2);
|
||||
@@ -1014,10 +1052,10 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start
|
||||
assert(r != AYSTAR_STILL_BUSY);
|
||||
|
||||
if (result.best_bird_dist != 0) {
|
||||
if (target != NULL) {
|
||||
if (target != nullptr) {
|
||||
DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile);
|
||||
} else {
|
||||
/* Assumption: target == NULL, so we are looking for a depot */
|
||||
/* Assumption: target == nullptr, so we are looking for a depot */
|
||||
DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile);
|
||||
}
|
||||
|
||||
@@ -1038,7 +1076,7 @@ static NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdi
|
||||
start1.direction = trackdir1;
|
||||
start2.direction = trackdir2;
|
||||
|
||||
return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, user, 0);
|
||||
return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : nullptr), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, user, 0);
|
||||
}
|
||||
|
||||
/* Will search from the given tile and direction, for a route to the given
|
||||
@@ -1066,9 +1104,9 @@ static NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Tra
|
||||
start1.direction = trackdir1;
|
||||
start2.direction = trackdir2;
|
||||
|
||||
/* perform a breadth first search. Target is NULL,
|
||||
/* perform a breadth first search. Target is nullptr,
|
||||
* since we are just looking for any depot...*/
|
||||
return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindDepot, NPFCalcZero, user, reverse_penalty, false, max_penalty);
|
||||
return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : nullptr), ignore_start_tile2, target, NPFFindDepot, NPFCalcZero, user, reverse_penalty, false, max_penalty);
|
||||
}
|
||||
|
||||
void InitializeNPF()
|
||||
@@ -1096,10 +1134,16 @@ static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *
|
||||
* 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());
|
||||
if (v->current_order.IsType(OT_GOTO_STATION) || 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);
|
||||
if (v->type == VEH_TRAIN) {
|
||||
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT;
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
fstd->station_type = RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK;
|
||||
} else if (v->type == VEH_SHIP) {
|
||||
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_DOCK : STATION_BUOY;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1117,8 +1161,8 @@ FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penal
|
||||
{
|
||||
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_ROAD, INVALID_RAILTYPES, v->compatible_roadtypes };
|
||||
NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, INVALID_TILE, INVALID_TRACKDIR, false, NULL, &user, 0, max_penalty);
|
||||
AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) };
|
||||
NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, INVALID_TILE, INVALID_TRACKDIR, false, nullptr, &user, 0, max_penalty);
|
||||
|
||||
if (ftd.best_bird_dist != 0) return FindDepotData();
|
||||
|
||||
@@ -1137,7 +1181,7 @@ Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDir
|
||||
NPFFillWithOrderData(&fstd, v);
|
||||
Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_ROAD, INVALID_RAILTYPES, v->compatible_roadtypes };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) };
|
||||
NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, &user);
|
||||
|
||||
assert(ftd.best_trackdir != INVALID_TRACKDIR);
|
||||
@@ -1160,7 +1204,7 @@ Track NPFShipChooseTrack(const Ship *v, bool &path_found)
|
||||
|
||||
NPFFillWithOrderData(&fstd, v);
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_WATER, INVALID_RAILTYPES, ROADTYPES_NONE };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 };
|
||||
NPFFoundTargetData ftd = NPFRouteToStationOrTile(v->tile, trackdir, true, &fstd, &user);
|
||||
|
||||
assert(ftd.best_trackdir != INVALID_TRACKDIR);
|
||||
@@ -1185,7 +1229,7 @@ bool NPFShipCheckReverse(const Ship *v)
|
||||
assert(trackdir != INVALID_TRACKDIR);
|
||||
assert(trackdir_rev != INVALID_TRACKDIR);
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_WATER, INVALID_RAILTYPES, ROADTYPES_NONE };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 };
|
||||
ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, v->tile, trackdir_rev, false, &fstd, &user);
|
||||
/* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */
|
||||
return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
|
||||
@@ -1203,7 +1247,7 @@ FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty)
|
||||
fstd.reserve_path = false;
|
||||
|
||||
assert(trackdir != INVALID_TRACKDIR);
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 };
|
||||
NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user, NPF_INFINITE_PENALTY, max_penalty);
|
||||
if (ftd.best_bird_dist != 0) return FindDepotData();
|
||||
|
||||
@@ -1230,10 +1274,10 @@ bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackd
|
||||
RailTypes railtypes = v->compatible_railtypes;
|
||||
if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes;
|
||||
|
||||
/* perform a breadth first search. Target is NULL,
|
||||
/* perform a breadth first search. Target is nullptr,
|
||||
* since we are just looking for any safe tile...*/
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE };
|
||||
return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, &user, 0, true).res_okay;
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE, 0 };
|
||||
return NPFRouteInternal(&start1, true, nullptr, false, &fstd, NPFFindSafeTile, NPFCalcZero, &user, 0, true).res_okay;
|
||||
}
|
||||
|
||||
bool NPFTrainCheckReverse(const Train *v)
|
||||
@@ -1249,7 +1293,7 @@ bool NPFTrainCheckReverse(const Train *v)
|
||||
assert(trackdir != INVALID_TRACKDIR);
|
||||
assert(trackdir_rev != INVALID_TRACKDIR);
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 };
|
||||
ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user);
|
||||
/* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */
|
||||
return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE);
|
||||
@@ -1263,10 +1307,10 @@ Track NPFTrainChooseTrack(const Train *v, bool &path_found, bool reserve_track,
|
||||
PBSTileInfo origin = FollowTrainReservation(v);
|
||||
assert(IsValidTrackdir(origin.trackdir));
|
||||
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE };
|
||||
AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 };
|
||||
NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, &user);
|
||||
|
||||
if (target != NULL) {
|
||||
if (target != nullptr) {
|
||||
target->tile = ftd.node.tile;
|
||||
target->trackdir = (Trackdir)ftd.node.direction;
|
||||
target->okay = ftd.res_okay;
|
||||
|
||||
@@ -37,7 +37,7 @@ void BinaryHeap::Clear(bool free_values)
|
||||
uint j;
|
||||
|
||||
for (i = 0; i < this->blocks; i++) {
|
||||
if (this->elements[i] == NULL) {
|
||||
if (this->elements[i] == nullptr) {
|
||||
/* No more allocated blocks */
|
||||
break;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ void BinaryHeap::Clear(bool free_values)
|
||||
if (i != 0) {
|
||||
/* Leave the first block of memory alone */
|
||||
free(this->elements[i]);
|
||||
this->elements[i] = NULL;
|
||||
this->elements[i] = nullptr;
|
||||
}
|
||||
}
|
||||
this->size = 0;
|
||||
@@ -73,7 +73,7 @@ void BinaryHeap::Free(bool free_values)
|
||||
|
||||
this->Clear(free_values);
|
||||
for (i = 0; i < this->blocks; i++) {
|
||||
if (this->elements[i] == NULL) break;
|
||||
if (this->elements[i] == nullptr) break;
|
||||
free(this->elements[i]);
|
||||
}
|
||||
free(this->elements);
|
||||
@@ -88,7 +88,7 @@ bool BinaryHeap::Push(void *item, int priority)
|
||||
if (this->size == this->max_size) return false;
|
||||
assert(this->size < this->max_size);
|
||||
|
||||
if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) {
|
||||
if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == nullptr) {
|
||||
/* The currently allocated blocks are full, allocate a new one */
|
||||
assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0);
|
||||
this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT<BinaryHeapNode>(BINARY_HEAP_BLOCKSIZE);
|
||||
@@ -195,7 +195,7 @@ void *BinaryHeap::Pop()
|
||||
{
|
||||
void *result;
|
||||
|
||||
if (this->size == 0) return NULL;
|
||||
if (this->size == 0) return nullptr;
|
||||
|
||||
/* The best item is always on top, so give that as result */
|
||||
result = this->GetElement(1).item;
|
||||
@@ -264,7 +264,7 @@ void Hash::Delete(bool free_values)
|
||||
/* Free the first value */
|
||||
if (free_values) free(this->buckets[i].value);
|
||||
node = this->buckets[i].next;
|
||||
while (node != NULL) {
|
||||
while (node != nullptr) {
|
||||
HashNode *prev = node;
|
||||
|
||||
node = node->next;
|
||||
@@ -296,7 +296,7 @@ void Hash::PrintStatistics() const
|
||||
const HashNode *node;
|
||||
|
||||
used_buckets++;
|
||||
for (node = &this->buckets[i]; node != NULL; node = node->next) collision++;
|
||||
for (node = &this->buckets[i]; node != nullptr; node = node->next) collision++;
|
||||
if (collision > max_collision) max_collision = collision;
|
||||
}
|
||||
if (collision >= lengthof(usage)) collision = lengthof(usage) - 1;
|
||||
@@ -351,7 +351,7 @@ void Hash::Clear(bool free_values)
|
||||
/* Free the first value */
|
||||
if (free_values) free(this->buckets[i].value);
|
||||
node = this->buckets[i].next;
|
||||
while (node != NULL) {
|
||||
while (node != nullptr) {
|
||||
HashNode *prev = node;
|
||||
|
||||
node = node->next;
|
||||
@@ -365,32 +365,32 @@ void Hash::Clear(bool free_values)
|
||||
|
||||
/**
|
||||
* Finds the node that that saves this key pair. If it is not
|
||||
* found, returns NULL. If it is found, *prev is set to the
|
||||
* found, returns nullptr. If it is found, *prev is set to the
|
||||
* node before the one found, or if the node found was the first in the bucket
|
||||
* to NULL. If it is not found, *prev is set to the last HashNode in the
|
||||
* bucket, or NULL if it is empty. prev can also be NULL, in which case it is
|
||||
* to nullptr. If it is not found, *prev is set to the last HashNode in the
|
||||
* bucket, or nullptr if it is empty. prev can also be nullptr, in which case it is
|
||||
* not used for output.
|
||||
*/
|
||||
HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
|
||||
{
|
||||
uint hash = this->hash(key1, key2);
|
||||
HashNode *result = NULL;
|
||||
HashNode *result = nullptr;
|
||||
|
||||
/* Check if the bucket is empty */
|
||||
if (!this->buckets_in_use[hash]) {
|
||||
if (prev_out != NULL) *prev_out = NULL;
|
||||
result = NULL;
|
||||
if (prev_out != nullptr) *prev_out = nullptr;
|
||||
result = nullptr;
|
||||
/* Check the first node specially */
|
||||
} else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) {
|
||||
/* Save the value */
|
||||
result = this->buckets + hash;
|
||||
if (prev_out != NULL) *prev_out = NULL;
|
||||
if (prev_out != nullptr) *prev_out = nullptr;
|
||||
/* Check all other nodes */
|
||||
} else {
|
||||
HashNode *prev = this->buckets + hash;
|
||||
HashNode *node;
|
||||
|
||||
for (node = prev->next; node != NULL; node = node->next) {
|
||||
for (node = prev->next; node != nullptr; node = node->next) {
|
||||
if (node->key1 == key1 && node->key2 == key2) {
|
||||
/* Found it */
|
||||
result = node;
|
||||
@@ -398,14 +398,14 @@ HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
if (prev_out != NULL) *prev_out = prev;
|
||||
if (prev_out != nullptr) *prev_out = prev;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the value with the specified key pair from the hash and returns
|
||||
* that value. Returns NULL when the value was not present. The value returned
|
||||
* that value. Returns nullptr when the value was not present. The value returned
|
||||
* is _not_ free()'d!
|
||||
*/
|
||||
void *Hash::DeleteValue(uint key1, uint key2)
|
||||
@@ -414,15 +414,15 @@ void *Hash::DeleteValue(uint key1, uint key2)
|
||||
HashNode *prev; // Used as output var for below function call
|
||||
HashNode *node = this->FindNode(key1, key2, &prev);
|
||||
|
||||
if (node == NULL) {
|
||||
if (node == nullptr) {
|
||||
/* not found */
|
||||
result = NULL;
|
||||
} else if (prev == NULL) {
|
||||
result = nullptr;
|
||||
} else if (prev == nullptr) {
|
||||
/* It is in the first node, we can't free that one, so we free
|
||||
* the next one instead (if there is any)*/
|
||||
/* Save the value */
|
||||
result = node->value;
|
||||
if (node->next != NULL) {
|
||||
if (node->next != nullptr) {
|
||||
HashNode *next = node->next;
|
||||
/* Copy the second to the first */
|
||||
*node = *next;
|
||||
@@ -443,20 +443,20 @@ void *Hash::DeleteValue(uint key1, uint key2)
|
||||
/* Free the node */
|
||||
free(node);
|
||||
}
|
||||
if (result != NULL) this->size--;
|
||||
if (result != nullptr) this->size--;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value associated with the given key pair to the given value.
|
||||
* Returns the old value if the value was replaced, NULL when it was not yet present.
|
||||
* Returns the old value if the value was replaced, nullptr when it was not yet present.
|
||||
*/
|
||||
void *Hash::Set(uint key1, uint key2, void *value)
|
||||
{
|
||||
HashNode *prev;
|
||||
HashNode *node = this->FindNode(key1, key2, &prev);
|
||||
|
||||
if (node != NULL) {
|
||||
if (node != nullptr) {
|
||||
/* Found it */
|
||||
void *result = node->value;
|
||||
|
||||
@@ -464,7 +464,7 @@ void *Hash::Set(uint key1, uint key2, void *value)
|
||||
return result;
|
||||
}
|
||||
/* It is not yet present, let's add it */
|
||||
if (prev == NULL) {
|
||||
if (prev == nullptr) {
|
||||
/* The bucket is still empty */
|
||||
uint hash = this->hash(key1, key2);
|
||||
this->buckets_in_use[hash] = true;
|
||||
@@ -474,21 +474,21 @@ void *Hash::Set(uint key1, uint key2, void *value)
|
||||
node = MallocT<HashNode>(1);
|
||||
prev->next = node;
|
||||
}
|
||||
node->next = NULL;
|
||||
node->next = nullptr;
|
||||
node->key1 = key1;
|
||||
node->key2 = key2;
|
||||
node->value = value;
|
||||
this->size++;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value associated with the given key pair, or NULL when it is not
|
||||
* Gets the value associated with the given key pair, or nullptr when it is not
|
||||
* present.
|
||||
*/
|
||||
void *Hash::Get(uint key1, uint key2) const
|
||||
{
|
||||
HashNode *node = this->FindNode(key1, key2, NULL);
|
||||
HashNode *node = this->FindNode(key1, key2, nullptr);
|
||||
|
||||
return (node != NULL) ? node->value : NULL;
|
||||
return (node != nullptr) ? node->value : nullptr;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ static const int YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH;
|
||||
/** Maximum length of ship path cache */
|
||||
static const int YAPF_SHIP_PATH_CACHE_LENGTH = 32;
|
||||
|
||||
/** Maximum segments of road vehicle path cache */
|
||||
static const int YAPF_ROADVEH_PATH_CACHE_SEGMENTS = 8;
|
||||
|
||||
/**
|
||||
* Helper container to find a depot
|
||||
*/
|
||||
|
||||
@@ -53,7 +53,7 @@ struct CPerfStartReal
|
||||
|
||||
inline CPerfStartReal(CPerformanceTimer& perf) : m_pperf(&perf)
|
||||
{
|
||||
if (m_pperf != NULL) m_pperf->Start();
|
||||
if (m_pperf != nullptr) m_pperf->Start();
|
||||
}
|
||||
|
||||
inline ~CPerfStartReal()
|
||||
@@ -63,9 +63,9 @@ struct CPerfStartReal
|
||||
|
||||
inline void Stop()
|
||||
{
|
||||
if (m_pperf != NULL) {
|
||||
if (m_pperf != nullptr) {
|
||||
m_pperf->Stop();
|
||||
m_pperf = NULL;
|
||||
m_pperf = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
/** default constructor */
|
||||
CNodeList_HashTableT() : m_open_queue(2048)
|
||||
{
|
||||
m_new_node = NULL;
|
||||
m_new_node = nullptr;
|
||||
}
|
||||
|
||||
/** destructor */
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
/** allocate new data item from m_arr */
|
||||
inline Titem_ *CreateNewNode()
|
||||
{
|
||||
if (m_new_node == NULL) m_new_node = m_arr.AppendC();
|
||||
if (m_new_node == nullptr) m_new_node = m_arr.AppendC();
|
||||
return m_new_node;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
{
|
||||
/* for now it is enough to invalidate m_new_node if it is our given node */
|
||||
if (&item == m_new_node) {
|
||||
m_new_node = NULL;
|
||||
m_new_node = nullptr;
|
||||
}
|
||||
/* TODO: do we need to store best nodes found in some extra list/array? Probably not now. */
|
||||
}
|
||||
@@ -82,11 +82,11 @@ public:
|
||||
/** insert given item as open node (into m_open and m_open_queue) */
|
||||
inline void InsertOpenNode(Titem_ &item)
|
||||
{
|
||||
assert(m_closed.Find(item.GetKey()) == NULL);
|
||||
assert(m_closed.Find(item.GetKey()) == nullptr);
|
||||
m_open.Push(item);
|
||||
m_open_queue.Include(&item);
|
||||
if (&item == m_new_node) {
|
||||
m_new_node = NULL;
|
||||
m_new_node = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
if (!m_open_queue.IsEmpty()) {
|
||||
return m_open_queue.Begin();
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** remove and return the best open node */
|
||||
@@ -107,10 +107,10 @@ public:
|
||||
m_open.Pop(*item);
|
||||
return item;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** return the open node specified by a key or NULL if not found */
|
||||
/** return the open node specified by a key or nullptr if not found */
|
||||
inline Titem_ *FindOpenNode(const Key &key)
|
||||
{
|
||||
Titem_ *item = m_open.Find(key);
|
||||
@@ -129,11 +129,11 @@ public:
|
||||
/** close node */
|
||||
inline void InsertClosedNode(Titem_ &item)
|
||||
{
|
||||
assert(m_open.Find(item.GetKey()) == NULL);
|
||||
assert(m_open.Find(item.GetKey()) == nullptr);
|
||||
m_closed.Push(item);
|
||||
}
|
||||
|
||||
/** return the closed node specified by a key or NULL if not found */
|
||||
/** return the closed node specified by a key or nullptr if not found */
|
||||
inline Titem_ *FindClosedNode(const Key &key)
|
||||
{
|
||||
Titem_ *item = m_closed.Find(key);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "../../track_type.h"
|
||||
#include "../../vehicle_type.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../roadveh.h"
|
||||
#include "../pathfinder_type.h"
|
||||
|
||||
/**
|
||||
@@ -45,7 +46,7 @@ bool YapfShipCheckReverse(const Ship *v);
|
||||
* @param path_found [out] Whether a path has been found (true) or has been guessed (false)
|
||||
* @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found
|
||||
*/
|
||||
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found);
|
||||
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache);
|
||||
|
||||
/**
|
||||
* Finds the best path for given train using YAPF.
|
||||
|
||||
@@ -81,11 +81,11 @@ public:
|
||||
public:
|
||||
/** default constructor */
|
||||
inline CYapfBaseT()
|
||||
: m_pBestDestNode(NULL)
|
||||
, m_pBestIntermediateNode(NULL)
|
||||
: m_pBestDestNode(nullptr)
|
||||
, m_pBestIntermediateNode(nullptr)
|
||||
, m_settings(&_settings_game.pf.yapf)
|
||||
, m_max_search_nodes(PfGetSettings().max_search_nodes)
|
||||
, m_veh(NULL)
|
||||
, m_veh(nullptr)
|
||||
, m_stats_cost_calcs(0)
|
||||
, m_stats_cache_hits(0)
|
||||
, m_num_steps(0)
|
||||
@@ -131,12 +131,12 @@ public:
|
||||
for (;;) {
|
||||
m_num_steps++;
|
||||
Node *n = m_nodes.GetBestOpenNode();
|
||||
if (n == NULL) {
|
||||
if (n == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* if the best open node was worse than the best path found, we can finish */
|
||||
if (m_pBestDestNode != NULL && m_pBestDestNode->GetCost() < n->GetCostEstimate()) {
|
||||
if (m_pBestDestNode != nullptr && m_pBestDestNode->GetCost() < n->GetCostEstimate()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bDestFound &= (m_pBestDestNode != NULL);
|
||||
bDestFound &= (m_pBestDestNode != nullptr);
|
||||
|
||||
perf.Stop();
|
||||
if (_debug_yapf_level >= 2) {
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
_total_pf_time_us += t;
|
||||
|
||||
if (_debug_yapf_level >= 3) {
|
||||
UnitID veh_idx = (m_veh != NULL) ? m_veh->unitnumber : 0;
|
||||
UnitID veh_idx = (m_veh != nullptr) ? m_veh->unitnumber : 0;
|
||||
char ttc = Yapf().TransportTypeChar();
|
||||
float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f);
|
||||
int cost = bDestFound ? m_pBestDestNode->m_cost : -1;
|
||||
@@ -180,7 +180,7 @@ public:
|
||||
*/
|
||||
inline Node *GetBestNode()
|
||||
{
|
||||
return (m_pBestDestNode != NULL) ? m_pBestDestNode : m_pBestIntermediateNode;
|
||||
return (m_pBestDestNode != nullptr) ? m_pBestDestNode : m_pBestIntermediateNode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
{
|
||||
Yapf().PfNodeCacheFetch(n);
|
||||
/* insert the new node only if it is not there */
|
||||
if (m_nodes.FindOpenNode(n.m_key) == NULL) {
|
||||
if (m_nodes.FindOpenNode(n.m_key) == nullptr) {
|
||||
m_nodes.InsertOpenNode(n);
|
||||
} else {
|
||||
/* if we are here, it means that node is already there - how it is possible?
|
||||
@@ -229,7 +229,7 @@ public:
|
||||
*/
|
||||
void PruneIntermediateNodeBranch()
|
||||
{
|
||||
while (Yapf().m_pBestIntermediateNode != NULL && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) {
|
||||
while (Yapf().m_pBestIntermediateNode != nullptr && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) {
|
||||
Yapf().m_pBestIntermediateNode = Yapf().m_pBestIntermediateNode->m_parent;
|
||||
}
|
||||
}
|
||||
@@ -262,20 +262,20 @@ public:
|
||||
/* detect the destination */
|
||||
bool bDestination = Yapf().PfDetectDestination(n);
|
||||
if (bDestination) {
|
||||
if (m_pBestDestNode == NULL || n < *m_pBestDestNode) {
|
||||
if (m_pBestDestNode == nullptr || n < *m_pBestDestNode) {
|
||||
m_pBestDestNode = &n;
|
||||
}
|
||||
m_nodes.FoundBestNode(n);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == NULL || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) {
|
||||
if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == nullptr || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) {
|
||||
m_pBestIntermediateNode = &n;
|
||||
}
|
||||
|
||||
/* check new node against open list */
|
||||
Node *openNode = m_nodes.FindOpenNode(n.GetKey());
|
||||
if (openNode != NULL) {
|
||||
if (openNode != nullptr) {
|
||||
/* another node exists with the same key in the open list
|
||||
* is it better than new one? */
|
||||
if (n.GetCostEstimate() < openNode->GetCostEstimate()) {
|
||||
@@ -290,7 +290,7 @@ public:
|
||||
|
||||
/* check new node against closed list */
|
||||
Node *closedNode = m_nodes.FindClosedNode(n.GetKey());
|
||||
if (closedNode != NULL) {
|
||||
if (closedNode != nullptr) {
|
||||
/* another node exists with the same key in the closed list
|
||||
* is it better than new one? */
|
||||
int node_est = n.GetCostEstimate();
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
for (TrackdirBits tdb = m_orgTrackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) {
|
||||
Trackdir td = (Trackdir)FindFirstBit2x64(tdb);
|
||||
Node &n1 = Yapf().CreateNewNode();
|
||||
n1.Set(NULL, m_orgTile, td, is_choice);
|
||||
n1.Set(nullptr, m_orgTile, td, is_choice);
|
||||
Yapf().AddStartupNode(n1);
|
||||
}
|
||||
}
|
||||
@@ -92,12 +92,12 @@ public:
|
||||
{
|
||||
if (m_orgTile != INVALID_TILE && m_orgTd != INVALID_TRACKDIR) {
|
||||
Node &n1 = Yapf().CreateNewNode();
|
||||
n1.Set(NULL, m_orgTile, m_orgTd, false);
|
||||
n1.Set(nullptr, m_orgTile, m_orgTd, false);
|
||||
Yapf().AddStartupNode(n1);
|
||||
}
|
||||
if (m_revTile != INVALID_TILE && m_revTd != INVALID_TRACKDIR) {
|
||||
Node &n2 = Yapf().CreateNewNode();
|
||||
n2.Set(NULL, m_revTile, m_revTd, false);
|
||||
n2.Set(nullptr, m_revTile, m_revTd, false);
|
||||
n2.m_cost = m_reverse_penalty;
|
||||
Yapf().AddStartupNode(n2);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ struct CSegmentCostCacheT : public CSegmentCostCacheBase {
|
||||
inline Tsegment& Get(Key &key, bool *found)
|
||||
{
|
||||
Tsegment *item = m_map.Find(key);
|
||||
if (item == NULL) {
|
||||
if (item == nullptr) {
|
||||
*found = false;
|
||||
item = new (m_heap.Append()) Tsegment(key);
|
||||
m_map.Push(*item);
|
||||
|
||||
@@ -47,14 +47,6 @@ protected:
|
||||
this->tile_type = GetTileType(tile);
|
||||
this->rail_type = GetTileRailType(tile);
|
||||
}
|
||||
|
||||
TILE(const TILE &src)
|
||||
{
|
||||
tile = src.tile;
|
||||
td = src.td;
|
||||
tile_type = src.tile_type;
|
||||
rail_type = src.rail_type;
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -251,7 +243,7 @@ public:
|
||||
{
|
||||
int cost = 0;
|
||||
const Train *v = Yapf().GetVehicle();
|
||||
assert(v != NULL);
|
||||
assert(v != nullptr);
|
||||
assert(v->type == VEH_TRAIN);
|
||||
assert(v->gcache.cached_total_length != 0);
|
||||
int missing_platform_length = CeilDiv(v->gcache.cached_total_length, TILE_SIZE) - platform_length;
|
||||
@@ -285,7 +277,7 @@ public:
|
||||
CPerfStart perf_cost(Yapf().m_perf_cost);
|
||||
|
||||
/* Does the node have some parent node? */
|
||||
bool has_parent = (n.m_parent != NULL);
|
||||
bool has_parent = (n.m_parent != nullptr);
|
||||
|
||||
/* Do we already have a cached segment? */
|
||||
CachedData &segment = *n.m_segment;
|
||||
@@ -496,7 +488,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
|
||||
if (!tf_local.Follow(cur.tile, cur.td)) {
|
||||
assert(tf_local.m_err != TrackFollower::EC_NONE);
|
||||
/* Can't move to the next tile (EOL?). */
|
||||
if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) {
|
||||
if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) {
|
||||
end_segment_reason |= ESRB_RAIL_TYPE;
|
||||
} else {
|
||||
end_segment_reason |= ESRB_DEAD_END;
|
||||
@@ -606,7 +598,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
|
||||
/* Station platform-length penalty. */
|
||||
if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) {
|
||||
const BaseStation *st = BaseStation::GetByTile(n.GetLastTile());
|
||||
assert(st != NULL);
|
||||
assert(st != nullptr);
|
||||
uint platform_length = st->GetPlatformLength(n.GetLastTile(), ReverseDiagDir(TrackdirToExitdir(n.GetLastTrackdir())));
|
||||
/* Reduce the extra cost caused by passing-station penalty (each station receives it in the segment cost). */
|
||||
extra_cost -= Yapf().PfGetSettings().rail_station_penalty * platform_length;
|
||||
@@ -624,7 +616,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
|
||||
inline bool CanUseGlobalCache(Node &n) const
|
||||
{
|
||||
return !m_disable_cache
|
||||
&& (n.m_parent != NULL)
|
||||
&& (n.m_parent != nullptr)
|
||||
&& (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size());
|
||||
}
|
||||
|
||||
|
||||
@@ -67,14 +67,16 @@ struct CYapfNodeT {
|
||||
Node *m_parent;
|
||||
int m_cost;
|
||||
int m_estimate;
|
||||
bool m_is_choice;
|
||||
|
||||
inline void Set(Node *parent, TileIndex tile, Trackdir td, bool is_choice)
|
||||
{
|
||||
m_key.Set(tile, td);
|
||||
m_hash_next = NULL;
|
||||
m_hash_next = nullptr;
|
||||
m_parent = parent;
|
||||
m_cost = 0;
|
||||
m_estimate = 0;
|
||||
m_is_choice = is_choice;
|
||||
}
|
||||
|
||||
inline Node *GetHashNext()
|
||||
@@ -112,6 +114,11 @@ struct CYapfNodeT {
|
||||
return m_estimate;
|
||||
}
|
||||
|
||||
inline bool GetIsChoice() const
|
||||
{
|
||||
return m_is_choice;
|
||||
}
|
||||
|
||||
inline bool operator<(const Node &other) const
|
||||
{
|
||||
return m_estimate < other.m_estimate;
|
||||
|
||||
@@ -83,7 +83,7 @@ struct CYapfRailSegment
|
||||
, m_last_signal_tile(INVALID_TILE)
|
||||
, m_last_signal_td(INVALID_TRACKDIR)
|
||||
, m_end_segment_reason(ESRB_NONE)
|
||||
, m_hash_next(NULL)
|
||||
, m_hash_next(nullptr)
|
||||
{}
|
||||
|
||||
inline const Key& GetKey() const
|
||||
@@ -142,8 +142,8 @@ struct CYapfRailNodeT
|
||||
inline void Set(CYapfRailNodeT *parent, TileIndex tile, Trackdir td, bool is_choice)
|
||||
{
|
||||
base::Set(parent, tile, td, is_choice);
|
||||
m_segment = NULL;
|
||||
if (parent == NULL) {
|
||||
m_segment = nullptr;
|
||||
if (parent == nullptr) {
|
||||
m_num_signals_passed = 0;
|
||||
flags_u.m_inherited_flags = 0;
|
||||
m_last_red_signal_type = SIGTYPE_NORMAL;
|
||||
@@ -169,19 +169,19 @@ struct CYapfRailNodeT
|
||||
|
||||
inline TileIndex GetLastTile() const
|
||||
{
|
||||
assert(m_segment != NULL);
|
||||
assert(m_segment != nullptr);
|
||||
return m_segment->m_last_tile;
|
||||
}
|
||||
|
||||
inline Trackdir GetLastTrackdir() const
|
||||
{
|
||||
assert(m_segment != NULL);
|
||||
assert(m_segment != nullptr);
|
||||
return m_segment->m_last_td;
|
||||
}
|
||||
|
||||
inline void SetLastTileTrackdir(TileIndex tile, Trackdir td)
|
||||
{
|
||||
assert(m_segment != NULL);
|
||||
assert(m_segment != nullptr);
|
||||
m_segment->m_last_tile = tile;
|
||||
m_segment->m_last_td = td;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,19 @@
|
||||
|
||||
/** Yapf Node for ships */
|
||||
template <class Tkey_>
|
||||
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > { };
|
||||
struct CYapfShipNodeT : CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > {
|
||||
typedef CYapfNodeT<Tkey_, CYapfShipNodeT<Tkey_> > base;
|
||||
|
||||
TileIndex m_segment_last_tile;
|
||||
Trackdir m_segment_last_td;
|
||||
|
||||
void Set(CYapfShipNodeT *parent, TileIndex tile, Trackdir td, bool is_choice)
|
||||
{
|
||||
base::Set(parent, tile, td, is_choice);
|
||||
m_segment_last_tile = tile;
|
||||
m_segment_last_td = td;
|
||||
}
|
||||
};
|
||||
|
||||
/* now define two major node types (that differ by key type) */
|
||||
typedef CYapfShipNodeT<CYapfNodeKeyExitDir> CYapfShipNodeExitDir;
|
||||
|
||||
@@ -28,8 +28,8 @@ template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
|
||||
pf2.DumpBase(dmp2);
|
||||
FILE *f1 = fopen("yapf1.txt", "wt");
|
||||
FILE *f2 = fopen("yapf2.txt", "wt");
|
||||
assert(f1 != NULL);
|
||||
assert(f2 != NULL);
|
||||
assert(f1 != nullptr);
|
||||
assert(f2 != nullptr);
|
||||
fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1);
|
||||
fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2);
|
||||
fclose(f1);
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
tile = TILE_ADD(tile, diff);
|
||||
} while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile);
|
||||
|
||||
TriggerStationRandomisation(NULL, start, SRT_PATH_RESERVATION);
|
||||
TriggerStationRandomisation(nullptr, start, SRT_PATH_RESERVATION);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
/** Check the node for a possible reservation target. */
|
||||
inline void FindSafePositionOnNode(Node *node)
|
||||
{
|
||||
assert(node->m_parent != NULL);
|
||||
assert(node->m_parent != nullptr);
|
||||
|
||||
/* We will never pass more than two signals, no need to check for a safe tile. */
|
||||
if (node->m_parent->m_num_signals_passed >= 2) return;
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
m_res_fail_tile = INVALID_TILE;
|
||||
m_origin_tile = origin;
|
||||
|
||||
if (target != NULL) {
|
||||
if (target != nullptr) {
|
||||
target->tile = m_res_dest;
|
||||
target->trackdir = m_res_dest_td;
|
||||
target->okay = false;
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
/* Don't bother if the target is reserved. */
|
||||
if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false;
|
||||
|
||||
for (Node *node = m_res_node; node->m_parent != NULL; node = node->m_parent) {
|
||||
for (Node *node = m_res_node; node->m_parent != nullptr; node = node->m_parent) {
|
||||
node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
|
||||
if (m_res_fail_tile != INVALID_TILE) {
|
||||
/* Reservation failed, undo. */
|
||||
@@ -173,13 +173,13 @@ public:
|
||||
/* If this is the node that failed, stop at the failed tile. */
|
||||
m_res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE;
|
||||
fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
|
||||
} while (fail_node != node && (fail_node = fail_node->m_parent) != NULL);
|
||||
} while (fail_node != node && (fail_node = fail_node->m_parent) != nullptr);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (target != NULL) target->okay = true;
|
||||
if (target != nullptr) target->okay = true;
|
||||
|
||||
if (Yapf().CanUseGlobalCache(*m_res_node)) {
|
||||
YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
|
||||
@@ -270,7 +270,7 @@ public:
|
||||
|
||||
/* walk through the path back to the origin */
|
||||
Node *pNode = n;
|
||||
while (pNode->m_parent != NULL) {
|
||||
while (pNode->m_parent != nullptr) {
|
||||
pNode = pNode->m_parent;
|
||||
}
|
||||
|
||||
@@ -351,15 +351,15 @@ public:
|
||||
this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir());
|
||||
|
||||
/* Walk through the path back to the origin. */
|
||||
Node *pPrev = NULL;
|
||||
while (pNode->m_parent != NULL) {
|
||||
Node *pPrev = nullptr;
|
||||
while (pNode->m_parent != nullptr) {
|
||||
pPrev = pNode;
|
||||
pNode = pNode->m_parent;
|
||||
|
||||
this->FindSafePositionOnNode(pPrev);
|
||||
}
|
||||
|
||||
return dont_reserve || this->TryReservePath(NULL, pNode->GetLastTile());
|
||||
return dont_reserve || this->TryReservePath(nullptr, pNode->GetLastTile());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -408,7 +408,7 @@ public:
|
||||
if (_debug_desync_level < 2) {
|
||||
result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
} else {
|
||||
result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, NULL);
|
||||
result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, nullptr);
|
||||
Tpf pf2;
|
||||
pf2.DisableCache(true);
|
||||
Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target);
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
|
||||
inline Trackdir ChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target)
|
||||
{
|
||||
if (target != NULL) target->tile = INVALID_TILE;
|
||||
if (target != nullptr) target->tile = INVALID_TILE;
|
||||
|
||||
/* set origin and destination nodes */
|
||||
PBSTileInfo origin = FollowTrainReservation(v);
|
||||
@@ -436,14 +436,14 @@ public:
|
||||
/* if path not found - return INVALID_TRACKDIR */
|
||||
Trackdir next_trackdir = INVALID_TRACKDIR;
|
||||
Node *pNode = Yapf().GetBestNode();
|
||||
if (pNode != NULL) {
|
||||
if (pNode != nullptr) {
|
||||
/* reserve till end of path */
|
||||
this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir());
|
||||
|
||||
/* path was found or at least suggested
|
||||
* walk through the path back to the origin */
|
||||
Node *pPrev = NULL;
|
||||
while (pNode->m_parent != NULL) {
|
||||
Node *pPrev = nullptr;
|
||||
while (pNode->m_parent != nullptr) {
|
||||
pPrev = pNode;
|
||||
pNode = pNode->m_parent;
|
||||
|
||||
@@ -494,7 +494,7 @@ public:
|
||||
/* path was found
|
||||
* walk through the path back to the origin */
|
||||
Node *pNode = Yapf().GetBestNode();
|
||||
while (pNode->m_parent != NULL) {
|
||||
while (pNode->m_parent != nullptr) {
|
||||
pNode = pNode->m_parent;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
/* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */
|
||||
TileIndex tile = n.m_key.m_tile;
|
||||
Trackdir trackdir = n.m_key.m_td;
|
||||
int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
|
||||
int parent_cost = (n.m_parent != nullptr) ? n.m_parent->m_cost : 0;
|
||||
|
||||
for (;;) {
|
||||
/* base tile cost depending on distance between edges */
|
||||
@@ -249,7 +249,7 @@ public:
|
||||
} else {
|
||||
m_dest_station = INVALID_STATION;
|
||||
m_destTile = v->dest_tile;
|
||||
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes));
|
||||
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,13 +348,13 @@ public:
|
||||
return 'r';
|
||||
}
|
||||
|
||||
static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found)
|
||||
static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found, RoadVehPathCache &path_cache)
|
||||
{
|
||||
Tpf pf;
|
||||
return pf.ChooseRoadTrack(v, tile, enterdir, path_found);
|
||||
return pf.ChooseRoadTrack(v, tile, enterdir, path_found, path_cache);
|
||||
}
|
||||
|
||||
inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found)
|
||||
inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found, RoadVehPathCache &path_cache)
|
||||
{
|
||||
/* Handle special case - when next tile is destination tile.
|
||||
* However, when going to a station the (initial) destination
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
/* our source tile will be the next vehicle tile (should be the given one) */
|
||||
TileIndex src_tile = tile;
|
||||
/* get available trackdirs on the start tile */
|
||||
TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes));
|
||||
TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype)));
|
||||
/* select reachable trackdirs only */
|
||||
src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
|
||||
|
||||
@@ -381,16 +381,29 @@ public:
|
||||
/* if path not found - return INVALID_TRACKDIR */
|
||||
Trackdir next_trackdir = INVALID_TRACKDIR;
|
||||
Node *pNode = Yapf().GetBestNode();
|
||||
if (pNode != NULL) {
|
||||
if (pNode != nullptr) {
|
||||
uint steps = 0;
|
||||
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
||||
|
||||
/* path was found or at least suggested
|
||||
* walk through the path back to its origin */
|
||||
while (pNode->m_parent != NULL) {
|
||||
while (pNode->m_parent != nullptr) {
|
||||
steps--;
|
||||
if (pNode->GetIsChoice() && steps < YAPF_ROADVEH_PATH_CACHE_SEGMENTS) {
|
||||
path_cache.td.push_front(pNode->GetTrackdir());
|
||||
path_cache.tile.push_front(pNode->GetTile());
|
||||
}
|
||||
pNode = pNode->m_parent;
|
||||
}
|
||||
/* return trackdir from the best origin node (one of start nodes) */
|
||||
Node &best_next_node = *pNode;
|
||||
assert(best_next_node.GetTile() == tile);
|
||||
next_trackdir = best_next_node.GetTrackdir();
|
||||
/* remove last element for the special case when tile == dest_tile */
|
||||
if (path_found && !path_cache.empty() && tile == v->dest_tile) {
|
||||
path_cache.td.pop_back();
|
||||
path_cache.tile.pop_back();
|
||||
}
|
||||
}
|
||||
return next_trackdir;
|
||||
}
|
||||
@@ -421,7 +434,7 @@ public:
|
||||
if (!Yapf().FindPath(v)) return dist;
|
||||
|
||||
Node *pNode = Yapf().GetBestNode();
|
||||
if (pNode != NULL) {
|
||||
if (pNode != nullptr) {
|
||||
/* path was found
|
||||
* get the path cost estimate */
|
||||
dist = pNode->GetCostEstimate();
|
||||
@@ -436,7 +449,7 @@ public:
|
||||
/* set origin (tile, trackdir) */
|
||||
TileIndex src_tile = v->tile;
|
||||
Trackdir src_td = v->GetVehicleTrackdir();
|
||||
if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)), src_td)) {
|
||||
if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, this->IsTram() ? RTT_TRAM : RTT_ROAD)), src_td)) {
|
||||
/* sometimes the roadveh is not on the road (it resides on non-existing track)
|
||||
* how should we handle that situation? */
|
||||
return false;
|
||||
@@ -497,18 +510,18 @@ struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNod
|
||||
struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
|
||||
|
||||
|
||||
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found)
|
||||
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache)
|
||||
{
|
||||
/* default is YAPF type 2 */
|
||||
typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found);
|
||||
typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found, RoadVehPathCache &path_cache);
|
||||
PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack; // default: ExitDir, allow 90-deg
|
||||
|
||||
/* check if non-default YAPF type should be used */
|
||||
if (_settings_game.pf.yapf.disable_node_optimization) {
|
||||
pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack; // Trackdir, allow 90-deg
|
||||
pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack; // Trackdir
|
||||
}
|
||||
|
||||
Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found);
|
||||
Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found, path_cache);
|
||||
return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs);
|
||||
}
|
||||
|
||||
@@ -516,7 +529,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist
|
||||
{
|
||||
TileIndex tile = v->tile;
|
||||
Trackdir trackdir = v->GetVehicleTrackdir();
|
||||
if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)), trackdir)) {
|
||||
if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))), trackdir)) {
|
||||
return FindDepotData();
|
||||
}
|
||||
|
||||
@@ -526,7 +539,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist
|
||||
|
||||
/* check if non-default YAPF type should be used */
|
||||
if (_settings_game.pf.yapf.disable_node_optimization) {
|
||||
pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir, allow 90-deg
|
||||
pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir
|
||||
}
|
||||
|
||||
return pfnFindNearestDepot(v, tile, trackdir, max_distance);
|
||||
|
||||
@@ -11,12 +11,96 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../ship.h"
|
||||
#include "../../industry.h"
|
||||
#include "../../vehicle_func.h"
|
||||
|
||||
#include "yapf.hpp"
|
||||
#include "yapf_node_ship.hpp"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
template <class Types>
|
||||
class CYapfDestinationTileWaterT
|
||||
{
|
||||
public:
|
||||
typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class)
|
||||
typedef typename Types::TrackFollower TrackFollower;
|
||||
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;
|
||||
TrackdirBits m_destTrackdirs;
|
||||
StationID m_destStation;
|
||||
|
||||
public:
|
||||
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);
|
||||
m_destTrackdirs = INVALID_TRACKDIR_BIT;
|
||||
} else {
|
||||
m_destStation = INVALID_STATION;
|
||||
m_destTile = v->dest_tile;
|
||||
m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** to access inherited path finder */
|
||||
inline 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)
|
||||
{
|
||||
return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
|
||||
}
|
||||
|
||||
inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
|
||||
{
|
||||
if (m_destStation != INVALID_STATION) {
|
||||
return IsDockingTile(tile) && IsShipDestinationTile(tile, m_destStation);
|
||||
}
|
||||
|
||||
return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.m_segment_last_tile;
|
||||
DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Node Follower module of YAPF for ships */
|
||||
template <class Types>
|
||||
class CYapfFollowShipT
|
||||
@@ -75,31 +159,32 @@ 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);
|
||||
|
||||
Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
|
||||
|
||||
Node *pNode = pf.GetBestNode();
|
||||
if (pNode != NULL) {
|
||||
if (pNode != nullptr) {
|
||||
uint steps = 0;
|
||||
for (Node *n = pNode; n->m_parent != NULL; n = n->m_parent) steps++;
|
||||
for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++;
|
||||
uint skip = 0;
|
||||
if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2;
|
||||
|
||||
/* walk through the path back to the origin */
|
||||
Node *pPrevNode = NULL;
|
||||
while (pNode->m_parent != NULL) {
|
||||
if (steps > 1 && --steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
||||
TrackdirByte td;
|
||||
td = pNode->GetTrackdir();
|
||||
path_cache.push_front(td);
|
||||
Node *pPrevNode = nullptr;
|
||||
while (pNode->m_parent != nullptr) {
|
||||
steps--;
|
||||
/* Skip tiles at end of path near destination. */
|
||||
if (skip > 0) skip--;
|
||||
if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) {
|
||||
path_cache.push_front(pNode->GetTrackdir());
|
||||
}
|
||||
pPrevNode = pNode;
|
||||
pNode = pNode->m_parent;
|
||||
@@ -125,23 +210,20 @@ 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;
|
||||
|
||||
Node *pNode = pf.GetBestNode();
|
||||
if (pNode == NULL) return false;
|
||||
if (pNode == nullptr) return false;
|
||||
|
||||
/* path was found
|
||||
* walk through the path back to the origin */
|
||||
while (pNode->m_parent != NULL) {
|
||||
while (pNode->m_parent != nullptr) {
|
||||
pNode = pNode->m_parent;
|
||||
}
|
||||
|
||||
@@ -169,6 +251,30 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
inline int CurveCost(Trackdir td1, Trackdir td2)
|
||||
{
|
||||
assert(IsValidTrackdir(td1));
|
||||
assert(IsValidTrackdir(td2));
|
||||
|
||||
if (HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) {
|
||||
/* 90-deg curve penalty */
|
||||
return Yapf().PfGetSettings().ship_curve90_penalty;
|
||||
} else if (td2 != NextTrackdir(td1)) {
|
||||
/* 45-deg curve penalty */
|
||||
return Yapf().PfGetSettings().ship_curve45_penalty;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Vehicle *CountShipProc(Vehicle *v, void *data)
|
||||
{
|
||||
uint *count = (uint *)data;
|
||||
/* Ignore other vehicles (aircraft) and ships inside depot. */
|
||||
if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by YAPF to calculate the cost from the origin to the given node.
|
||||
* Calculates only the cost of given node, adds it to the parent node cost
|
||||
@@ -179,9 +285,13 @@ public:
|
||||
/* base tile cost depending on distance */
|
||||
int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
|
||||
/* additional penalty for curves */
|
||||
if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
|
||||
/* new trackdir does not match the next one when going straight */
|
||||
c += YAPF_TILE_LENGTH;
|
||||
c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir());
|
||||
|
||||
if (IsDockingTile(n.GetTile())) {
|
||||
/* Check docking tile for occupancy */
|
||||
uint count = 1;
|
||||
HasVehicleOnPos(n.GetTile(), &count, &CountShipProc);
|
||||
c += count * 3 * YAPF_TILE_LENGTH;
|
||||
}
|
||||
|
||||
/* Skipped tile cost for aqueducts. */
|
||||
@@ -219,30 +329,36 @@ 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 CYapfDestinationTileWaterT<Types> PfDestination; // destination/distance provider
|
||||
typedef CYapfSegmentCostCacheNoneT<Types> PfCache; // segment cost cache provider
|
||||
typedef CYapfCostShipT<Types> PfCost; // cost provider
|
||||
};
|
||||
|
||||
/* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */
|
||||
/* YAPF type 1 - uses TileIndex/Trackdir as Node key */
|
||||
struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater , CShipNodeListTrackDir> > {};
|
||||
/* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */
|
||||
/* YAPF type 2 - uses TileIndex/DiagDirection as Node key */
|
||||
struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater , CShipNodeListExitDir > > {};
|
||||
/* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */
|
||||
struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
|
||||
|
||||
static inline bool RequireTrackdirKey()
|
||||
{
|
||||
/* If the two curve penalties are not equal, then it is not possible to use the
|
||||
* ExitDir keyed node list, as it there will be key overlap. Using Trackdir keyed
|
||||
* nodes means potentially more paths are tested, which would be wasteful if it's
|
||||
* not necessary.
|
||||
*/
|
||||
return _settings_game.pf.yapf.ship_curve45_penalty != _settings_game.pf.yapf.ship_curve90_penalty;
|
||||
}
|
||||
|
||||
/** Ship controller helper - path finder invoker */
|
||||
Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, ShipPathCache &path_cache)
|
||||
{
|
||||
/* default is YAPF type 2 */
|
||||
typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found, ShipPathCache &path_cache);
|
||||
PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
|
||||
PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir
|
||||
|
||||
/* check if non-default YAPF type needed */
|
||||
if (_settings_game.pf.forbid_90_deg) {
|
||||
pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
|
||||
} else if (_settings_game.pf.yapf.disable_node_optimization) {
|
||||
pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
|
||||
if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) {
|
||||
pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir
|
||||
}
|
||||
|
||||
Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found, path_cache);
|
||||
@@ -256,13 +372,11 @@ bool YapfShipCheckReverse(const Ship *v)
|
||||
TileIndex tile = v->tile;
|
||||
|
||||
typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir);
|
||||
PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg
|
||||
PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir
|
||||
|
||||
/* check if non-default YAPF type needed */
|
||||
if (_settings_game.pf.forbid_90_deg) {
|
||||
pfnCheckReverseShip = &CYapfShip3::CheckShipReverse; // Trackdir, forbid 90-deg
|
||||
} else if (_settings_game.pf.yapf.disable_node_optimization) {
|
||||
pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir, allow 90-deg
|
||||
if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) {
|
||||
pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir
|
||||
}
|
||||
|
||||
bool reverse = pfnCheckReverseShip(v, tile, td, td_rev);
|
||||
|
||||
Reference in New Issue
Block a user