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