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, bool *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) *train_on_res = HasVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00278 return ftoti.res;
00279 }
00280
00288 Train *GetTrainForReservation(TileIndex tile, Track track)
00289 {
00290 assert(HasReservedTracks(tile, TrackToTrackBits(track)));
00291 Trackdir trackdir = TrackToTrackdir(track);
00292
00293 RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
00294
00295
00296
00297
00298 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
00299 FindTrainOnTrackInfo ftoti;
00300 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
00301
00302 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00303 if (ftoti.best != NULL) return ftoti.best;
00304
00305
00306 if (IsRailStationTile(ftoti.res.tile)) {
00307 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00308 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00309 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00310 if (ftoti.best != NULL) return ftoti.best;
00311 }
00312 }
00313
00314
00315 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00316 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00317 if (ftoti.best != NULL) return ftoti.best;
00318 }
00319 }
00320
00321 return NULL;
00322 }
00323
00334 bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
00335 {
00336 if (IsRailDepotTile(tile)) return true;
00337
00338 if (IsTileType(tile, MP_RAILWAY)) {
00339
00340 if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
00341 }
00342
00343
00344 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00345
00346
00347 if (!ft.Follow(tile, trackdir)) {
00348
00349 if (include_line_end) return true;
00350 }
00351
00352
00353 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00354 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00355 if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
00356
00357 if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
00358
00359 if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) return true;
00360 }
00361
00362 return false;
00363 }
00364
00374 bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
00375 {
00376 Track track = TrackdirToTrack(trackdir);
00377 TrackBits reserved = GetReservedTrackbits(tile);
00378
00379
00380 if (TrackOverlapsTracks(reserved, track)) return false;
00381
00382
00383 if (IsRailDepotTile(tile)) return true;
00384 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00385
00386
00387 CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
00388
00389 if (!ft.Follow(tile, trackdir)) return true;
00390
00391
00392 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00393 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00394
00395 return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
00396 }