00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "functions.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) break;
00195
00196
00197 Trackdir new_trackdir = FindFirstTrackdir(reserved);
00198
00199
00200
00201 if (!ignore_oneway && HasOnewaySignalBlockingTrackdir(ft.m_new_tile, new_trackdir)) break;
00202
00203 tile = ft.m_new_tile;
00204 trackdir = new_trackdir;
00205
00206 if (first_loop) {
00207
00208
00209
00210
00211 start_tile = tile;
00212 start_trackdir = trackdir;
00213 first_loop = false;
00214 } else {
00215
00216 if (tile == start_tile && trackdir == start_trackdir) break;
00217 }
00218
00219 if (IsRailDepotTile(tile)) break;
00220
00221 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
00222 }
00223
00224 return PBSTileInfo(tile, trackdir, false);
00225 }
00226
00230 struct FindTrainOnTrackInfo {
00231 PBSTileInfo res;
00232 Train *best;
00233
00235 FindTrainOnTrackInfo() : best(NULL) {}
00236 };
00237
00239 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
00240 {
00241 FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
00242
00243 if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
00244
00245 Train *t = Train::From(v);
00246 if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
00247 t = t->First();
00248
00249
00250 if (info->best == NULL || t->index < info->best->index) info->best = t;
00251 return t;
00252 }
00253
00254 return NULL;
00255 }
00256
00264 PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
00265 {
00266 assert(v->type == VEH_TRAIN);
00267
00268 TileIndex tile = v->tile;
00269 Trackdir trackdir = v->GetVehicleTrackdir();
00270
00271 if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false);
00272
00273 FindTrainOnTrackInfo ftoti;
00274 ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir);
00275 ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
00276 if (train_on_res != NULL) {
00277 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00278 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00279 if (*train_on_res == NULL && IsRailStationTile(ftoti.res.tile)) {
00280
00281
00282
00283
00284 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00285 for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == NULL && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00286 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00287 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00288 }
00289 }
00290 if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00291
00292 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00293 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00294 }
00295 }
00296 return ftoti.res;
00297 }
00298
00306 Train *GetTrainForReservation(TileIndex tile, Track track)
00307 {
00308 assert(HasReservedTracks(tile, TrackToTrackBits(track)));
00309 Trackdir trackdir = TrackToTrackdir(track);
00310
00311 RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
00312
00313
00314
00315
00316 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
00317
00318
00319 if (HasOnewaySignalBlockingTrackdir(tile, ReverseTrackdir(trackdir)) && !HasPbsSignalOnTrackdir(tile, trackdir)) continue;
00320
00321 FindTrainOnTrackInfo ftoti;
00322 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
00323
00324 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00325 if (ftoti.best != NULL) return ftoti.best;
00326
00327
00328 if (IsRailStationTile(ftoti.res.tile)) {
00329 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00330 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00331 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00332 if (ftoti.best != NULL) return ftoti.best;
00333 }
00334 }
00335
00336
00337 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00338 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00339 if (ftoti.best != NULL) return ftoti.best;
00340 }
00341 }
00342
00343 return NULL;
00344 }
00345
00356 bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
00357 {
00358 if (IsRailDepotTile(tile)) return true;
00359
00360 if (IsTileType(tile, MP_RAILWAY)) {
00361
00362 if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
00363 }
00364
00365
00366 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00367
00368
00369 if (!ft.Follow(tile, trackdir)) {
00370
00371 if (include_line_end) return true;
00372 }
00373
00374
00375 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00376 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00377 if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
00378
00379 if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
00380 Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
00381
00382 if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true;
00383
00384 if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
00385 GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
00386 return include_line_end;
00387 }
00388 }
00389
00390 return false;
00391 }
00392
00402 bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
00403 {
00404 Track track = TrackdirToTrack(trackdir);
00405 TrackBits reserved = GetReservedTrackbits(tile);
00406
00407
00408 if (TrackOverlapsTracks(reserved, track)) return false;
00409
00410
00411 if (IsRailDepotTile(tile)) return true;
00412 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00413
00414
00415 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00416
00417 if (!ft.Follow(tile, trackdir)) return true;
00418
00419
00420 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00421 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00422
00423 return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
00424 }