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