pbs.cpp

Go to the documentation of this file.
00001 /* $Id: pbs.cpp 15299 2009-01-31 20:16:06Z smatz $ */
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     /* show the reserved rail if needed */
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); // some GRFs change their appearance when tile is reserved
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); // crossing barred, make tile dirty
00097         return true;
00098       }
00099       break;
00100 
00101     case MP_STATION:
00102       if (IsRailwayStation(tile) && !GetRailwayStationReservation(tile)) {
00103         SetRailwayStationReservation(tile, true);
00104         MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track
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   /* Start track not reserved? This can happen if two trains
00177    * are on the same tile. The reservation on the next tile
00178    * is not ours in this case, so exit. */
00179   if (!HasReservedTracks(tile, TrackToTrackBits(TrackdirToTrack(trackdir)))) return PBSTileInfo(tile, trackdir, false);
00180 
00181   /* Do not disallow 90 deg turns as the setting might have changed between reserving and now. */
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     /* No reservation --> path end found */
00187     if (reserved == TRACKDIR_BIT_NONE) break;
00188 
00189     /* Can't have more than one reserved trackdir */
00190     Trackdir new_trackdir = FindFirstTrackdir(reserved);
00191 
00192     /* One-way signal against us. The reservation can't be ours as it is not
00193      * a safe position from our direction and we can never pass the signal. */
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       /* Update the start tile after we followed the track the first
00201        * time. This is neccessary because the track follower can skip
00202        * tiles (in stations for example) which means that we might
00203        * never visit our original starting tile again. */
00204       start_tile = tile;
00205       start_trackdir = trackdir;
00206       first_loop = false;
00207     } else {
00208       /* Loop encountered? */
00209       if (tile == start_tile && trackdir == start_trackdir) break;
00210     }
00211     /* Depot tile? Can't continue. */
00212     if (IsRailDepotTile(tile)) break;
00213     /* Non-pbs signal? Reservation can't continue. */
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     /* ALWAYS return the lowest ID (anti-desync!) */
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   /* Follow the path from tile to both ends, one of the end tiles should
00285    * have a train on it. We need FollowReservation to ignore one-way signals
00286    * here, as one of the two search directions will be the "wrong" way. */
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     /* Special case for stations: check the whole platform for a vehicle. */
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     /* Special case for bridges/tunnels: check the other end as well. */
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     /* For non-pbs signals, stop on the signal tile. */
00329     if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
00330   }
00331 
00332   /* Check next tile. For perfomance reasons, we check for 90 degree turns ourself. */
00333   CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
00334 
00335   /* End of track? */
00336   if (!ft.Follow(tile, trackdir)) {
00337     /* Last tile of a terminus station is a safe position. */
00338     if (include_line_end) return true;
00339   }
00340 
00341   /* Check for reachable tracks. */
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     /* PBS signal on next trackdir? Safe position. */
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   /* Tile reserved? Can never be a free waiting position. */
00369   if (TrackOverlapsTracks(reserved, track)) return false;
00370 
00371   /* Not reserved and depot or not a pbs signal -> free. */
00372   if (IsRailDepotTile(tile)) return true;
00373   if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
00374 
00375   /* Check the next tile, if it's a PBS signal, it has to be free as well. */
00376   CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
00377 
00378   if (!ft.Follow(tile, trackdir)) return true;
00379 
00380   /* Check for reachable tracks. */
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 }

Generated on Tue Jul 21 18:48:25 2009 for OpenTTD by  doxygen 1.5.6