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 UpdateLevelCrossing(tile, false);
00103 return true;
00104 }
00105 break;
00106
00107 case MP_STATION:
00108 if (HasStationRail(tile) && !HasStationReservation(tile)) {
00109 SetRailStationReservation(tile, true);
00110 MarkTileDirtyByTile(tile);
00111 return true;
00112 }
00113 break;
00114
00115 case MP_TUNNELBRIDGE:
00116 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
00117 SetTunnelBridgeReservation(tile, true);
00118 return true;
00119 }
00120 break;
00121
00122 default:
00123 break;
00124 }
00125 return false;
00126 }
00127
00133 void UnreserveRailTrack(TileIndex tile, Track t)
00134 {
00135 assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
00136
00137 if (_settings_client.gui.show_track_reservation) {
00138 MarkTileDirtyByTile(tile);
00139 }
00140
00141 switch (GetTileType(tile)) {
00142 case MP_RAILWAY:
00143 if (IsRailDepot(tile)) {
00144 SetDepotReservation(tile, false);
00145 MarkTileDirtyByTile(tile);
00146 break;
00147 }
00148 if (IsPlainRail(tile)) UnreserveTrack(tile, t);
00149 break;
00150
00151 case MP_ROAD:
00152 if (IsLevelCrossing(tile)) {
00153 SetCrossingReservation(tile, false);
00154 UpdateLevelCrossing(tile);
00155 }
00156 break;
00157
00158 case MP_STATION:
00159 if (HasStationRail(tile)) {
00160 SetRailStationReservation(tile, false);
00161 MarkTileDirtyByTile(tile);
00162 }
00163 break;
00164
00165 case MP_TUNNELBRIDGE:
00166 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false);
00167 break;
00168
00169 default:
00170 break;
00171 }
00172 }
00173
00174
00176 static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false)
00177 {
00178 TileIndex start_tile = tile;
00179 Trackdir start_trackdir = trackdir;
00180 bool first_loop = true;
00181
00182
00183
00184
00185 if (!HasReservedTracks(tile, TrackToTrackBits(TrackdirToTrack(trackdir)))) return PBSTileInfo(tile, trackdir, false);
00186
00187
00188 CFollowTrackRail ft(o, rts);
00189 while (ft.Follow(tile, trackdir)) {
00190 TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile));
00191
00192
00193 if (reserved == TRACKDIR_BIT_NONE) break;
00194
00195
00196 Trackdir new_trackdir = FindFirstTrackdir(reserved);
00197
00198
00199
00200 if (!ignore_oneway && HasOnewaySignalBlockingTrackdir(ft.m_new_tile, new_trackdir)) break;
00201
00202 tile = ft.m_new_tile;
00203 trackdir = new_trackdir;
00204
00205 if (first_loop) {
00206
00207
00208
00209
00210 start_tile = tile;
00211 start_trackdir = trackdir;
00212 first_loop = false;
00213 } else {
00214
00215 if (tile == start_tile && trackdir == start_trackdir) break;
00216 }
00217
00218 if (IsRailDepotTile(tile)) break;
00219
00220 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir))) && !IsSpeedSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
00221 }
00222
00223 return PBSTileInfo(tile, trackdir, false);
00224 }
00225
00229 struct FindTrainOnTrackInfo {
00230 PBSTileInfo res;
00231 Train *best;
00232
00234 FindTrainOnTrackInfo() : best(NULL) {}
00235 };
00236
00238 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
00239 {
00240 FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
00241
00242 if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
00243
00244 Train *t = Train::From(v);
00245 if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
00246 t = t->First();
00247
00248
00249 if (info->best == NULL || t->index < info->best->index) info->best = t;
00250 return t;
00251 }
00252
00253 return NULL;
00254 }
00255
00263 PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
00264 {
00265 assert(v->type == VEH_TRAIN);
00266
00267 TileIndex tile = v->tile;
00268 Trackdir trackdir = v->GetVehicleTrackdir();
00269
00270 if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false);
00271
00272 FindTrainOnTrackInfo ftoti;
00273 ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir);
00274 ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
00275 if (train_on_res != NULL) {
00276 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00277 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00278 if (*train_on_res == NULL && IsRailStationTile(ftoti.res.tile)) {
00279
00280
00281
00282
00283 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00284 for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == NULL && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00285 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00286 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00287 }
00288 }
00289 if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00290
00291 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00292 if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
00293 }
00294 }
00295 return ftoti.res;
00296 }
00297
00305 Train *GetTrainForReservation(TileIndex tile, Track track)
00306 {
00307 assert(HasReservedTracks(tile, TrackToTrackBits(track)));
00308 Trackdir trackdir = TrackToTrackdir(track);
00309
00310 RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
00311
00312
00313
00314
00315 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
00316
00317
00318 if (HasOnewaySignalBlockingTrackdir(tile, ReverseTrackdir(trackdir)) && !HasPbsSignalOnTrackdir(tile, trackdir)) continue;
00319
00320 FindTrainOnTrackInfo ftoti;
00321 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
00322
00323 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00324 if (ftoti.best != NULL) return ftoti.best;
00325
00326
00327 if (IsRailStationTile(ftoti.res.tile)) {
00328 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00329 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00330 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00331 if (ftoti.best != NULL) return ftoti.best;
00332 }
00333 }
00334
00335
00336 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00337 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00338 if (ftoti.best != NULL) return ftoti.best;
00339 }
00340 }
00341
00342 return NULL;
00343 }
00344
00355 bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
00356 {
00357 if (IsRailDepotTile(tile)) return true;
00358
00359 if (IsTileType(tile, MP_RAILWAY)) {
00360
00361 if (HasSignalOnTrackdir(tile, trackdir) &&
00362 !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir))) &&
00363 !IsSpeedSignal(GetSignalType(tile, TrackdirToTrack(trackdir))))
00364 return true;
00365 }
00366
00367
00368 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00369
00370
00371 if (!ft.Follow(tile, trackdir)) {
00372
00373 if (include_line_end) return true;
00374 }
00375
00376
00377 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00378 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00379 if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
00380
00381 if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
00382 Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
00383
00384 if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true;
00385
00386 if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) &&
00387 GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) {
00388 return include_line_end;
00389 }
00390 }
00391
00392 return false;
00393 }
00394
00404 bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
00405 {
00406 Track track = TrackdirToTrack(trackdir);
00407 TrackBits reserved = GetReservedTrackbits(tile);
00408
00409
00410 if (TrackOverlapsTracks(reserved, track)) return false;
00411
00412
00413 if (IsRailDepotTile(tile)) return true;
00414 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00415
00416
00417 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00418
00419 if (!ft.Follow(tile, trackdir)) return true;
00420
00421
00422 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00423 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00424
00425 return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
00426 }