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