2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file yapf_rail.cpp The rail pathfinding. */
10 #include "../../stdafx.h"
13 #include "yapf_cache.h"
14 #include "yapf_node_rail.hpp"
15 #include "yapf_costrail.hpp"
16 #include "yapf_destrail.hpp"
17 #include "../../viewport_func.h"
18 #include "../../newgrf_station.h"
20 #include "../../safeguards.h"
22 template <typename Tpf
> void DumpState(Tpf
&pf1
, Tpf
&pf2
)
24 DumpTarget dmp1
, dmp2
;
27 FILE *f1
= fopen("yapf1.txt", "wt");
28 FILE *f2
= fopen("yapf2.txt", "wt");
29 assert(f1
!= nullptr);
30 assert(f2
!= nullptr);
31 fwrite(dmp1
.m_out
.Data(), 1, dmp1
.m_out
.Size(), f1
);
32 fwrite(dmp2
.m_out
.Data(), 1, dmp2
.m_out
.Size(), f2
);
37 int _total_pf_time_us
= 0;
39 template <class Types
>
40 class CYapfReserveTrack
43 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
44 typedef typename
Types::TrackFollower TrackFollower
;
45 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
48 /** to access inherited pathfinder */
51 return *static_cast<Tpf
*>(this);
55 TileIndex m_res_dest
; ///< The reservation target tile
56 Trackdir m_res_dest_td
; ///< The reservation target trackdir
57 Node
*m_res_node
; ///< The reservation target node
58 TileIndex m_res_fail_tile
; ///< The tile where the reservation failed
59 Trackdir m_res_fail_td
; ///< The trackdir where the reservation failed
60 TileIndex m_origin_tile
; ///< Tile our reservation will originate from
62 bool FindSafePositionProc(TileIndex tile
, Trackdir td
)
64 if (IsSafeWaitingPosition(Yapf().GetVehicle(), tile
, td
, true, !TrackFollower::Allow90degTurns())) {
67 return false; // Stop iterating segment
72 /** Reserve a railway platform. Tile contains the failed tile on abort. */
73 bool ReserveRailStationPlatform(TileIndex
&tile
, DiagDirection dir
)
75 TileIndex start
= tile
;
76 TileIndexDiff diff
= TileOffsByDiagDir(dir
);
79 if (HasStationReservation(tile
)) return false;
80 SetRailStationReservation(tile
, true);
81 MarkTileDirtyByTile(tile
);
82 tile
= TILE_ADD(tile
, diff
);
83 } while (IsCompatibleTrainStationTile(tile
, start
) && tile
!= m_origin_tile
);
85 TriggerStationRandomisation(nullptr, start
, SRT_PATH_RESERVATION
);
90 /** Try to reserve a single track/platform. */
91 bool ReserveSingleTrack(TileIndex tile
, Trackdir td
)
93 if (IsRailStationTile(tile
)) {
94 if (!ReserveRailStationPlatform(tile
, TrackdirToExitdir(ReverseTrackdir(td
)))) {
95 /* Platform could not be reserved, undo. */
96 m_res_fail_tile
= tile
;
100 if (!TryReserveRailTrack(tile
, TrackdirToTrack(td
))) {
101 /* Tile couldn't be reserved, undo. */
102 m_res_fail_tile
= tile
;
108 return tile
!= m_res_dest
|| td
!= m_res_dest_td
;
111 /** Unreserve a single track/platform. Stops when the previous failer is reached. */
112 bool UnreserveSingleTrack(TileIndex tile
, Trackdir td
)
114 if (IsRailStationTile(tile
)) {
115 TileIndex start
= tile
;
116 TileIndexDiff diff
= TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(td
)));
117 while ((tile
!= m_res_fail_tile
|| td
!= m_res_fail_td
) && IsCompatibleTrainStationTile(tile
, start
)) {
118 SetRailStationReservation(tile
, false);
119 tile
= TILE_ADD(tile
, diff
);
121 } else if (tile
!= m_res_fail_tile
|| td
!= m_res_fail_td
) {
122 UnreserveRailTrack(tile
, TrackdirToTrack(td
));
124 return (tile
!= m_res_dest
|| td
!= m_res_dest_td
) && (tile
!= m_res_fail_tile
|| td
!= m_res_fail_td
);
128 /** Set the target to where the reservation should be extended. */
129 inline void SetReservationTarget(Node
*node
, TileIndex tile
, Trackdir td
)
136 /** Check the node for a possible reservation target. */
137 inline void FindSafePositionOnNode(Node
*node
)
139 assert(node
->m_parent
!= nullptr);
141 /* We will never pass more than two signals, no need to check for a safe tile. */
142 if (node
->m_parent
->m_num_signals_passed
>= 2) return;
144 if (!node
->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack
<Types
>::FindSafePositionProc
)) {
149 /** Try to reserve the path till the reservation target. */
150 bool TryReservePath(PBSTileInfo
*target
, TileIndex origin
)
152 m_res_fail_tile
= INVALID_TILE
;
153 m_origin_tile
= origin
;
155 if (target
!= nullptr) {
156 target
->tile
= m_res_dest
;
157 target
->trackdir
= m_res_dest_td
;
158 target
->okay
= false;
161 /* Don't bother if the target is reserved. */
162 if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest
, m_res_dest_td
)) return false;
164 for (Node
*node
= m_res_node
; node
->m_parent
!= nullptr; node
= node
->m_parent
) {
165 node
->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack
<Types
>::ReserveSingleTrack
);
166 if (m_res_fail_tile
!= INVALID_TILE
) {
167 /* Reservation failed, undo. */
168 Node
*fail_node
= m_res_node
;
169 TileIndex stop_tile
= m_res_fail_tile
;
171 /* If this is the node that failed, stop at the failed tile. */
172 m_res_fail_tile
= fail_node
== node
? stop_tile
: INVALID_TILE
;
173 fail_node
->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack
<Types
>::UnreserveSingleTrack
);
174 } while (fail_node
!= node
&& (fail_node
= fail_node
->m_parent
) != nullptr);
180 if (target
!= nullptr) target
->okay
= true;
182 if (Yapf().CanUseGlobalCache(*m_res_node
)) {
183 YapfNotifyTrackLayoutChange(INVALID_TILE
, INVALID_TRACK
);
190 template <class Types
>
191 class CYapfFollowAnyDepotRailT
194 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
195 typedef typename
Types::TrackFollower TrackFollower
;
196 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
197 typedef typename
Node::Key Key
; ///< key to hash tables
200 /** to access inherited path finder */
203 return *static_cast<Tpf
*>(this);
208 * Called by YAPF to move from the given node to the next tile. For each
209 * reachable trackdir on the new tile creates new node, initializes it
210 * and adds it to the open list by calling Yapf().AddNewNode(n)
212 inline void PfFollowNode(Node
&old_node
)
214 TrackFollower
F(Yapf().GetVehicle());
215 if (F
.Follow(old_node
.GetLastTile(), old_node
.GetLastTrackdir())) {
216 Yapf().AddMultipleNodes(&old_node
, F
);
220 /** return debug report character to identify the transportation type */
221 inline char TransportTypeChar() const
226 static FindDepotData
stFindNearestDepotTwoWay(const Train
*v
, TileIndex t1
, Trackdir td1
, TileIndex t2
, Trackdir td2
, int max_penalty
, int reverse_penalty
)
230 * With caching enabled it simply cannot get a reliable result when you
231 * have limited the distance a train may travel. This means that the
232 * cached result does not match uncached result in all cases and that
233 * causes desyncs. So disable caching when finding for a depot that is
234 * nearby. This only happens with automatic servicing of vehicles,
235 * so it will only impact performance when you do not manually set
236 * depot orders and you do not disable automatic servicing.
238 if (max_penalty
!= 0) pf1
.DisableCache(true);
239 FindDepotData result1
= pf1
.FindNearestDepotTwoWay(v
, t1
, td1
, t2
, td2
, max_penalty
, reverse_penalty
);
241 if (_debug_desync_level
>= 2) {
243 pf2
.DisableCache(true);
244 FindDepotData result2
= pf2
.FindNearestDepotTwoWay(v
, t1
, td1
, t2
, td2
, max_penalty
, reverse_penalty
);
245 if (result1
.tile
!= result2
.tile
|| (result1
.reverse
!= result2
.reverse
)) {
246 DEBUG(desync
, 2, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]",
247 result1
.tile
!= INVALID_TILE
? "T" : "F",
248 result2
.tile
!= INVALID_TILE
? "T" : "F");
256 inline FindDepotData
FindNearestDepotTwoWay(const Train
*v
, TileIndex t1
, Trackdir td1
, TileIndex t2
, Trackdir td2
, int max_penalty
, int reverse_penalty
)
258 /* set origin and destination nodes */
259 Yapf().SetOrigin(t1
, td1
, t2
, td2
, reverse_penalty
, true);
260 Yapf().SetDestination(v
);
261 Yapf().SetMaxCost(max_penalty
);
263 /* find the best path */
264 if (!Yapf().FindPath(v
)) return FindDepotData();
266 /* Some path found. */
267 Node
*n
= Yapf().GetBestNode();
269 /* walk through the path back to the origin */
271 while (pNode
->m_parent
!= nullptr) {
272 pNode
= pNode
->m_parent
;
275 /* if the origin node is our front vehicle tile/Trackdir then we didn't reverse
276 * but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed) */
277 return FindDepotData(n
->GetLastTile(), n
->m_cost
, pNode
->m_cost
!= 0);
281 template <class Types
>
282 class CYapfFollowAnySafeTileRailT
: public CYapfReserveTrack
<Types
>
285 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
286 typedef typename
Types::TrackFollower TrackFollower
;
287 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
288 typedef typename
Node::Key Key
; ///< key to hash tables
291 /** to access inherited path finder */
294 return *static_cast<Tpf
*>(this);
299 * Called by YAPF to move from the given node to the next tile. For each
300 * reachable trackdir on the new tile creates new node, initializes it
301 * and adds it to the open list by calling Yapf().AddNewNode(n)
303 inline void PfFollowNode(Node
&old_node
)
305 TrackFollower
F(Yapf().GetVehicle(), Yapf().GetCompatibleRailTypes());
306 if (F
.Follow(old_node
.GetLastTile(), old_node
.GetLastTrackdir()) && F
.MaskReservedTracks()) {
307 Yapf().AddMultipleNodes(&old_node
, F
);
311 /** Return debug report character to identify the transportation type */
312 inline char TransportTypeChar() const
317 static bool stFindNearestSafeTile(const Train
*v
, TileIndex t1
, Trackdir td
, bool override_railtype
)
319 /* Create pathfinder instance */
322 if (_debug_desync_level
< 2) {
323 result1
= pf1
.FindNearestSafeTile(v
, t1
, td
, override_railtype
, false);
325 bool result2
= pf1
.FindNearestSafeTile(v
, t1
, td
, override_railtype
, true);
327 pf2
.DisableCache(true);
328 result1
= pf2
.FindNearestSafeTile(v
, t1
, td
, override_railtype
, false);
329 if (result1
!= result2
) {
330 DEBUG(desync
, 2, "CACHE ERROR: FindSafeTile() = [%s, %s]", result2
? "T" : "F", result1
? "T" : "F");
338 bool FindNearestSafeTile(const Train
*v
, TileIndex t1
, Trackdir td
, bool override_railtype
, bool dont_reserve
)
340 /* Set origin and destination. */
341 Yapf().SetOrigin(t1
, td
);
342 Yapf().SetDestination(v
, override_railtype
);
344 bool bFound
= Yapf().FindPath(v
);
345 if (!bFound
) return false;
347 /* Found a destination, set as reservation target. */
348 Node
*pNode
= Yapf().GetBestNode();
349 this->SetReservationTarget(pNode
, pNode
->GetLastTile(), pNode
->GetLastTrackdir());
351 /* Walk through the path back to the origin. */
352 Node
*pPrev
= nullptr;
353 while (pNode
->m_parent
!= nullptr) {
355 pNode
= pNode
->m_parent
;
357 this->FindSafePositionOnNode(pPrev
);
360 return dont_reserve
|| this->TryReservePath(nullptr, pNode
->GetLastTile());
364 template <class Types
>
365 class CYapfFollowRailT
: public CYapfReserveTrack
<Types
>
368 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
369 typedef typename
Types::TrackFollower TrackFollower
;
370 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
371 typedef typename
Node::Key Key
; ///< key to hash tables
374 /** to access inherited path finder */
377 return *static_cast<Tpf
*>(this);
382 * Called by YAPF to move from the given node to the next tile. For each
383 * reachable trackdir on the new tile creates new node, initializes it
384 * and adds it to the open list by calling Yapf().AddNewNode(n)
386 inline void PfFollowNode(Node
&old_node
)
388 TrackFollower
F(Yapf().GetVehicle());
389 if (F
.Follow(old_node
.GetLastTile(), old_node
.GetLastTrackdir())) {
390 Yapf().AddMultipleNodes(&old_node
, F
);
394 /** return debug report character to identify the transportation type */
395 inline char TransportTypeChar() const
400 static Trackdir
stChooseRailTrack(const Train
*v
, TileIndex tile
, DiagDirection enterdir
, TrackBits tracks
, bool &path_found
, bool reserve_track
, PBSTileInfo
*target
)
402 /* create pathfinder instance */
406 if (_debug_desync_level
< 2) {
407 result1
= pf1
.ChooseRailTrack(v
, tile
, enterdir
, tracks
, path_found
, reserve_track
, target
);
409 result1
= pf1
.ChooseRailTrack(v
, tile
, enterdir
, tracks
, path_found
, false, nullptr);
411 pf2
.DisableCache(true);
412 Trackdir result2
= pf2
.ChooseRailTrack(v
, tile
, enterdir
, tracks
, path_found
, reserve_track
, target
);
413 if (result1
!= result2
) {
414 DEBUG(desync
, 2, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1
, result2
);
422 inline Trackdir
ChooseRailTrack(const Train
*v
, TileIndex tile
, DiagDirection enterdir
, TrackBits tracks
, bool &path_found
, bool reserve_track
, PBSTileInfo
*target
)
424 if (target
!= nullptr) target
->tile
= INVALID_TILE
;
426 /* set origin and destination nodes */
427 PBSTileInfo origin
= FollowTrainReservation(v
);
428 Yapf().SetOrigin(origin
.tile
, origin
.trackdir
, INVALID_TILE
, INVALID_TRACKDIR
, 1, true);
429 Yapf().SetDestination(v
);
431 /* find the best path */
432 path_found
= Yapf().FindPath(v
);
434 /* if path not found - return INVALID_TRACKDIR */
435 Trackdir next_trackdir
= INVALID_TRACKDIR
;
436 Node
*pNode
= Yapf().GetBestNode();
437 if (pNode
!= nullptr) {
438 /* reserve till end of path */
439 this->SetReservationTarget(pNode
, pNode
->GetLastTile(), pNode
->GetLastTrackdir());
441 /* path was found or at least suggested
442 * walk through the path back to the origin */
443 Node
*pPrev
= nullptr;
444 while (pNode
->m_parent
!= nullptr) {
446 pNode
= pNode
->m_parent
;
448 this->FindSafePositionOnNode(pPrev
);
450 /* return trackdir from the best origin node (one of start nodes) */
451 Node
&best_next_node
= *pPrev
;
452 next_trackdir
= best_next_node
.GetTrackdir();
454 if (reserve_track
&& path_found
) this->TryReservePath(target
, pNode
->GetLastTile());
457 /* Treat the path as found if stopped on the first two way signal(s). */
458 path_found
|= Yapf().m_stopped_on_first_two_way_signal
;
459 return next_trackdir
;
462 static bool stCheckReverseTrain(const Train
*v
, TileIndex t1
, Trackdir td1
, TileIndex t2
, Trackdir td2
, int reverse_penalty
)
465 bool result1
= pf1
.CheckReverseTrain(v
, t1
, td1
, t2
, td2
, reverse_penalty
);
467 if (_debug_desync_level
>= 2) {
469 pf2
.DisableCache(true);
470 bool result2
= pf2
.CheckReverseTrain(v
, t1
, td1
, t2
, td2
, reverse_penalty
);
471 if (result1
!= result2
) {
472 DEBUG(desync
, 2, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1
? "T" : "F", result2
? "T" : "F");
480 inline bool CheckReverseTrain(const Train
*v
, TileIndex t1
, Trackdir td1
, TileIndex t2
, Trackdir td2
, int reverse_penalty
)
482 /* create pathfinder instance
483 * set origin and destination nodes */
484 Yapf().SetOrigin(t1
, td1
, t2
, td2
, reverse_penalty
, false);
485 Yapf().SetDestination(v
);
487 /* find the best path */
488 bool bFound
= Yapf().FindPath(v
);
490 if (!bFound
) return false;
493 * walk through the path back to the origin */
494 Node
*pNode
= Yapf().GetBestNode();
495 while (pNode
->m_parent
!= nullptr) {
496 pNode
= pNode
->m_parent
;
499 /* check if it was reversed origin */
500 Node
&best_org_node
= *pNode
;
501 bool reversed
= (best_org_node
.m_cost
!= 0);
506 template <class Tpf_
, class Ttrack_follower
, class Tnode_list
, template <class Types
> class TdestinationT
, template <class Types
> class TfollowT
>
507 struct CYapfRail_TypesT
509 typedef CYapfRail_TypesT
<Tpf_
, Ttrack_follower
, Tnode_list
, TdestinationT
, TfollowT
> Types
;
512 typedef Ttrack_follower TrackFollower
;
513 typedef Tnode_list NodeList
;
514 typedef Train VehicleType
;
515 typedef CYapfBaseT
<Types
> PfBase
;
516 typedef TfollowT
<Types
> PfFollow
;
517 typedef CYapfOriginTileTwoWayT
<Types
> PfOrigin
;
518 typedef TdestinationT
<Types
> PfDestination
;
519 typedef CYapfSegmentCostCacheGlobalT
<Types
> PfCache
;
520 typedef CYapfCostRailT
<Types
> PfCost
;
523 struct CYapfRail1
: CYapfT
<CYapfRail_TypesT
<CYapfRail1
, CFollowTrackRail
, CRailNodeListTrackDir
, CYapfDestinationTileOrStationRailT
, CYapfFollowRailT
> > {};
524 struct CYapfRail2
: CYapfT
<CYapfRail_TypesT
<CYapfRail2
, CFollowTrackRailNo90
, CRailNodeListTrackDir
, CYapfDestinationTileOrStationRailT
, CYapfFollowRailT
> > {};
526 struct CYapfAnyDepotRail1
: CYapfT
<CYapfRail_TypesT
<CYapfAnyDepotRail1
, CFollowTrackRail
, CRailNodeListTrackDir
, CYapfDestinationAnyDepotRailT
, CYapfFollowAnyDepotRailT
> > {};
527 struct CYapfAnyDepotRail2
: CYapfT
<CYapfRail_TypesT
<CYapfAnyDepotRail2
, CFollowTrackRailNo90
, CRailNodeListTrackDir
, CYapfDestinationAnyDepotRailT
, CYapfFollowAnyDepotRailT
> > {};
529 struct CYapfAnySafeTileRail1
: CYapfT
<CYapfRail_TypesT
<CYapfAnySafeTileRail1
, CFollowTrackFreeRail
, CRailNodeListTrackDir
, CYapfDestinationAnySafeTileRailT
, CYapfFollowAnySafeTileRailT
> > {};
530 struct CYapfAnySafeTileRail2
: CYapfT
<CYapfRail_TypesT
<CYapfAnySafeTileRail2
, CFollowTrackFreeRailNo90
, CRailNodeListTrackDir
, CYapfDestinationAnySafeTileRailT
, CYapfFollowAnySafeTileRailT
> > {};
533 Track
YapfTrainChooseTrack(const Train
*v
, TileIndex tile
, DiagDirection enterdir
, TrackBits tracks
, bool &path_found
, bool reserve_track
, PBSTileInfo
*target
)
535 /* default is YAPF type 2 */
536 typedef Trackdir (*PfnChooseRailTrack
)(const Train
*, TileIndex
, DiagDirection
, TrackBits
, bool&, bool, PBSTileInfo
*);
537 PfnChooseRailTrack pfnChooseRailTrack
= &CYapfRail1::stChooseRailTrack
;
539 /* check if non-default YAPF type needed */
540 if (_settings_game
.pf
.forbid_90_deg
) {
541 pfnChooseRailTrack
= &CYapfRail2::stChooseRailTrack
; // Trackdir, forbid 90-deg
544 Trackdir td_ret
= pfnChooseRailTrack(v
, tile
, enterdir
, tracks
, path_found
, reserve_track
, target
);
545 return (td_ret
!= INVALID_TRACKDIR
) ? TrackdirToTrack(td_ret
) : FindFirstTrack(tracks
);
548 bool YapfTrainCheckReverse(const Train
*v
)
550 const Train
*last_veh
= v
->Last();
552 /* get trackdirs of both ends */
553 Trackdir td
= v
->GetVehicleTrackdir();
554 Trackdir td_rev
= ReverseTrackdir(last_veh
->GetVehicleTrackdir());
556 /* tiles where front and back are */
557 TileIndex tile
= v
->tile
;
558 TileIndex tile_rev
= last_veh
->tile
;
560 int reverse_penalty
= 0;
562 if (v
->track
== TRACK_BIT_WORMHOLE
) {
563 /* front in tunnel / on bridge */
564 DiagDirection dir_into_wormhole
= GetTunnelBridgeDirection(tile
);
566 if (TrackdirToExitdir(td
) == dir_into_wormhole
) tile
= GetOtherTunnelBridgeEnd(tile
);
567 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
569 /* Current position of the train in the wormhole */
570 TileIndex cur_tile
= TileVirtXY(v
->x_pos
, v
->y_pos
);
572 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
573 * Note: Negative penalties are ok for the start tile. */
574 reverse_penalty
-= DistanceManhattan(cur_tile
, tile
) * YAPF_TILE_LENGTH
;
577 if (last_veh
->track
== TRACK_BIT_WORMHOLE
) {
578 /* back in tunnel / on bridge */
579 DiagDirection dir_into_wormhole
= GetTunnelBridgeDirection(tile_rev
);
581 if (TrackdirToExitdir(td_rev
) == dir_into_wormhole
) tile_rev
= GetOtherTunnelBridgeEnd(tile_rev
);
582 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
584 /* Current position of the last wagon in the wormhole */
585 TileIndex cur_tile
= TileVirtXY(last_veh
->x_pos
, last_veh
->y_pos
);
587 /* Add distance to drive in the wormhole as penalty for the revere path. */
588 reverse_penalty
+= DistanceManhattan(cur_tile
, tile_rev
) * YAPF_TILE_LENGTH
;
591 typedef bool (*PfnCheckReverseTrain
)(const Train
*, TileIndex
, Trackdir
, TileIndex
, Trackdir
, int);
592 PfnCheckReverseTrain pfnCheckReverseTrain
= CYapfRail1::stCheckReverseTrain
;
594 /* check if non-default YAPF type needed */
595 if (_settings_game
.pf
.forbid_90_deg
) {
596 pfnCheckReverseTrain
= &CYapfRail2::stCheckReverseTrain
; // Trackdir, forbid 90-deg
599 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
600 if (reverse_penalty
== 0) reverse_penalty
= 1;
602 bool reverse
= pfnCheckReverseTrain(v
, tile
, td
, tile_rev
, td_rev
, reverse_penalty
);
607 FindDepotData
YapfTrainFindNearestDepot(const Train
*v
, int max_penalty
)
609 const Train
*last_veh
= v
->Last();
611 PBSTileInfo origin
= FollowTrainReservation(v
);
612 TileIndex last_tile
= last_veh
->tile
;
613 Trackdir td_rev
= ReverseTrackdir(last_veh
->GetVehicleTrackdir());
615 typedef FindDepotData (*PfnFindNearestDepotTwoWay
)(const Train
*, TileIndex
, Trackdir
, TileIndex
, Trackdir
, int, int);
616 PfnFindNearestDepotTwoWay pfnFindNearestDepotTwoWay
= &CYapfAnyDepotRail1::stFindNearestDepotTwoWay
;
618 /* check if non-default YAPF type needed */
619 if (_settings_game
.pf
.forbid_90_deg
) {
620 pfnFindNearestDepotTwoWay
= &CYapfAnyDepotRail2::stFindNearestDepotTwoWay
; // Trackdir, forbid 90-deg
623 return pfnFindNearestDepotTwoWay(v
, origin
.tile
, origin
.trackdir
, last_tile
, td_rev
, max_penalty
, YAPF_INFINITE_PENALTY
);
626 bool YapfTrainFindNearestSafeTile(const Train
*v
, TileIndex tile
, Trackdir td
, bool override_railtype
)
628 typedef bool (*PfnFindNearestSafeTile
)(const Train
*, TileIndex
, Trackdir
, bool);
629 PfnFindNearestSafeTile pfnFindNearestSafeTile
= CYapfAnySafeTileRail1::stFindNearestSafeTile
;
631 /* check if non-default YAPF type needed */
632 if (_settings_game
.pf
.forbid_90_deg
) {
633 pfnFindNearestSafeTile
= &CYapfAnySafeTileRail2::stFindNearestSafeTile
;
636 return pfnFindNearestSafeTile(v
, tile
, td
, override_railtype
);
639 /** if any track changes, this counter is incremented - that will invalidate segment cost cache */
640 int CSegmentCostCacheBase::s_rail_change_counter
= 0;
642 void YapfNotifyTrackLayoutChange(TileIndex tile
, Track track
)
644 CSegmentCostCacheBase::NotifyTrackLayoutChange(tile
, track
);