follow_track.hpp
Go to the documentation of this file.00001
00002
00005 #ifndef FOLLOW_TRACK_HPP
00006 #define FOLLOW_TRACK_HPP
00007
00008 #include "yapf.hpp"
00009
00010
00014 template <TransportType Ttr_type_, bool T90deg_turns_allowed_ = true>
00015 struct CFollowTrackT
00016 {
00017 enum ErrorCode {
00018 EC_NONE,
00019 EC_OWNER,
00020 EC_RAIL_TYPE,
00021 EC_90DEG,
00022 EC_NO_WAY,
00023 };
00024
00025 const Vehicle* m_veh;
00026 TileIndex m_old_tile;
00027 Trackdir m_old_td;
00028 TileIndex m_new_tile;
00029 TrackdirBits m_new_td_bits;
00030 DiagDirection m_exitdir;
00031 bool m_is_tunnel;
00032 bool m_is_bridge;
00033 bool m_is_station;
00034 int m_tiles_skipped;
00035 ErrorCode m_err;
00036 CPerformanceTimer* m_pPerf;
00037
00038 FORCEINLINE CFollowTrackT(const Vehicle* v = NULL, CPerformanceTimer* pPerf = NULL)
00039 {
00040 Init(v, pPerf);
00041 }
00042
00043 FORCEINLINE void Init(const Vehicle* v, CPerformanceTimer* pPerf)
00044 {
00045 assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN));
00046 m_veh = v;
00047 m_pPerf = pPerf;
00048
00049 m_new_tile = INVALID_TILE;
00050 m_new_td_bits = TRACKDIR_BIT_NONE;
00051 m_exitdir = INVALID_DIAGDIR;
00052 m_is_station = m_is_bridge = m_is_tunnel = false;
00053 m_tiles_skipped = 0;
00054 m_err = EC_NONE;
00055 }
00056
00057 FORCEINLINE static TransportType TT() {return Ttr_type_;}
00058 FORCEINLINE static bool IsWaterTT() {return TT() == TRANSPORT_WATER;}
00059 FORCEINLINE static bool IsRailTT() {return TT() == TRANSPORT_RAIL;}
00060 FORCEINLINE bool IsTram() {return IsRoadTT() && HasBit(m_veh->u.road.compatible_roadtypes, ROADTYPE_TRAM);}
00061 FORCEINLINE static bool IsRoadTT() {return TT() == TRANSPORT_ROAD;}
00062 FORCEINLINE static bool Allow90degTurns() {return T90deg_turns_allowed_;}
00063
00065 FORCEINLINE DiagDirection GetSingleTramBit(TileIndex tile)
00066 {
00067 if (IsTram() && IsNormalRoadTile(tile)) {
00068 RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM);
00069 switch (rb) {
00070 case ROAD_NW: return DIAGDIR_NW;
00071 case ROAD_SW: return DIAGDIR_SW;
00072 case ROAD_SE: return DIAGDIR_SE;
00073 case ROAD_NE: return DIAGDIR_NE;
00074 default: break;
00075 }
00076 }
00077 return INVALID_DIAGDIR;
00078 }
00079
00082 FORCEINLINE bool Follow(TileIndex old_tile, Trackdir old_td)
00083 {
00084 m_old_tile = old_tile;
00085 m_old_td = old_td;
00086 m_err = EC_NONE;
00087 assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), m_veh->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
00088 (GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR));
00089 m_exitdir = TrackdirToExitdir(m_old_td);
00090 if (ForcedReverse()) return true;
00091 if (!CanExitOldTile()) return false;
00092 FollowTileExit();
00093 if (!QueryNewTileTrackStatus()) return TryReverse();
00094 if (!CanEnterNewTile()) return false;
00095 m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir);
00096 if (m_new_td_bits == TRACKDIR_BIT_NONE) {
00097 m_err = EC_NO_WAY;
00098 return false;
00099 }
00100 if (!Allow90degTurns()) {
00101 m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
00102 if (m_new_td_bits == TRACKDIR_BIT_NONE) {
00103 m_err = EC_90DEG;
00104 return false;
00105 }
00106 }
00107 return true;
00108 }
00109
00110 protected:
00112 FORCEINLINE void FollowTileExit()
00113 {
00114 m_is_station = m_is_bridge = m_is_tunnel = false;
00115 m_tiles_skipped = 0;
00116
00117
00118 if (IsTileType(m_old_tile, MP_TUNNELBRIDGE)) {
00119 DiagDirection enterdir = GetTunnelBridgeDirection(m_old_tile);
00120 if (enterdir == m_exitdir) {
00121
00122 if (IsTunnel(m_old_tile)) {
00123 m_is_tunnel = true;
00124 m_new_tile = GetOtherTunnelEnd(m_old_tile);
00125 } else {
00126 m_is_bridge = true;
00127 m_new_tile = GetOtherBridgeEnd(m_old_tile);
00128 }
00129 m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
00130 return;
00131 }
00132 assert(ReverseDiagDir(enterdir) == m_exitdir);
00133 }
00134
00135
00136 TileIndexDiff diff = TileOffsByDiagDir(m_exitdir);
00137 m_new_tile = TILE_ADD(m_old_tile, diff);
00138
00139
00140 if (IsRailTT() && IsRailwayStationTile(m_new_tile)) {
00141 m_is_station = true;
00142 } else if (IsRoadTT() && IsRoadStopTile(m_new_tile)) {
00143 m_is_station = true;
00144 } else {
00145 m_is_station = false;
00146 }
00147 }
00148
00150 FORCEINLINE bool QueryNewTileTrackStatus()
00151 {
00152 CPerfStart perf(*m_pPerf);
00153 if (IsRailTT() && GetTileType(m_new_tile) == MP_RAILWAY && IsPlainRailTile(m_new_tile)) {
00154 m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101);
00155 } else {
00156 m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), m_veh->u.road.compatible_roadtypes));
00157
00158 if (m_new_td_bits == 0) {
00159
00160
00161 switch (GetSingleTramBit(m_new_tile)) {
00162 case DIAGDIR_NE:
00163 case DIAGDIR_SW:
00164 m_new_td_bits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW;
00165 break;
00166
00167 case DIAGDIR_NW:
00168 case DIAGDIR_SE:
00169 m_new_td_bits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE;
00170 break;
00171
00172 default: break;
00173 }
00174 }
00175 }
00176 return (m_new_td_bits != TRACKDIR_BIT_NONE);
00177 }
00178
00180 FORCEINLINE bool CanExitOldTile()
00181 {
00182
00183 if (IsRoadTT() && IsStandardRoadStopTile(m_old_tile)) {
00184 DiagDirection exitdir = GetRoadStopDir(m_old_tile);
00185 if (exitdir != m_exitdir) {
00186 m_err = EC_NO_WAY;
00187 return false;
00188 }
00189 }
00190
00191
00192 DiagDirection single_tram = GetSingleTramBit(m_old_tile);
00193 if (single_tram != INVALID_DIAGDIR && single_tram != m_exitdir) {
00194 m_err = EC_NO_WAY;
00195 return false;
00196 }
00197
00198
00199 if (IsRoadTT() && IsTileDepotType(m_old_tile, TT())) {
00200 DiagDirection exitdir = GetRoadDepotDirection(m_old_tile);
00201 if (exitdir != m_exitdir) {
00202 m_err = EC_NO_WAY;
00203 return false;
00204 }
00205 }
00206 return true;
00207 }
00208
00210 FORCEINLINE bool CanEnterNewTile()
00211 {
00212 if (IsRoadTT() && IsStandardRoadStopTile(m_new_tile)) {
00213
00214 DiagDirection exitdir = GetRoadStopDir(m_new_tile);
00215 if (ReverseDiagDir(exitdir) != m_exitdir) {
00216 m_err = EC_NO_WAY;
00217 return false;
00218 }
00219 }
00220
00221
00222 DiagDirection single_tram = GetSingleTramBit(m_new_tile);
00223 if (single_tram != INVALID_DIAGDIR && single_tram != ReverseDiagDir(m_exitdir)) {
00224 m_err = EC_NO_WAY;
00225 return false;
00226 }
00227
00228
00229 if (IsRoadTT() && IsTileDepotType(m_new_tile, TT())) {
00230 DiagDirection exitdir = GetRoadDepotDirection(m_new_tile);
00231 if (ReverseDiagDir(exitdir) != m_exitdir) {
00232 m_err = EC_NO_WAY;
00233 return false;
00234 }
00235
00236 if (GetTileOwner(m_new_tile) != m_veh->owner) {
00237 m_err = EC_OWNER;
00238 return false;
00239 }
00240 }
00241 if (IsRailTT() && IsTileDepotType(m_new_tile, TT())) {
00242 DiagDirection exitdir = GetRailDepotDirection(m_new_tile);
00243 if (ReverseDiagDir(exitdir) != m_exitdir) {
00244 m_err = EC_NO_WAY;
00245 return false;
00246 }
00247 }
00248
00249
00250 if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh->owner) {
00251
00252 m_err = EC_NO_WAY;
00253 return false;
00254 }
00255
00256
00257 if (IsRailTT()) {
00258 RailType rail_type = GetTileRailType(m_new_tile);
00259 if (!HasBit(m_veh->u.rail.compatible_railtypes, rail_type)) {
00260
00261 m_err = EC_RAIL_TYPE;
00262 return false;
00263 }
00264 }
00265
00266
00267 if (!IsWaterTT() && IsTileType(m_new_tile, MP_TUNNELBRIDGE)) {
00268 if (IsTunnel(m_new_tile)) {
00269 if (!m_is_tunnel) {
00270 DiagDirection tunnel_enterdir = GetTunnelBridgeDirection(m_new_tile);
00271 if (tunnel_enterdir != m_exitdir) {
00272 m_err = EC_NO_WAY;
00273 return false;
00274 }
00275 }
00276 } else {
00277 if (!m_is_bridge) {
00278 DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
00279 if (ramp_enderdir != m_exitdir) {
00280 m_err = EC_NO_WAY;
00281 return false;
00282 }
00283 }
00284 }
00285 }
00286
00287
00288 if (IsRailTT() && m_is_station) {
00289
00290
00291 uint length = GetStationByTile(m_new_tile)->GetPlatformLength(m_new_tile, TrackdirToExitdir(m_old_td));
00292
00293 m_tiles_skipped = length - 1;
00294
00295 TileIndexDiff diff = TileOffsByDiagDir(m_exitdir);
00296 diff *= m_tiles_skipped;
00297 m_new_tile = TILE_ADD(m_new_tile, diff);
00298 return true;
00299 }
00300
00301 return true;
00302 }
00303
00305 FORCEINLINE bool ForcedReverse()
00306 {
00307
00308 if (!IsWaterTT() && IsTileDepotType(m_old_tile, TT())) {
00309 DiagDirection exitdir = IsRailTT() ? GetRailDepotDirection(m_old_tile) : GetRoadDepotDirection(m_old_tile);
00310 if (exitdir != m_exitdir) {
00311
00312 m_new_tile = m_old_tile;
00313 m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td));
00314 m_exitdir = exitdir;
00315 m_tiles_skipped = 0;
00316 m_is_tunnel = m_is_bridge = m_is_station = false;
00317 return true;
00318 }
00319 }
00320
00321
00322 if (GetSingleTramBit(m_old_tile) == ReverseDiagDir(m_exitdir)) {
00323
00324 m_new_tile = m_old_tile;
00325 m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td));
00326 m_exitdir = ReverseDiagDir(m_exitdir);
00327 m_tiles_skipped = 0;
00328 m_is_tunnel = m_is_bridge = m_is_station = false;
00329 return true;
00330 }
00331
00332 return false;
00333 }
00334
00336 FORCEINLINE bool TryReverse()
00337 {
00338 if (IsRoadTT() && !IsTram()) {
00339
00340 m_exitdir = ReverseDiagDir(m_exitdir);
00341
00342 m_new_tile = m_old_tile;
00343
00344 QueryNewTileTrackStatus();
00345 m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir);
00346 if (m_new_td_bits != TRACKDIR_BIT_NONE) {
00347
00348 return true;
00349 }
00350 }
00351 m_err = EC_NO_WAY;
00352 return false;
00353 }
00354
00355 public:
00357 int GetSpeedLimit(int *pmin_speed = NULL) const
00358 {
00359 int min_speed = 0;
00360 int max_speed = INT_MAX;
00361
00362
00363 if (!IsWaterTT() && IsBridgeTile(m_old_tile)) {
00364 int spd = GetBridgeSpec(GetBridgeType(m_old_tile))->speed;
00365 if (IsRoadTT()) spd *= 2;
00366 if (max_speed > spd) max_speed = spd;
00367 }
00368
00369
00370 if (pmin_speed) *pmin_speed = min_speed;
00371 return max_speed;
00372 }
00373 };
00374
00375 typedef CFollowTrackT<TRANSPORT_WATER, true > CFollowTrackWater;
00376 typedef CFollowTrackT<TRANSPORT_ROAD , true > CFollowTrackRoad;
00377 typedef CFollowTrackT<TRANSPORT_RAIL , true > CFollowTrackRail;
00378
00379 typedef CFollowTrackT<TRANSPORT_WATER, false> CFollowTrackWaterNo90;
00380 typedef CFollowTrackT<TRANSPORT_ROAD , false> CFollowTrackRoadNo90;
00381 typedef CFollowTrackT<TRANSPORT_RAIL , false> CFollowTrackRailNo90;
00382
00383 #endif