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