4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file follow_track.hpp Template function for track followers */
12 #ifndef FOLLOW_TRACK_HPP
13 #define FOLLOW_TRACK_HPP
15 #include "../map/road.h"
17 #include "../roadveh.h"
18 #include "../station_base.h"
20 #include "../tunnelbridge.h"
21 #include "../depot_func.h"
22 #include "../bridge.h"
24 #include "pathfinder_type.h"
25 #include "pf_performance_timer.hpp"
28 * Track follower common base class
30 struct CFollowTrackBase
54 PFPos m_old
; ///< the origin (vehicle moved from) before move
55 PFNewPos m_new
; ///< the new tile (the vehicle has entered)
56 DiagDirection m_exitdir
; ///< exit direction (leaving the old tile)
57 TileFlag m_flag
; ///< last turn passed station, tunnel or bridge
58 int m_tiles_skipped
; ///< number of skipped tunnel or station tiles
64 * Track follower rail base class
66 struct CFollowTrackRailBase
: CFollowTrackBase
68 static inline bool StepWormhole() { return true; }
70 const Owner m_veh_owner
; ///< owner of the vehicle
71 const bool m_allow_90deg
;
72 const RailTypes m_railtypes
;
73 CPerformanceTimer
*const m_pPerf
;
75 inline bool Allow90deg() const { return m_allow_90deg
; }
77 inline CFollowTrackRailBase(const Train
*v
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
78 : m_veh_owner(v
->owner
), m_allow_90deg(allow_90deg
), m_railtypes(railtype_override
== INVALID_RAILTYPES
? v
->compatible_railtypes
: railtype_override
), m_pPerf(pPerf
)
81 assert(m_railtypes
!= INVALID_RAILTYPES
);
84 inline CFollowTrackRailBase(Owner o
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
85 : m_veh_owner(o
), m_allow_90deg(allow_90deg
), m_railtypes(railtype_override
), m_pPerf(pPerf
)
87 assert(railtype_override
!= INVALID_RAILTYPES
);
90 static inline bool IsTrackBridgeTile(TileIndex tile
)
92 return IsRailBridgeTile(tile
);
95 inline TrackdirBits
GetTrackStatusTrackdirBits(TileIndex tile
) const
97 return TrackStatusToTrackdirBits(GetTileRailwayStatus(tile
));
100 /** check old tile */
101 inline TileResult
CheckOldTile()
103 assert((GetTrackStatusTrackdirBits(m_old
.tile
) & TrackdirToTrackdirBits(m_old
.td
)) != 0);
105 /* depots cause reversing */
106 if (IsRailDepotTile(m_old
.tile
)) {
107 DiagDirection exitdir
= GetGroundDepotDirection(m_old
.tile
);
108 if (exitdir
!= m_exitdir
) {
109 assert(exitdir
== ReverseDiagDir(m_exitdir
));
117 /** stores track status (available trackdirs) for the new tile into m_new.trackdirs */
118 inline bool CheckNewTile()
120 CPerfStart
perf(*m_pPerf
);
122 if (IsNormalRailTile(m_new
.tile
)) {
123 m_new
.trackdirs
= TrackBitsToTrackdirBits(GetTrackBits(m_new
.tile
));
125 m_new
.trackdirs
= GetTrackStatusTrackdirBits(m_new
.tile
);
128 if (m_new
.trackdirs
== TRACKDIR_BIT_NONE
) return false;
132 if (IsRailDepotTile(m_new
.tile
)) {
133 DiagDirection exitdir
= GetGroundDepotDirection(m_new
.tile
);
134 if (ReverseDiagDir(exitdir
) != m_exitdir
) {
140 /* rail transport is possible only on tiles with the same owner as vehicle */
141 if (GetTileOwner(m_new
.tile
) != m_veh_owner
) {
142 /* different owner */
147 /* rail transport is possible only on compatible rail types */
149 if (IsRailwayTile(m_new
.tile
)) {
150 rail_type
= GetSideRailType(m_new
.tile
, ReverseDiagDir(m_exitdir
));
151 if (rail_type
== INVALID_RAILTYPE
) {
156 rail_type
= GetRailType(m_new
.tile
);
159 if (!HasBit(m_railtypes
, rail_type
)) {
160 /* incompatible rail type */
161 m_err
= EC_RAIL_TYPE
;
165 /* tunnel holes and bridge ramps can be entered only from proper direction */
166 if (IsTunnelTile(m_new
.tile
)) {
167 if (m_flag
!= TF_TUNNEL
) {
168 DiagDirection tunnel_enterdir
= GetTunnelBridgeDirection(m_new
.tile
);
169 if (tunnel_enterdir
!= m_exitdir
) {
174 } else if (IsRailBridgeTile(m_new
.tile
)) {
175 if (m_flag
!= TF_BRIDGE
) {
176 DiagDirection ramp_enderdir
= GetTunnelBridgeDirection(m_new
.tile
);
177 if (ramp_enderdir
== ReverseDiagDir(m_exitdir
)) {
184 /* special handling for rail stations - get to the end of platform */
185 if (m_flag
== TF_STATION
) {
186 /* entered railway station
187 * get platform length */
188 uint length
= BaseStation::GetByTile(m_new
.tile
)->GetPlatformLength(m_new
.tile
, TrackdirToExitdir(m_old
.td
));
189 /* how big step we must do to get to the last platform tile; */
190 m_tiles_skipped
= length
- 1;
191 /* move to the platform end */
192 TileIndexDiff diff
= TileOffsByDiagDir(m_exitdir
);
193 diff
*= m_tiles_skipped
;
194 m_new
.tile
= TILE_ADD(m_new
.tile
, diff
);
200 /** return true if we successfully reversed at end of road/track */
201 inline bool CheckEndOfLine()
207 inline bool CheckStation()
209 return HasStationTileRail(m_new
.tile
);
212 /** Helper for pathfinders - get min/max speed on m_old */
213 int GetSpeedLimit(int *pmin_speed
= NULL
) const
215 /* Check for on-bridge and railtype speed limit */
216 TileIndex bridge_tile
;
219 if (!m_old
.InWormhole()) {
220 bridge_tile
= IsRailBridgeTile(m_old
.tile
) ? m_old
.tile
: INVALID_TILE
;
221 rt
= GetRailType(m_old
.tile
, TrackdirToTrack(m_old
.td
));
222 } else if (IsTileSubtype(m_old
.wormhole
, TT_BRIDGE
)) {
223 bridge_tile
= m_old
.wormhole
;
224 rt
= GetBridgeRailType(bridge_tile
);
226 bridge_tile
= INVALID_TILE
;
227 rt
= GetRailType(m_old
.wormhole
);
232 /* Check for on-bridge speed limit */
233 if (bridge_tile
!= INVALID_TILE
) {
234 max_speed
= GetBridgeSpec(GetRailBridgeType(bridge_tile
))->speed
;
236 max_speed
= INT_MAX
; // no limit
239 /* Check for speed limit imposed by railtype */
240 uint16 rail_speed
= GetRailTypeInfo(rt
)->max_speed
;
241 if (rail_speed
> 0) max_speed
= min(max_speed
, rail_speed
);
243 /* if min speed was requested, return it */
244 if (pmin_speed
!= NULL
) *pmin_speed
= 0;
249 struct CFollowTrackAnyRailBase
: CFollowTrackRailBase
251 inline CFollowTrackAnyRailBase(const Train
*v
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
252 : CFollowTrackRailBase(v
, allow_90deg
, railtype_override
, pPerf
)
256 inline CFollowTrackAnyRailBase(Owner o
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
257 : CFollowTrackRailBase(o
, allow_90deg
, railtype_override
, pPerf
)
261 inline static bool DoTrackMasking() { return false; }
263 inline bool MaskReservedTracks() { return true; }
266 struct CFollowTrackFreeRailBase
: CFollowTrackRailBase
268 inline CFollowTrackFreeRailBase(const Train
*v
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
269 : CFollowTrackRailBase(v
, allow_90deg
, railtype_override
, pPerf
)
273 inline CFollowTrackFreeRailBase(Owner o
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
, CPerformanceTimer
*pPerf
= NULL
)
274 : CFollowTrackRailBase(o
, allow_90deg
, railtype_override
, pPerf
)
278 inline static bool DoTrackMasking() { return true; }
280 inline bool MaskReservedTracks()
282 if (m_flag
== TF_STATION
) {
283 /* Check skipped station tiles as well. */
284 TileIndexDiff diff
= TileOffsByDiagDir(m_exitdir
);
285 for (TileIndex tile
= m_new
.tile
- diff
* m_tiles_skipped
; tile
!= m_new
.tile
; tile
+= diff
) {
286 if (HasStationReservation(tile
)) {
287 m_new
.td
= INVALID_TRACKDIR
;
288 m_new
.trackdirs
= TRACKDIR_BIT_NONE
;
295 if (m_new
.InWormhole()) {
296 assert(m_new
.IsTrackdirSet());
297 if (HasReservedPos(m_new
)) {
298 m_new
.td
= INVALID_TRACKDIR
;
299 m_new
.trackdirs
= TRACKDIR_BIT_NONE
;
307 TrackBits reserved
= GetReservedTrackbits(m_new
.tile
);
308 /* Mask already reserved trackdirs. */
309 m_new
.trackdirs
&= ~TrackBitsToTrackdirBits(reserved
);
310 /* Mask out all trackdirs that conflict with the reservation. */
312 FOR_EACH_SET_TRACK(t
, TrackdirBitsToTrackBits(m_new
.trackdirs
)) {
313 if (TracksOverlap(reserved
| TrackToTrackBits(t
))) m_new
.trackdirs
&= ~TrackToTrackdirBits(t
);
315 if (m_new
.trackdirs
== TRACKDIR_BIT_NONE
) {
316 m_new
.td
= INVALID_TRACKDIR
;
320 /* Check if the resulting trackdirs is a single trackdir */
327 * Track follower road base class
329 struct CFollowTrackRoadBase
: CFollowTrackBase
331 static inline bool StepWormhole() { return false; }
333 const RoadVehicle
*const m_veh
; ///< moving vehicle
335 static inline bool Allow90deg() { return true; }
337 inline CFollowTrackRoadBase(const RoadVehicle
*v
)
343 static inline bool IsTrackBridgeTile(TileIndex tile
)
345 return IsRoadBridgeTile(tile
);
348 inline TrackdirBits
GetTrackStatusTrackdirBits(TileIndex tile
) const
350 return TrackStatusToTrackdirBits(GetTileRoadStatus(tile
, m_veh
->compatible_roadtypes
));
353 inline bool IsTram() { return HasBit(m_veh
->compatible_roadtypes
, ROADTYPE_TRAM
); }
355 /** Tests if a tile is a road tile with a single tramtrack (tram can reverse) */
356 inline DiagDirection
GetSingleTramBit(TileIndex tile
)
358 assert(IsTram()); // this function shouldn't be called in other cases
360 if (IsRoadTile(tile
)) {
361 RoadBits rb
= GetRoadBits(tile
, ROADTYPE_TRAM
);
363 case ROAD_NW
: return DIAGDIR_NW
;
364 case ROAD_SW
: return DIAGDIR_SW
;
365 case ROAD_SE
: return DIAGDIR_SE
;
366 case ROAD_NE
: return DIAGDIR_NE
;
370 return INVALID_DIAGDIR
;
373 /** check old tile */
374 inline TileResult
CheckOldTile()
376 assert(((GetTrackStatusTrackdirBits(m_old
.tile
) & TrackdirToTrackdirBits(m_old
.td
)) != 0) ||
377 (IsTram() && GetSingleTramBit(m_old
.tile
) != INVALID_DIAGDIR
)); // Disable the assertion for single tram bits
379 /* depots cause reversing */
380 if (IsRoadDepotTile(m_old
.tile
)) {
381 DiagDirection exitdir
= GetGroundDepotDirection(m_old
.tile
);
382 if (exitdir
!= m_exitdir
) {
383 assert(exitdir
== ReverseDiagDir(m_exitdir
));
388 /* road stop can be left at one direction only unless it's a drive-through stop */
389 if (IsStandardRoadStopTile(m_old
.tile
)) {
390 DiagDirection exitdir
= GetRoadStopDir(m_old
.tile
);
391 if (exitdir
!= m_exitdir
) {
397 DiagDirection single_tram
= GetSingleTramBit(m_old
.tile
);
398 /* single tram bits cause reversing */
399 if (single_tram
== ReverseDiagDir(m_exitdir
)) {
402 /* single tram bits can only be left in one direction */
403 if (single_tram
!= INVALID_DIAGDIR
&& single_tram
!= m_exitdir
) {
411 /** stores track status (available trackdirs) for the new tile into m_new.trackdirs */
412 inline bool CheckNewTile()
414 m_new
.trackdirs
= GetTrackStatusTrackdirBits(m_new
.tile
);
416 if (m_new
.trackdirs
== TRACKDIR_BIT_NONE
) {
417 if (!IsTram()) return false;
419 /* GetTileRoadStatus() returns 0 for single tram bits.
420 * As we cannot change it there (easily) without breaking something, change it here */
421 DiagDirection single_tram
= GetSingleTramBit(m_new
.tile
);
422 if (single_tram
== ReverseDiagDir(m_exitdir
)) {
423 m_new
.trackdirs
= DiagDirToAxis(single_tram
) == AXIS_X
? TRACKDIR_BIT_X_NE
| TRACKDIR_BIT_X_SW
: TRACKDIR_BIT_Y_NW
| TRACKDIR_BIT_Y_SE
;
431 if (IsStandardRoadStopTile(m_new
.tile
)) {
432 /* road stop can be entered from one direction only unless it's a drive-through stop */
433 DiagDirection exitdir
= GetRoadStopDir(m_new
.tile
);
434 if (ReverseDiagDir(exitdir
) != m_exitdir
) {
440 /* depots can also be entered from one direction only */
441 if (IsRoadDepotTile(m_new
.tile
)) {
442 DiagDirection exitdir
= GetGroundDepotDirection(m_new
.tile
);
443 if (ReverseDiagDir(exitdir
) != m_exitdir
) {
447 /* don't try to enter other company's depots */
448 if (GetTileOwner(m_new
.tile
) != m_veh
->owner
) {
454 /* tunnel holes and bridge ramps can be entered only from proper direction */
455 if (IsTunnelTile(m_new
.tile
)) {
456 if (m_flag
!= TF_TUNNEL
) {
457 DiagDirection tunnel_enterdir
= GetTunnelBridgeDirection(m_new
.tile
);
458 if (tunnel_enterdir
!= m_exitdir
) {
463 } else if (IsRoadBridgeTile(m_new
.tile
)) {
464 if (m_flag
!= TF_BRIDGE
) {
465 DiagDirection ramp_enderdir
= GetTunnelBridgeDirection(m_new
.tile
);
466 if (ramp_enderdir
== ReverseDiagDir(m_exitdir
)) {
476 /** return true if we successfully reversed at end of road/track */
477 inline bool CheckEndOfLine()
479 /* In case we can't enter the next tile, but are
480 * a normal road vehicle, then we can actually
481 * try to reverse as this is the end of the road.
482 * Trams can only turn on the appropriate bits in
483 * which case reaching this would mean a dead end
484 * near a building and in that case there would
485 * a "false" QueryNewTileTrackStatus result and
486 * as such reversing is already tried. The fact
487 * that function failed can have to do with a
488 * missing road bit, or inability to connect the
489 * different bits due to slopes. */
491 /* if we reached the end of road, we can reverse the RV and continue moving */
492 m_exitdir
= ReverseDiagDir(m_exitdir
);
493 /* new tile will be the same as old one */
494 m_new
.tile
= m_old
.tile
;
495 m_new
.wormhole
= INVALID_TILE
;
496 /* set new trackdir bits to all reachable trackdirs */
497 m_new
.trackdirs
= GetTrackStatusTrackdirBits(m_new
.tile
);
498 m_new
.trackdirs
&= DiagdirReachesTrackdirs(m_exitdir
);
499 /* we always have some trackdirs reachable after reversal */
500 assert(m_new
.trackdirs
!= TRACKDIR_BIT_NONE
);
501 /* check if the resulting trackdirs is a single trackdir */
509 inline bool CheckStation()
511 return IsRoadStopTile(m_new
.tile
);
514 /** Helper for pathfinders - get min/max speed on m_old */
515 int GetSpeedLimit(int *pmin_speed
= NULL
) const
519 /* Check for on-bridge speed limit */
520 if (IsRoadBridgeTile(m_old
.tile
)) {
521 max_speed
= 2 * GetBridgeSpec(GetRoadBridgeType(m_old
.tile
))->speed
;
523 max_speed
= INT_MAX
; // no limit
526 /* if min speed was requested, return it */
527 if (pmin_speed
!= NULL
) *pmin_speed
= 0;
533 * Track follower water base class
535 struct CFollowTrackWaterBase
: CFollowTrackBase
537 static inline bool StepWormhole() { return false; }
539 const bool m_allow_90deg
;
541 inline bool Allow90deg() const { return m_allow_90deg
; }
543 inline CFollowTrackWaterBase(bool allow_90deg
= true)
544 : m_allow_90deg(allow_90deg
)
548 static inline bool IsTrackBridgeTile(TileIndex tile
)
550 return IsAqueductTile(tile
);
553 inline TrackdirBits
GetTrackStatusTrackdirBits(TileIndex tile
) const
555 return TrackStatusToTrackdirBits(GetTileWaterwayStatus(tile
));
558 /** check old tile */
559 inline TileResult
CheckOldTile()
561 assert((GetTrackStatusTrackdirBits(m_old
.tile
) & TrackdirToTrackdirBits(m_old
.td
)) != 0);
566 /** stores track status (available trackdirs) for the new tile into m_new.trackdirs */
567 inline bool CheckNewTile()
569 m_new
.trackdirs
= GetTrackStatusTrackdirBits(m_new
.tile
);
571 if (m_new
.trackdirs
== TRACKDIR_BIT_NONE
) return false;
573 /* tunnel holes and bridge ramps can be entered only from proper direction */
574 if (IsAqueductTile(m_new
.tile
)) {
575 if (m_flag
!= TF_BRIDGE
) {
576 DiagDirection ramp_enderdir
= GetTunnelBridgeDirection(m_new
.tile
);
577 if (ramp_enderdir
== ReverseDiagDir(m_exitdir
)) {
587 /** return true if we successfully reversed at end of road/track */
588 inline bool CheckEndOfLine()
594 inline bool CheckStation()
602 * Track follower helper template class (can serve pathfinders and vehicle
603 * controllers). See 6 different typedefs below for 3 different transport
604 * types w/ or w/o 90-deg turns allowed
606 template <class Base
>
607 struct CFollowTrack
: Base
609 /* MSVC does not support variadic templates. Oh well... */
611 inline CFollowTrack() : Base() { }
613 template <typename T1
>
614 inline CFollowTrack (T1 t1
) : Base (t1
) { }
616 template <typename T1
, typename T2
>
617 inline CFollowTrack (T1 t1
, T2 t2
) : Base (t1
, t2
) { }
619 template <typename T1
, typename T2
, typename T3
>
620 inline CFollowTrack (T1 t1
, T2 t2
, T3 t3
) : Base (t1
, t2
, t3
) { }
622 template <typename T1
, typename T2
, typename T3
, typename T4
>
623 inline CFollowTrack (T1 t1
, T2 t2
, T3 t3
, T4 t4
) : Base (t1
, t2
, t3
, t4
) { }
626 * main follower routine. Fills all members and return true on success.
627 * Otherwise returns false if track can't be followed.
629 inline bool Follow(const PFPos
&pos
)
632 Base::m_err
= Base::EC_NONE
;
633 Base::m_exitdir
= TrackdirToExitdir(Base::m_old
.td
);
635 if (Base::m_old
.InWormhole()) {
638 switch (Base::CheckOldTile()) {
639 case Base::TR_NO_WAY
:
640 Base::m_err
= Base::EC_NO_WAY
;
642 case Base::TR_REVERSE
:
643 Base::m_new
.tile
= Base::m_old
.tile
;
644 Base::m_new
.wormhole
= INVALID_TILE
;
645 Base::m_new
.td
= ReverseTrackdir(Base::m_old
.td
);
646 Base::m_new
.trackdirs
= TrackdirToTrackdirBits(Base::m_new
.td
);
647 Base::m_exitdir
= ReverseDiagDir(Base::m_exitdir
);
648 Base::m_tiles_skipped
= 0;
649 Base::m_flag
= Base::TF_NONE
;
657 if (Base::m_new
.InWormhole()) {
658 assert(Base::StepWormhole());
659 Base::m_new
.td
= DiagDirToDiagTrackdir(Base::m_exitdir
);
660 Base::m_new
.trackdirs
= TrackdirToTrackdirBits(Base::m_new
.td
);
664 if (!Base::CheckNewTile() || (Base::m_new
.trackdirs
&= DiagdirReachesTrackdirs(Base::m_exitdir
)) == TRACKDIR_BIT_NONE
) {
665 return Base::CheckEndOfLine();
667 if (!Base::Allow90deg()) {
668 Base::m_new
.trackdirs
&= (TrackdirBits
)~(int)TrackdirCrossesTrackdirs(Base::m_old
.td
);
669 if (Base::m_new
.trackdirs
== TRACKDIR_BIT_NONE
) {
670 Base::m_err
= Base::EC_90DEG
;
674 /* Check if the resulting trackdirs is a single trackdir */
675 Base::m_new
.SetTrackdir();
679 inline bool FollowNext()
681 assert(Base::m_new
.tile
!= INVALID_TILE
);
682 assert(Base::m_new
.IsTrackdirSet());
683 return Follow(Base::m_new
);
686 inline void SetPos(const PFPos
&pos
)
688 Base::m_new
.PFPos::operator = (pos
);
689 Base::m_new
.trackdirs
= TrackdirToTrackdirBits(pos
.td
);
693 /** Follow m_exitdir from m_old and fill m_new.tile and m_tiles_skipped */
694 inline void FollowTileExit()
696 assert(!Base::m_old
.InWormhole());
697 /* extra handling for bridges in our direction */
698 if (Base::IsTrackBridgeTile(Base::m_old
.tile
)) {
699 if (Base::m_exitdir
== GetTunnelBridgeDirection(Base::m_old
.tile
)) {
700 /* we are entering the bridge */
701 Base::m_flag
= Base::TF_BRIDGE
;
702 Base::m_new
.tile
= GetOtherBridgeEnd(Base::m_old
.tile
);
703 Base::m_tiles_skipped
= GetTunnelBridgeLength(Base::m_new
.tile
, Base::m_old
.tile
);
704 if (Base::StepWormhole() && Base::m_tiles_skipped
> 0) {
705 Base::m_tiles_skipped
--;
706 Base::m_new
.wormhole
= Base::m_new
.tile
;
707 Base::m_new
.tile
= TILE_ADD(Base::m_new
.tile
, TileOffsByDiagDir(ReverseDiagDir(Base::m_exitdir
)));
709 Base::m_new
.wormhole
= INVALID_TILE
;
713 /* extra handling for tunnels in our direction */
714 } else if (IsTunnelTile(Base::m_old
.tile
)) {
715 DiagDirection enterdir
= GetTunnelBridgeDirection(Base::m_old
.tile
);
716 if (enterdir
== Base::m_exitdir
) {
717 /* we are entering the tunnel */
718 Base::m_flag
= Base::TF_TUNNEL
;
719 Base::m_new
.tile
= GetOtherTunnelEnd(Base::m_old
.tile
);
720 Base::m_tiles_skipped
= GetTunnelBridgeLength(Base::m_new
.tile
, Base::m_old
.tile
);
721 if (Base::StepWormhole() && Base::m_tiles_skipped
> 0) {
722 Base::m_tiles_skipped
--;
723 Base::m_new
.wormhole
= Base::m_new
.tile
;
724 Base::m_new
.tile
= TILE_ADD(Base::m_new
.tile
, TileOffsByDiagDir(ReverseDiagDir(Base::m_exitdir
)));
726 Base::m_new
.wormhole
= INVALID_TILE
;
730 assert(ReverseDiagDir(enterdir
) == Base::m_exitdir
);
733 /* normal or station tile, do one step */
734 TileIndexDiff diff
= TileOffsByDiagDir(Base::m_exitdir
);
735 Base::m_new
.tile
= TILE_ADD(Base::m_old
.tile
, diff
);
736 Base::m_new
.wormhole
= INVALID_TILE
;
738 /* special handling for stations */
739 Base::m_flag
= Base::CheckStation() ? Base::TF_STATION
: Base::TF_NONE
;
741 Base::m_tiles_skipped
= 0;
744 /** Follow m_old when in a wormhole */
745 inline void FollowWormhole()
747 assert(Base::m_old
.InWormhole());
748 assert(Base::IsTrackBridgeTile(Base::m_old
.wormhole
) || IsTunnelTile(Base::m_old
.wormhole
));
750 Base::m_new
.tile
= Base::m_old
.wormhole
;
751 Base::m_new
.wormhole
= INVALID_TILE
;
752 Base::m_flag
= IsTileSubtype(Base::m_old
.wormhole
, TT_BRIDGE
) ? Base::TF_BRIDGE
: Base::TF_TUNNEL
;
753 Base::m_tiles_skipped
= GetTunnelBridgeLength(Base::m_new
.tile
, Base::m_old
.tile
);
757 template <bool T90deg_turns_allowed
>
758 struct CFollowTrackWaterT
: CFollowTrack
<CFollowTrackWaterBase
>
760 inline CFollowTrackWaterT(const Ship
*v
)
761 : CFollowTrack
<CFollowTrackWaterBase
>(T90deg_turns_allowed
)
765 inline static bool Allow90degTurns() { return T90deg_turns_allowed
; }
768 typedef CFollowTrackWaterT
<true> CFollowTrackWater90
;
769 typedef CFollowTrackWaterT
<false> CFollowTrackWaterNo90
;
771 typedef CFollowTrack
<CFollowTrackRoadBase
> CFollowTrackRoad
;
773 template <class Base
, bool T90deg_turns_allowed
>
774 struct CFollowTrackRailT
: CFollowTrack
<Base
>
776 inline CFollowTrackRailT(const Train
*v
)
777 : CFollowTrack
<Base
>(v
, T90deg_turns_allowed
)
781 inline CFollowTrackRailT(const Train
*v
, RailTypes railtype_override
, CPerformanceTimer
*pPerf
= NULL
)
782 : CFollowTrack
<Base
>(v
, T90deg_turns_allowed
, railtype_override
, pPerf
)
786 inline static bool Allow90degTurns() { return T90deg_turns_allowed
; }
789 typedef CFollowTrackRailT
<CFollowTrackAnyRailBase
, true > CFollowTrackRail90
;
790 typedef CFollowTrackRailT
<CFollowTrackAnyRailBase
, false> CFollowTrackRailNo90
;
791 typedef CFollowTrackRailT
<CFollowTrackFreeRailBase
, true > CFollowTrackFreeRail90
;
792 typedef CFollowTrackRailT
<CFollowTrackFreeRailBase
, false> CFollowTrackFreeRailNo90
;
794 struct CFollowTrackRail
: CFollowTrack
<CFollowTrackAnyRailBase
>
796 inline CFollowTrackRail(const Train
*v
= NULL
, bool allow_90deg
= true, bool railtype_override
= false)
797 : CFollowTrack
<CFollowTrackAnyRailBase
>(v
, allow_90deg
, railtype_override
? GetRailTypeInfo(v
->railtype
)->compatible_railtypes
: INVALID_RAILTYPES
)
801 inline CFollowTrackRail(Owner o
, bool allow_90deg
= true, RailTypes railtype_override
= INVALID_RAILTYPES
)
802 : CFollowTrack
<CFollowTrackAnyRailBase
>(o
, allow_90deg
, railtype_override
)
807 #endif /* FOLLOW_TRACK_HPP */