1 /*
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/>.
6  */
7 
8 /** @file yapf_destrail.hpp Determining the destination for rail vehicles. */
9 
10 #ifndef YAPF_DESTRAIL_HPP
11 #define YAPF_DESTRAIL_HPP
12 
13 class CYapfDestinationRailBase {
14 protected:
15 	RailTypes m_compatible_railtypes;
16 
17 public:
SetDestination(const Train * v,bool override_rail_type=false)18 	void SetDestination(const Train *v, bool override_rail_type = false)
19 	{
20 		m_compatible_railtypes = v->compatible_railtypes;
21 		if (override_rail_type) m_compatible_railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes;
22 	}
23 
IsCompatibleRailType(RailType rt)24 	bool IsCompatibleRailType(RailType rt)
25 	{
26 		return HasBit(m_compatible_railtypes, rt);
27 	}
28 
GetCompatibleRailTypes() const29 	RailTypes GetCompatibleRailTypes() const
30 	{
31 		return m_compatible_railtypes;
32 	}
33 };
34 
35 template <class Types>
36 class CYapfDestinationAnyDepotRailT : public CYapfDestinationRailBase {
37 public:
38 	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
39 	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
40 	typedef typename Node::Key Key;               ///< key to hash tables
41 
42 	/** to access inherited path finder */
Yapf()43 	Tpf& Yapf()
44 	{
45 		return *static_cast<Tpf *>(this);
46 	}
47 
48 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(Node & n)49 	inline bool PfDetectDestination(Node &n)
50 	{
51 		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
52 	}
53 
54 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(TileIndex tile,Trackdir td)55 	inline bool PfDetectDestination(TileIndex tile, Trackdir td)
56 	{
57 		bool bDest = IsRailDepotTile(tile);
58 		return bDest;
59 	}
60 
61 	/**
62 	 * Called by YAPF to calculate cost estimate. Calculates distance to the destination
63 	 *  adds it to the actual cost from origin and stores the sum to the Node::m_estimate
64 	 */
PfCalcEstimate(Node & n)65 	inline bool PfCalcEstimate(Node &n)
66 	{
67 		n.m_estimate = n.m_cost;
68 		return true;
69 	}
70 };
71 
72 template <class Types>
73 class CYapfDestinationAnySafeTileRailT : public CYapfDestinationRailBase {
74 public:
75 	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
76 	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
77 	typedef typename Node::Key Key;               ///< key to hash tables
78 	typedef typename Types::TrackFollower TrackFollower; ///< TrackFollower. Need to typedef for gcc 2.95
79 
80 	/** to access inherited path finder */
Yapf()81 	Tpf& Yapf()
82 	{
83 		return *static_cast<Tpf *>(this);
84 	}
85 
86 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(Node & n)87 	inline bool PfDetectDestination(Node &n)
88 	{
89 		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
90 	}
91 
92 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(TileIndex tile,Trackdir td)93 	inline bool PfDetectDestination(TileIndex tile, Trackdir td)
94 	{
95 		return IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns()) &&
96 				IsWaitingPositionFree(Yapf().GetVehicle(), tile, td, !TrackFollower::Allow90degTurns());
97 	}
98 
99 	/**
100 	 * Called by YAPF to calculate cost estimate. Calculates distance to the destination
101 	 *  adds it to the actual cost from origin and stores the sum to the Node::m_estimate.
102 	 */
PfCalcEstimate(Node & n)103 	inline bool PfCalcEstimate(Node &n)
104 	{
105 		n.m_estimate = n.m_cost;
106 		return true;
107 	}
108 };
109 
110 template <class Types>
111 class CYapfDestinationTileOrStationRailT : public CYapfDestinationRailBase {
112 public:
113 	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
114 	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
115 	typedef typename Node::Key Key;               ///< key to hash tables
116 
117 protected:
118 	TileIndex    m_destTile;
119 	TrackdirBits m_destTrackdirs;
120 	StationID    m_dest_station_id;
121 
122 	/** to access inherited path finder */
Yapf()123 	Tpf& Yapf()
124 	{
125 		return *static_cast<Tpf *>(this);
126 	}
127 
128 public:
SetDestination(const Train * v)129 	void SetDestination(const Train *v)
130 	{
131 		switch (v->current_order.GetType()) {
132 			case OT_GOTO_WAYPOINT:
133 				if (!Waypoint::Get(v->current_order.GetDestination())->IsSingleTile()) {
134 					/* In case of 'complex' waypoints we need to do a look
135 					 * ahead. This look ahead messes a bit about, which
136 					 * means that it 'corrupts' the cache. To prevent this
137 					 * we disable caching when we're looking for a complex
138 					 * waypoint. */
139 					Yapf().DisableCache(true);
140 				}
141 				FALLTHROUGH;
142 
143 			case OT_GOTO_STATION:
144 				m_destTile = CalcClosestStationTile(v->current_order.GetDestination(), v->tile, v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT);
145 				m_dest_station_id = v->current_order.GetDestination();
146 				m_destTrackdirs = INVALID_TRACKDIR_BIT;
147 				break;
148 
149 			default:
150 				m_destTile = v->dest_tile;
151 				m_dest_station_id = INVALID_STATION;
152 				m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_RAIL, 0));
153 				break;
154 		}
155 		CYapfDestinationRailBase::SetDestination(v);
156 	}
157 
158 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(Node & n)159 	inline bool PfDetectDestination(Node &n)
160 	{
161 		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
162 	}
163 
164 	/** Called by YAPF to detect if node ends in the desired destination */
PfDetectDestination(TileIndex tile,Trackdir td)165 	inline bool PfDetectDestination(TileIndex tile, Trackdir td)
166 	{
167 		if (m_dest_station_id != INVALID_STATION) {
168 			return HasStationTileRail(tile)
169 				&& (GetStationIndex(tile) == m_dest_station_id)
170 				&& (GetRailStationTrack(tile) == TrackdirToTrack(td));
171 		}
172 
173 		return (tile == m_destTile) && HasTrackdir(m_destTrackdirs, td);
174 	}
175 
176 	/**
177 	 * Called by YAPF to calculate cost estimate. Calculates distance to the destination
178 	 *  adds it to the actual cost from origin and stores the sum to the Node::m_estimate
179 	 */
PfCalcEstimate(Node & n)180 	inline bool PfCalcEstimate(Node &n)
181 	{
182 		static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
183 		static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
184 		if (PfDetectDestination(n)) {
185 			n.m_estimate = n.m_cost;
186 			return true;
187 		}
188 
189 		TileIndex tile = n.GetLastTile();
190 		DiagDirection exitdir = TrackdirToExitdir(n.GetLastTrackdir());
191 		int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
192 		int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
193 		int x2 = 2 * TileX(m_destTile);
194 		int y2 = 2 * TileY(m_destTile);
195 		int dx = abs(x1 - x2);
196 		int dy = abs(y1 - y2);
197 		int dmin = std::min(dx, dy);
198 		int dxy = abs(dx - dy);
199 		int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
200 		n.m_estimate = n.m_cost + d;
201 		assert(n.m_estimate >= n.m_parent->m_estimate);
202 		return true;
203 	}
204 };
205 
206 #endif /* YAPF_DESTRAIL_HPP */
207