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