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