00001
00002
00004 #include "stdafx.h"
00005 #include "pbs.h"
00006 #include "functions.h"
00007 #include "vehicle_func.h"
00008 #include "yapf/follow_track.hpp"
00009
00016 TrackBits GetReservedTrackbits(TileIndex t)
00017 {
00018 switch (GetTileType(t)) {
00019 case MP_RAILWAY:
00020 if (IsRailWaypoint(t) || IsRailDepot(t)) return GetRailWaypointReservation(t);
00021 if (IsPlainRailTile(t)) return GetTrackReservation(t);
00022 break;
00023
00024 case MP_ROAD:
00025 if (IsLevelCrossing(t)) return GetRailCrossingReservation(t);
00026 break;
00027
00028 case MP_STATION:
00029 if (IsRailwayStation(t)) return GetRailStationReservation(t);
00030 break;
00031
00032 case MP_TUNNELBRIDGE:
00033 if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) return GetRailTunnelBridgeReservation(t);
00034 break;
00035
00036 default:
00037 break;
00038 }
00039 return TRACK_BIT_NONE;
00040 }
00041
00049 void SetRailwayStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
00050 {
00051 TileIndex tile = start;
00052 TileIndexDiff diff = TileOffsByDiagDir(dir);
00053
00054 assert(IsRailwayStationTile(start));
00055 assert(GetRailStationAxis(start) == DiagDirToAxis(dir));
00056
00057 do {
00058 SetRailwayStationReservation(tile, b);
00059 MarkTileDirtyByTile(tile);
00060 tile = TILE_ADD(tile, diff);
00061 } while (IsCompatibleTrainStationTile(tile, start));
00062 }
00063
00071 bool TryReserveRailTrack(TileIndex tile, Track t)
00072 {
00073 assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
00074
00075 if (_settings_client.gui.show_track_reservation) {
00076
00077 MarkTileDirtyByTile(tile);
00078 }
00079
00080 switch (GetTileType(tile)) {
00081 case MP_RAILWAY:
00082 if (IsPlainRailTile(tile)) return TryReserveTrack(tile, t);
00083 if (IsRailWaypoint(tile) || IsRailDepot(tile)) {
00084 if (!GetDepotWaypointReservation(tile)) {
00085 SetDepotWaypointReservation(tile, true);
00086 MarkTileDirtyByTile(tile);
00087 return true;
00088 }
00089 }
00090 break;
00091
00092 case MP_ROAD:
00093 if (IsLevelCrossing(tile) && !GetCrossingReservation(tile)) {
00094 SetCrossingReservation(tile, true);
00095 BarCrossing(tile);
00096 MarkTileDirtyByTile(tile);
00097 return true;
00098 }
00099 break;
00100
00101 case MP_STATION:
00102 if (IsRailwayStation(tile) && !GetRailwayStationReservation(tile)) {
00103 SetRailwayStationReservation(tile, true);
00104 MarkTileDirtyByTile(tile);
00105 return true;
00106 }
00107 break;
00108
00109 case MP_TUNNELBRIDGE:
00110 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetRailTunnelBridgeReservation(tile)) {
00111 SetTunnelBridgeReservation(tile, true);
00112 return true;
00113 }
00114 break;
00115
00116 default:
00117 break;
00118 }
00119 return false;
00120 }
00121
00127 void UnreserveRailTrack(TileIndex tile, Track t)
00128 {
00129 assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
00130
00131 if (_settings_client.gui.show_track_reservation) {
00132 MarkTileDirtyByTile(tile);
00133 }
00134
00135 switch (GetTileType(tile)) {
00136 case MP_RAILWAY:
00137 if (IsRailWaypoint(tile) || IsRailDepot(tile)) {
00138 SetDepotWaypointReservation(tile, false);
00139 MarkTileDirtyByTile(tile);
00140 break;
00141 }
00142 if (IsPlainRailTile(tile)) UnreserveTrack(tile, t);
00143 break;
00144
00145 case MP_ROAD:
00146 if (IsLevelCrossing(tile)) {
00147 SetCrossingReservation(tile, false);
00148 UpdateLevelCrossing(tile);
00149 }
00150 break;
00151
00152 case MP_STATION:
00153 if (IsRailwayStation(tile)) {
00154 SetRailwayStationReservation(tile, false);
00155 MarkTileDirtyByTile(tile);
00156 }
00157 break;
00158
00159 case MP_TUNNELBRIDGE:
00160 if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false);
00161 break;
00162
00163 default:
00164 break;
00165 }
00166 }
00167
00168
00170 static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false)
00171 {
00172 TileIndex start_tile = tile;
00173 Trackdir start_trackdir = trackdir;
00174 bool first_loop = true;
00175
00176
00177
00178
00179 if (!HasReservedTracks(tile, TrackToTrackBits(TrackdirToTrack(trackdir)))) return PBSTileInfo(tile, trackdir, false);
00180
00181
00182 CFollowTrackRail ft(o, rts);
00183 while (ft.Follow(tile, trackdir)) {
00184 TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile));
00185
00186
00187 if (reserved == TRACKDIR_BIT_NONE) break;
00188
00189
00190 Trackdir new_trackdir = FindFirstTrackdir(reserved);
00191
00192
00193
00194 if (!ignore_oneway && HasOnewaySignalBlockingTrackdir(ft.m_new_tile, new_trackdir)) break;
00195
00196 tile = ft.m_new_tile;
00197 trackdir = new_trackdir;
00198
00199 if (first_loop) {
00200
00201
00202
00203
00204 start_tile = tile;
00205 start_trackdir = trackdir;
00206 first_loop = false;
00207 } else {
00208
00209 if (tile == start_tile && trackdir == start_trackdir) break;
00210 }
00211
00212 if (IsRailDepotTile(tile)) break;
00213
00214 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
00215 }
00216
00217 return PBSTileInfo(tile, trackdir, false);
00218 }
00219
00223 struct FindTrainOnTrackInfo {
00224 PBSTileInfo res;
00225 Vehicle *best;
00226
00228 FindTrainOnTrackInfo() : best(NULL) {}
00229 };
00230
00232 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
00233 {
00234 FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
00235
00236 if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info->res.trackdir))) {
00237 v = v->First();
00238
00239
00240 if (info->best == NULL || v->index < info->best->index) info->best = v;
00241 return v;
00242 }
00243
00244 return NULL;
00245 }
00246
00254 PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res)
00255 {
00256 assert(v->type == VEH_TRAIN);
00257
00258 TileIndex tile = v->tile;
00259 Trackdir trackdir = GetVehicleTrackdir(v);
00260
00261 if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false);
00262
00263 FindTrainOnTrackInfo ftoti;
00264 ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
00265 ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
00266 if (train_on_res != NULL) *train_on_res = HasVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00267 return ftoti.res;
00268 }
00269
00277 Vehicle *GetTrainForReservation(TileIndex tile, Track track)
00278 {
00279 assert(HasReservedTracks(tile, TrackToTrackBits(track)));
00280 Trackdir trackdir = TrackToTrackdir(track);
00281
00282 RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
00283
00284
00285
00286
00287 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
00288 FindTrainOnTrackInfo ftoti;
00289 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
00290
00291 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
00292 if (ftoti.best != NULL) return ftoti.best;
00293
00294
00295 if (IsRailwayStationTile(ftoti.res.tile)) {
00296 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir)));
00297 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) {
00298 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum);
00299 if (ftoti.best != NULL) return ftoti.best;
00300 }
00301 }
00302
00303
00304 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
00305 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
00306 if (ftoti.best != NULL) return ftoti.best;
00307 }
00308 }
00309
00310 return NULL;
00311 }
00312
00323 bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
00324 {
00325 if (IsRailDepotTile(tile)) return true;
00326
00327 if (IsTileType(tile, MP_RAILWAY)) {
00328
00329 if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
00330 }
00331
00332
00333 CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
00334
00335
00336 if (!ft.Follow(tile, trackdir)) {
00337
00338 if (include_line_end) return true;
00339 }
00340
00341
00342 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00343 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00344 if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end;
00345
00346 if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
00347
00348 if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) return true;
00349 }
00350
00351 return false;
00352 }
00353
00363 bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
00364 {
00365 Track track = TrackdirToTrack(trackdir);
00366 TrackBits reserved = GetReservedTrackbits(tile);
00367
00368
00369 if (TrackOverlapsTracks(reserved, track)) return false;
00370
00371
00372 if (IsRailDepotTile(tile)) return true;
00373 if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00374
00375
00376 CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
00377
00378 if (!ft.Follow(tile, trackdir)) return true;
00379
00380
00381 ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir);
00382 if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir);
00383
00384 return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits));
00385 }