12 #ifndef YAPF_COSTRAIL_HPP 13 #define YAPF_COSTRAIL_HPP 15 #include "../../pbs.h" 17 template <
class Types>
20 typedef typename Types::Tpf
Tpf;
21 typedef typename Types::TrackFollower TrackFollower;
22 typedef typename Types::NodeList::Titem
Node;
23 typedef typename Node::Key
Key;
24 typedef typename Node::CachedData CachedData;
55 tile_type = src.tile_type;
56 rail_type = src.rail_type;
70 bool m_stopped_on_first_two_way_signal;
73 static const int s_max_segment_cost = 10000;
75 CYapfCostRailT() : m_max_cost(0), m_disable_cache(false), m_stopped_on_first_two_way_signal(false)
78 int p0 =
Yapf().PfGetSettings().rail_look_ahead_signal_p0;
79 int p1 =
Yapf().PfGetSettings().rail_look_ahead_signal_p1;
80 int p2 =
Yapf().PfGetSettings().rail_look_ahead_signal_p2;
81 int *pen = m_sig_look_ahead_costs.
GrowSizeNC(
Yapf().PfGetSettings().rail_look_ahead_max_signals);
82 for (uint i = 0; i <
Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) {
83 pen[i] = p0 + i * (p1 + i * p2);
90 return *
static_cast<Tpf *
>(
this);
98 return Yapf().PfGetSettings().rail_slope_penalty;
106 if (TrackFollower::Allow90degTurns()
109 cost +=
Yapf().PfGetSettings().rail_curve90_penalty;
112 cost +=
Yapf().PfGetSettings().rail_curve45_penalty;
122 if (t1 && t2)
return Yapf().PfGetSettings().rail_doubleslip_penalty;
138 cost +=
Yapf().PfGetSettings().rail_crossing_penalty;
156 for (; skipped >= 0; skipped--, tile += diff) {
165 if (n.m_num_signals_passed >= m_sig_look_ahead_costs.
Size() / 2)
return 0;
166 if (!IsPbsSignal(n.m_last_signal_type))
return 0;
169 return Yapf().PfGetSettings().rail_pbs_station_penalty * (skipped + 1);
171 int cost =
Yapf().PfGetSettings().rail_pbs_cross_penalty;
173 return cost * (skipped + 1);
188 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
190 if (has_signal_along) {
194 n.m_last_signal_type = sig_type;
197 int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.
Size()) ? m_sig_look_ahead_costs.
Data()[n.m_num_signals_passed] : 0;
200 n.flags_u.flags_s.m_last_signal_was_red =
false;
202 if (look_ahead_cost < 0) {
204 cost -= look_ahead_cost;
209 if (!IsPbsSignal(sig_type) &&
Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
211 Yapf().PruneIntermediateNodeBranch();
212 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
213 Yapf().m_stopped_on_first_two_way_signal =
true;
216 n.m_last_red_signal_type = sig_type;
217 n.flags_u.flags_s.m_last_signal_was_red =
true;
220 if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) {
222 cost += look_ahead_cost;
226 if (n.m_num_signals_passed == 0) {
229 case SIGTYPE_EXIT: cost +=
Yapf().PfGetSettings().rail_firstred_exit_penalty;
break;
237 n.m_num_signals_passed++;
238 n.m_segment->m_last_signal_tile = tile;
239 n.m_segment->m_last_signal_td = trackdir;
242 if (has_signal_against && IsPbsSignal(GetSignalType(tile,
TrackdirToTrack(trackdir)))) {
243 cost += n.m_num_signals_passed <
Yapf().PfGetSettings().rail_look_ahead_max_signals ?
Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
250 inline int PlatformLengthPenalty(
int platform_length)
258 if (missing_platform_length < 0) {
260 cost +=
Yapf().PfGetSettings().rail_longer_platform_penalty +
Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
261 }
else if (missing_platform_length > 0) {
263 cost +=
Yapf().PfGetSettings().rail_shorter_platform_penalty +
Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length;
269 inline void SetMaxCost(
int max_cost)
271 m_max_cost = max_cost;
281 assert(!n.flags_u.flags_s.m_targed_seen);
282 assert(tf->m_new_tile == n.m_key.m_tile);
288 bool has_parent = (n.m_parent != NULL);
291 CachedData &segment = *n.m_segment;
292 bool is_cached_segment = (segment.m_cost >= 0);
294 int parent_cost = has_parent ? n.m_parent->m_cost : 0;
315 int transition_cost = 0;
323 int segment_entry_cost = 0;
324 int segment_cost = 0;
329 TILE cur(n.m_key.m_tile, n.m_key.m_td);
332 TILE prev = !has_parent ?
TILE() : TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir());
334 EndSegmentReasonBits end_segment_reason = ESRB_NONE;
336 TrackFollower tf_local(v,
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
340 assert(!is_cached_segment);
347 transition_cost =
Yapf().CurveCost(prev.td, cur.td);
352 if (segment_cost == 0) {
354 segment_entry_cost = transition_cost;
358 if (is_cached_segment) {
360 segment_cost = segment.m_cost;
362 end_segment_reason = segment.m_end_segment_reason;
368 n.flags_u.flags_s.m_last_signal_was_red = is_red;
370 n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile,
TrackdirToTrack(segment.m_last_signal_td));
374 cur = TILE(n.GetLastTile(), n.GetLastTrackdir());
379 segment_cost += transition_cost;
385 segment_cost +=
Yapf().OneTileCost(cur.tile, cur.td);
391 segment_cost +=
Yapf().SlopeCost(cur.tile, cur.td);
394 segment_cost +=
Yapf().SignalCost(n, cur.tile, cur.td);
397 segment_cost +=
Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped);
399 end_segment_reason = segment.m_end_segment_reason;
402 if (cur.tile == prev.tile) {
405 segment_cost +=
Yapf().PfGetSettings().rail_depot_reverse_penalty;
409 end_segment_reason |= ESRB_DEPOT;
423 while (ft.
Follow(t, td)) {
426 if (t == cur.tile || --max_tiles == 0) {
449 extra_cost +=
Yapf().PfGetSettings().rail_lastred_penalty;
453 end_segment_reason |= ESRB_WAYPOINT;
455 }
else if (tf->m_is_station) {
457 uint platform_length = tf->m_tiles_skipped + 1;
460 segment_cost +=
Yapf().PfGetSettings().rail_station_penalty * platform_length;
462 end_segment_reason |= ESRB_STATION;
464 }
else if (TrackFollower::DoTrackMasking() && cur.tile_type ==
MP_RAILWAY) {
467 end_segment_reason |= ESRB_SAFE_TILE;
473 if (n.m_num_signals_passed < m_sig_look_ahead_costs.
Size())
476 int max_speed = tf->GetSpeedLimit(&min_speed);
478 if (max_speed < max_veh_speed) {
479 extra_cost +=
YAPF_TILE_LENGTH * (max_veh_speed - max_speed) * (4 + tf->m_tiles_skipped) / max_veh_speed;
481 if (min_speed > max_veh_speed) {
488 if (m_max_cost > 0 && (parent_cost + segment_entry_cost + segment_cost) >
m_max_cost) {
489 end_segment_reason |= ESRB_PATH_TOO_LONG;
494 tf_local.Init(v,
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
496 if (!tf_local.Follow(cur.tile, cur.td)) {
497 assert(tf_local.m_err != TrackFollower::EC_NONE);
499 if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) {
500 end_segment_reason |= ESRB_RAIL_TYPE;
502 end_segment_reason |= ESRB_DEAD_END;
506 end_segment_reason |= ESRB_SAFE_TILE;
514 end_segment_reason |= ESRB_CHOICE_FOLLOWS;
524 end_segment_reason |= ESRB_SAFE_TILE;
527 end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END;
528 extra_cost +=
Yapf().PfGetSettings().rail_lastred_exit_penalty;
533 if (next.rail_type != cur.rail_type) {
535 end_segment_reason |= ESRB_RAIL_TYPE;
540 if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) {
541 end_segment_reason |= ESRB_INFINITE_LOOP;
545 if (segment_cost > s_max_segment_cost) {
549 end_segment_reason |= ESRB_SEGMENT_TOO_LONG;
555 if (end_segment_reason != ESRB_NONE) {
566 if (end_segment_reason & ESRB_PATH_TOO_LONG)
return false;
568 bool target_seen =
false;
569 if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) {
571 if (
Yapf().PfDetectDestination(cur.tile, cur.td)) {
578 if (!is_cached_segment) {
580 segment.m_cost = segment_cost;
581 segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK;
583 n.SetLastTileTrackdir(cur.tile, cur.td);
587 if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) {
594 n.flags_u.flags_s.m_targed_seen =
true;
596 if (n.flags_u.flags_s.m_last_signal_was_red) {
599 extra_cost +=
Yapf().PfGetSettings().rail_lastred_exit_penalty;
600 }
else if (!IsPbsSignal(n.m_last_red_signal_type)) {
602 extra_cost +=
Yapf().PfGetSettings().rail_lastred_penalty;
607 if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) {
612 extra_cost -=
Yapf().PfGetSettings().rail_station_penalty * platform_length;
614 extra_cost += PlatformLengthPenalty(platform_length);
619 n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost;
624 inline bool CanUseGlobalCache(Node &n)
const 626 return !m_disable_cache
627 && (n.m_parent != NULL)
628 && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.
Size());
631 inline void ConnectNodeToCachedData(Node &n, CachedData &ci)
634 if (n.m_segment->m_cost < 0) {
635 n.m_segment->m_last_tile = n.m_key.m_tile;
636 n.m_segment->m_last_td = n.m_key.m_td;
640 void DisableCache(
bool disable)
642 m_disable_cache = disable;
bool PfCalcCost(Node &n, const TrackFollower *tf)
Called by YAPF to calculate the cost from the origin to the given node.
static TileType GetTileType(TileIndex tile)
Get the tiletype of a given tile.
static bool HasSignalOnTrackdir(TileIndex tile, Trackdir trackdir)
Checks for the presence of signals along the given trackdir on the given rail tile.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
virtual uint GetPlatformLength(TileIndex tile) const =0
Obtain the length of a platform.
bool Follow(TileIndex old_tile, Trackdir old_td)
main follower routine.
SignalType
Type of signal, i.e.
RailType
Enumeration for all possible railtypes.
TrackdirBits m_new_td_bits
the new set of available trackdirs
int32 TileIndexDiff
An offset value between to tiles.
static Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
TileType
The different types of tiles.
A tile with road (or tram tracks)
SignalState
These are states in which a signal can be.
static bool IsOnewaySignal(TileIndex t, Track track)
One-way signals can't be passed the 'wrong' way.
PathfinderSettings pf
settings for all pathfinders
Types::NodeList::Titem Node
this will be our node type
static Trackdir NextTrackdir(Trackdir trackdir)
Maps a trackdir to the trackdir that you will end up on if you go straight ahead. ...
int GetDisplayMaxSpeed() const
Gets the maximum speed in km-ish/h that can be sent into SetDParam for string processing.
bool forbid_90_deg
forbid trains to make 90 deg turns
Tpf & Yapf()
to access inherited path finder
static bool IsLevelCrossing(TileIndex t)
Return whether a tile is a level crossing.
static DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
static const uint TILE_SIZE
Tile size in world coordinates.
int ReservationCost(Node &n, TileIndex tile, Trackdir trackdir, int skipped)
The cost for reserved tiles, including skipped ones.
static bool TrackOverlapsTracks(TrackBits tracks, Track track)
Check if a given track is contained within or overlaps some other tracks.
Base implementation for cost accounting.
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
static bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a give tiletype.
T * GrowSizeNC(size_t num_items)
Grow number of data items in Blob by given number - doesn't construct items.
static bool HasStationReservation(TileIndex t)
Get the reservation state of the rail station.
static bool IsRailStationTile(TileIndex t)
Is this tile a station tile and a rail station?
static TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir)
Maps a Trackdir to the corresponding TrackdirBits value.
bool IsType(OrderType type) const
Check whether this order is of the given type.
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
Determine whether a certain track on a tile is a safe position to end a path.
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
static Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
static uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
static const int YAPF_TILE_LENGTH
Length (penalty) of one tile with YAPF.
Trackdir
Enumeration for tracks and directions.
DiagDirection
Enumeration for diagonal directions.
static bool stSlopeCost(TileIndex tile, Trackdir td)
Does the given track direction on the given tile yield an uphill penalty?
Node::Key Key
key to hash tables
static bool IsPlainRailTile(TileIndex t)
Checks whether the tile is a rail tile or rail tile with signals.
Track follower helper template class (can serve pathfinders and vehicle controllers).
static Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Types::Tpf Tpf
the pathfinder class (derived from THIS class)
static TrackBits DiagdirReachesTracks(DiagDirection diagdir)
Returns all tracks that can be reached when entering a tile from a given (diagonal) direction...
'Train' is either a loco or a wagon.
static TrackBits GetTrackBits(TileIndex tile)
Gets the track bits of the given tile.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
RailType GetTileRailType(TileIndex tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
static T KillFirstBit(T value)
Clear the first bit in an integer.
static bool IsRailDepot(TileIndex t)
Is this rail tile a rail depot?
DestinationID GetDestination() const
Gets the destination of this order.
static bool IsRailDepotTile(TileIndex t)
Is this tile rail tile and a rail depot?
Invisible tiles at the SW and SE border.
uint32 TileIndex
The index/ID of a Tile.
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
TileIndex m_new_tile
the new tile (the vehicle has entered)
T * Data()
Return pointer to the first data item - non-const version.
uint16 cached_total_length
Length of the whole vehicle (valid only for the first engine).
static bool IsDiagonalTrackdir(Trackdir trackdir)
Checks if a given Trackdir is diagonal.
static uint8 FindFirstBit2x64(const int value)
Finds the position of the first non-zero bit in an integer.
static bool IsRailWaypoint(TileIndex t)
Is this station tile a rail waypoint?
TrackdirBits
Enumeration of bitmasks for the TrackDirs.
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
int OneTileCost(TileIndex &tile, Trackdir trackdir)
Return one tile cost (base cost + level crossing penalty).
Flag for invalid railtype.
Flag for an invalid trackdir.
size_t Size() const
Return number of items in the Blob.
static const int YAPF_TILE_CORNER_LENGTH
Length (penalty) of a corner with YAPF.
static bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
Is a one-way signal blocking the trackdir? A one-way signal on the trackdir against will block...
static SignalState GetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
static Waypoint * Get(size_t index)
Gets station with given index.
static TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir)
Maps a trackdir to all trackdirs that make 90 deg turns with it.
VehicleTypeByte type
Type of vehicle.
Base class for all station-ish types.
Order current_order
The current order (+ status, like: loading)
bool IsAnyStationTileReserved(TileIndex tile, Trackdir trackdir, int skipped)
Check for a reserved station platform.
GroundVehicleCache gcache
Cache of often calculated values.