00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "viewport_func.h"
00014 #include "vehicle_func.h"
00015 #include "pathfinder/follow_track.hpp"
00016
00023 TrackBits GetReservedTrackbits(TileIndex t)
00024 {
00025 switch (GetTileType(t)) {
00026 case MP_RAILWAY:
00027 if (IsRailDepot(t)) return GetDepotReservationTrackBits(t);
00028 if (IsPlainRail(t)) return GetRailReservationTrackBits(t);
00029 break;
00030
00031 case MP_ROAD:
00032 if (IsLevelCrossing(t)) return GetCrossingReservationTrackBits(t);
00033 break;
00034
00035 case MP_STATION:
00036 if (HasStationRail(t)) return GetStationReservationTrackBits(t);
00037 break;
00038
00039 case MP_TUNNELBRIDGE:
00040 if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) return GetTunnelBridgeReservationTrackBits(t);
00041 break;
00042
00043 default:
00044 break;
00045 }
00046 return TRACK_BIT_NONE;
00047 }
00048
00056 void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
00057 {
00058 TileIndex tile = start;
00059 TileIndexDiff diff = TileOffsByDiagDir(dir);
00060
00061 assert(IsRailStationTile(start));
00062 assert(GetRailStationAxis(start) == DiagDirToAxis(dir));
00063
00064 do {
00065 SetRailStationReservation(tile, b);
00066 MarkTileDirtyByTile(tile);
00067 tile = TILE_ADD(tile, diff);
00068 } while (IsCompatibleTrainStationTile(tile, start));
00069 }
00070
00078 bool TryReserveRailTrack(TileIndex tile, Track t)
00079 {
00080 assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
00081
00082 if (_settings_client.gui.show_track_reservation) {
00083
00084 MarkTileDirtyByTile(tile);
00085 }
00086
00087 switch (GetTileType(tile)) {
00088 case MP_RAILWAY:
00089 if (IsPlainRail(tile)) return TryReserveTrack(tile, t);
00090 if (IsRailDepot(tile)) {
00091 if (!HasDepotReservation(tile)) {
00092 SetDepotReservation(tile, true);
00093 MarkTileDirtyByTile(tile);
00094 return true;
00095 }
00096 }
00097 break;
00098
00099 case MP_ROAD:
00100 if (IsLevelCrossing(tile) && !HasCrossingReservation(tile)) {
00101 SetCrossingReservation(tile, true);
00102 BarCrossing(tile);
00103 MarkTileDirtyByTile(tile);
00104 return true;
00105 }
00106 break;
00107
00108 case MP_STATION:
00109 if (HasStationRail(tile) && !HasStationReservation(tile)) {
00110 SetRailStationReservation(tile, true);
00111 MarkTileDirtyByTile(tile);
00112 return true;
00113 }
00114 break;
00115
00116 case MP_TUNNELBRIDGE:
00117 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
00118 SetTunnelBridgeReservation(tile, true);
00119 return true;
00120 }
00121 break;
00122
00123 default:
00124 break;
00125 }
00126 return false;
00127 }
00128
00134 void UnreserveRailTrack(TileIndex tile, Track t)
00135 {
00136 assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
00137
00138 if (_settings_client.gui.show_track_reservation) {
00139 MarkTileDirtyByTile(tile);
00140 }
00141
00142 switch (GetTileType(tile)) {
00143 case MP_RAILWAY:
00144 if (IsRailDepot(tile)) {
00145 SetDepotReservation(tile, false);
00146 MarkTileDirtyByTile(tile);
00147 break;
00148 }
00149 if (IsPlainRail(tile)) UnreserveTrack(tile, t);
00150 break;
00151
00152 case MP_ROAD:
00153 if (IsLevelCrossing(tile)) {
00154 SetCrossingReservation(tile, false);
00155 UpdateLevelCrossing(tile);
00156 }
00157 break;
00158
00159 case MP_STATION:
00160 if (HasStationRail(tile)) {
00161 SetRailStationReservation(tile, false);
00162 MarkTileDirtyByTile(tile);
00163 }
00164 break;
00165
00166 case MP_TUNNELBRIDGE:
00167 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false);
00168 break;
00169
00170 default:
00171 break;
00172 }
00173 }
00174
00175
00177 static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false)
00178 {
00179 TileIndex start_tile = tile;
00180 Trackdir start_trackdir = trackdir;
00181 bool first_loop = true;
00182
00183
00184
00185
00186 if (!HasReservedTracks(tile, TrackToTrackBits(TrackdirToTrack(trackdir)))) return PBSTileInfo(tile, trackdir, false);
00187
00188
00189 CFollowTrackRail ft(o, rts);
00190 while (ft.Follow(tile, trackdir)) {
00191 TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile));
00192
00193
00194 if (reserved == TRACKDIR_BIT_NONE) {
00195 if (ft.m_is_station) {
00196
00197 TileIndexDiff diff = TileOffsByDiagDir(ft.m_exitdir);
00198 while (ft.m_tiles_skipped-- > 0) {
00199 ft.m_new_tile -= diff;
00200 if (HasStationReservation(ft.m_new_tile)) {
00201 tile = ft.m_new_tile;
00202 trackdir = DiagDirToDiagTrackdir(ft.m_exitdir);
00203 break;
00204 }
00205 }
00206 }
00207 break;
00208 }
00209
00210
00211 Trackdir new_trackdir = FindFirstTrackdir(reserved);
00212
00213
00214
00215 if (!ignore_oneway && HasOnewaySignalBlockingTrackdir(ft.m_new_tile, new_trackdir)) break;
00216
00217 tile = ft.m_new_tile;
00218 trackdir = new_trackdir;
00219
00220 if (first_loop) {
00221
00222
00223
00224
00225 start_tile = tile;
00226 start_trackdir = trackdir;
00227 first_loop = false;
00228 } else {
00229
00230 if (tile == start_tile && trackdir == start_trackdir) break;
00231 }
00232
00233 if (IsRailDepotTile(tile)) break;
00234
00235 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
00236 }
00237
00238 return PBSTileInfo(tile, trackdir, false);
00239 }
00240
00244 struct FindTrainOnTrackInfo {
00245 PBSTileInfo res;
00246 Train *best;
00247
00249 FindTrainOnTrackInfo() : best(NULL) {}
00250 };
00251
00253 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
00254 {
00255 FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
00256
00257 if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
00258
00259 Train *t = Train::From(v);
00260 if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
00261 t = t->First();
00262
00263
00264 if (info->best == NULL || t->index < info->best->index) info->best = t;
00265 return t;
00266 }
00267
00268 return NULL;
00269 }
00270
00278 PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
00279 {
00280 assert(v->type == VEH_TRAIN);
00281
00282 TileIndex tile = v->tile;
00283 Trackdir trackdir = v->GetVehicleTrackdir();
00284
00285 if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false);
00286
00287 FindTrainOnTrackInfo ftoti;
00288 ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir);
00289 ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
00290 if (train_on_res != NULL) {
00291 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00292 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00293 if (*train_on_res == NULL && IsRailStationTile(ftoti.res.tile)) {
00294
00295
00296
00297
00298 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00299 for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == NULL && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00300 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00301 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00302 }
00303 }
00304 if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00305
00306 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00307 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00308 }
00309 }
00310 return ftoti.res;
00311 }
00312
00320 Train *GetTrainForReservation(TileIndex tile, Track track)
00321 {
00322 assert(HasReservedTracks(tile, TrackToTrackBits(track)));
00323 Trackdir trackdir = TrackToTrackdir(track);
00324
00325 RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
00326
00327
00328
00329
00330 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
00331
00332
00333 if (HasOnewaySignalBlockingTrackdir(tile, ReverseTrackdir(trackdir)) && !HasPbsSignalOnTrackdir(tile, trackdir)) continue;
00334
00335 FindTrainOnTrackInfo ftoti;
00336 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
00337
00338 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00339 if (ftoti.best != NULL) return ftoti.best;
00340
00341
00342 if (IsRailStationTile(ftoti.res.tile)) {
00343 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00344 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00345 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00346 if (ftoti.best != NULL) return ftoti.best;
00347 }
00348 }
00349
00350
00351 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00352 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00353 if (ftoti.best != NULL) return ftoti.best;
00354 }
00355 }
00356
00357 return NULL;
00358 }
00359
00370 bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
00371 {
00372 if (IsRailDepotTile(tile)) return true;
00373
00374 if (IsTileType(tile, MP_RAILWAY)) {
00375
00376 if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
00377 }
00378
00379
00380 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00381
00382
00383 if (!ft.Follow(tile, trackdir)) {
00384
00385 if (include_line_end) return true;
00386 }
00387
00388
00389 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00390 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00391 if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
00392
00393 if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
00394 Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
00395
00396 if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true;
00397
00398 if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
00399 GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
00400 return include_line_end;
00401 }
00402 }
00403
00404 return false;
00405 }
00406
00416 bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
00417 {
00418 Track track = TrackdirToTrack(trackdir);
00419 TrackBits reserved = GetReservedTrackbits(tile);
00420
00421
00422 if (TrackOverlapsTracks(reserved, track)) return false;
00423
00424
00425 if (IsRailDepotTile(tile)) return true;
00426 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00427
00428
00429 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00430
00431 if (!ft.Follow(tile, trackdir)) return true;
00432
00433
00434 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00435 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00436
00437 return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
00438 }