summaryrefslogtreecommitdiff
path: root/pbs.c
diff options
context:
space:
mode:
Diffstat (limited to 'pbs.c')
-rw-r--r--pbs.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/pbs.c b/pbs.c
new file mode 100644
index 000000000..fdb47854d
--- /dev/null
+++ b/pbs.c
@@ -0,0 +1,291 @@
+#include "stdafx.h"
+#include "openttd.h"
+#include "pbs.h"
+#include "functions.h"
+#include "debug.h"
+#include "map.h"
+#include "tile.h"
+#include "npf.h"
+#include "pathfind.h"
+#include "depot.h"
+
+/** @file pbs.c Path-Based-Signalling implementation file
+ * @see pbs.h */
+
+/* reserved track encoding:
+ normal railway tracks:
+ map3lo bits 4..6 = 'Track'number of reserved track + 1, if this is zero it means nothing is reserved on this tile
+ map3lo bit 7 = if this is set, then the opposite track ('Track'number^1) is also reserved
+ waypoints/stations:
+ map3lo bit 6 set = track is reserved
+ tunnels/bridges:
+ map3hi bit 0 set = track with 'Track'number 0 is reserved
+ map3hi bit 1 set = track with 'Track'number 1 is reserved
+ level crossings:
+ map5 bit 0 set = the rail track is reserved
+*/
+
+/**
+ * maps an encoded reserved track (from map3lo bits 4..7)
+ * to the tracks that are reserved.
+ * 0xFF are invalid entries and should never be accessed.
+ */
+static const byte encrt_to_reserved[16] = {
+ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x0C, 0x0C, 0x30, 0x30, 0xFF
+};
+
+/**
+ * maps an encoded reserved track (from map3lo bits 4..7)
+ * to the track(dir)s that are unavailable due to reservations.
+ * 0xFFFF are invalid entries and should never be accessed.
+ */
+static const int16 encrt_to_unavail[16] = {
+ 0x0000, 0x3F3F, 0x3F3F, 0x3737, 0x3B3B, 0x1F1F, 0x2F2F, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0x3F3F, 0x3F3F, 0x3F3F, 0x3F3F, 0xFFFF
+};
+
+void PBSReserveTrack(TileIndex tile, Track track) {
+ assert(IsValidTile(tile));
+ assert(track <= 5);
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ if ((_map5[tile] & ~1) == 0xC4) {
+ // waypoint
+ SETBIT(_map3_lo[tile], 6);
+ } else {
+ // normal rail track
+ byte encrt = (_map3_hi[tile] & 0xF0) >> 4; // get current encoded info (see comments at top of file)
+
+ if (encrt == 0) // nothing reserved before
+ encrt = track + 1;
+ else if (encrt == (track^1) + 1) // opposite track reserved before
+ encrt |= 8;
+
+ _map3_hi[tile] &= ~0xF0;
+ _map3_hi[tile] |= encrt << 4;
+ }
+ break;
+ case MP_TUNNELBRIDGE:
+ _map3_hi[tile] |= (1 << track) & 3;
+ break;
+ case MP_STATION:
+ SETBIT(_map3_lo[tile], 6);
+ break;
+ case MP_STREET:
+ // make sure it is a railroad crossing
+ if (!IsLevelCrossing(tile)) return;
+ SETBIT(_map5[tile], 0);
+ break;
+ default:
+ return;
+ };
+ // if debugging, mark tile dirty to show reserved status
+ if (_debug_pbs_level >= 1)
+ MarkTileDirtyByTile(tile);
+}
+
+byte PBSTileReserved(TileIndex tile) {
+ assert(IsValidTile(tile));
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ if ((_map5[tile] & ~1) == 0xC4) {
+ // waypoint
+ // check if its reserved
+ if (!HASBIT(_map3_lo[tile], 6)) return 0;
+ // return the track for the correct direction
+ return HASBIT(_map5[tile], 0) ? 2 : 1;
+ } else {
+ // normal track
+ byte res = encrt_to_reserved[(_map3_hi[tile] & 0xF0) >> 4];
+ assert(res != 0xFF);
+ return res;
+ };
+ case MP_TUNNELBRIDGE:
+ return (_map3_hi[tile] & 3);
+ case MP_STATION:
+ // check if its reserved
+ if (!HASBIT(_map3_lo[tile], 6)) return 0;
+ // return the track for the correct direction
+ return HASBIT(_map5[tile], 0) ? 2 : 1;
+ case MP_STREET:
+ // make sure its a railroad crossing
+ if (!IsLevelCrossing(tile)) return 0;
+ // check if its reserved
+ if (!HASBIT(_map5[tile], 0)) return 0;
+ // return the track for the correct direction
+ return HASBIT(_map5[tile], 3) ? 1 : 2;
+ default:
+ return 0;
+ };
+};
+
+uint16 PBSTileUnavail(TileIndex tile) {
+ assert(IsValidTile(tile));
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ if ((_map5[tile] & ~1) == 0xC4) {
+ // waypoint
+ return HASBIT(_map3_lo[tile], 6) ? TRACKDIR_BIT_MASK : 0;
+ } else {
+ // normal track
+ uint16 res = encrt_to_unavail[(_map3_hi[tile] & 0xF0) >> 4];
+ assert(res != 0xFFFF);
+ return res;
+ };
+ case MP_TUNNELBRIDGE:
+ return (_map3_hi[tile] & 3) | ((_map3_hi[tile] & 3) << 8);
+ case MP_STATION:
+ return HASBIT(_map3_lo[tile], 6) ? TRACKDIR_BIT_MASK : 0;
+ case MP_STREET:
+ // make sure its a railroad crossing
+ if (!IsLevelCrossing(tile)) return 0;
+ // check if its reserved
+ return (HASBIT(_map5[tile], 0)) ? TRACKDIR_BIT_MASK : 0;
+ default:
+ return 0;
+ };
+};
+
+void PBSClearTrack(TileIndex tile, Track track) {
+ assert(IsValidTile(tile));
+ assert(track <= 5);
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ if ((_map5[tile] & ~1) == 0xC4) {
+ // waypoint
+ CLRBIT(_map3_lo[tile], 6);
+ } else {
+ // normal rail track
+ byte encrt = (_map3_hi[tile] & 0xF0) >> 4;
+
+ if (encrt == track + 1)
+ encrt = 0;
+ else if (encrt == track + 1 + 8)
+ encrt = (track^1) + 1;
+ else if (encrt == (track^1) + 1 + 8)
+ encrt &= 7;
+
+ _map3_hi[tile] &= ~0xF0;
+ _map3_hi[tile] |= encrt << 4;
+ }
+ break;
+ case MP_TUNNELBRIDGE:
+ _map3_hi[tile] &= ~((1 << track) & 3);
+ break;
+ case MP_STATION:
+ CLRBIT(_map3_lo[tile], 6);
+ break;
+ case MP_STREET:
+ // make sure it is a railroad crossing
+ if (!IsLevelCrossing(tile)) return;
+ CLRBIT(_map5[tile], 0);
+ break;
+ default:
+ return;
+ };
+ // if debugging, mark tile dirty to show reserved status
+ if (_debug_pbs_level >= 1)
+ MarkTileDirtyByTile(tile);
+};
+
+void PBSClearPath(TileIndex tile, Trackdir trackdir) {
+ uint16 res;
+ FindLengthOfTunnelResult flotr;
+ assert(IsValidTile(tile));
+ assert((trackdir & ~8) <= 5);
+ do {
+ PBSClearTrack(tile, trackdir & 7);
+
+ if (IsTileType(tile, MP_TUNNELBRIDGE) && (_map5[tile] & 0xF0)==0 && (unsigned)(_map5[tile] & 3) == TrackdirToExitdir(trackdir)) {
+ // this is a tunnel
+ flotr = FindLengthOfTunnel(tile, TrackdirToExitdir(trackdir));
+
+ tile = flotr.tile;
+ } else {
+ byte exitdir = TrackdirToExitdir(trackdir);
+ if (IsTileDepotType(tile, TRANSPORT_RAIL) && (exitdir != GetDepotDirection(tile, TRANSPORT_RAIL)))
+ return;
+ tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(exitdir));
+ if (IsTileDepotType(tile, TRANSPORT_RAIL) && (exitdir != ReverseDiagdir(GetDepotDirection(tile, TRANSPORT_RAIL))))
+ return;
+ };
+
+ res = PBSTileReserved(tile);
+ res |= res << 8;
+ res &= TrackdirReachesTrackdirs(trackdir);
+ trackdir = FindFirstBit2x64(res);
+
+ } while (res != 0);
+};
+
+bool PBSIsPbsSignal(TileIndex tile, Trackdir trackdir)
+{
+ assert(IsValidTile(tile));
+ assert(IsValidTrackdir(trackdir));
+
+ if (!_patches.new_pathfinding_all)
+ return false;
+
+ if (!IsTileType(tile, MP_RAILWAY))
+ return false;
+
+ if (GetRailTileType(tile) != RAIL_TYPE_SIGNALS)
+ return false;
+
+ if (!HasSignalOnTrackdir(tile, trackdir))
+ return false;
+
+ if (GetSignalType(tile, TrackdirToTrack(trackdir)) == 4)
+ return true;
+ else
+ return false;
+};
+
+typedef struct SetSignalsDataPbs {
+ int cur;
+
+ // these are used to keep track of the signals.
+ byte bit[NUM_SSD_ENTRY];
+ TileIndex tile[NUM_SSD_ENTRY];
+} SetSignalsDataPbs;
+
+// This function stores the signals inside the SetSignalsDataPbs struct, passed as callback to FollowTrack() in the PBSIsPbsSegment() function below
+static bool SetSignalsEnumProcPBS(uint tile, SetSignalsDataPbs *ssd, int trackdir, uint length, byte *state)
+{
+ // the tile has signals?
+ if (IsTileType(tile, MP_RAILWAY)) {
+ if (HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) {
+
+ if (ssd->cur != NUM_SSD_ENTRY) {
+ ssd->tile[ssd->cur] = tile; // remember the tile index
+ ssd->bit[ssd->cur] = TrackdirToTrack(trackdir); // and the controlling bit number
+ ssd->cur++;
+ }
+ return true;
+ } else if (IsTileDepotType(tile, TRANSPORT_RAIL))
+ return true; // don't look further if the tile is a depot
+ }
+ return false;
+}
+
+bool PBSIsPbsDepot(uint tile)
+{
+ SetSignalsDataPbs ssd;
+ bool result = false;
+ DiagDirection direction = GetDepotDirection(tile,TRANSPORT_RAIL);
+ int i;
+
+ ssd.cur = 0;
+
+ FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, direction, (TPFEnumProc*)SetSignalsEnumProcPBS, NULL, &ssd);
+ for(i=0; i!=ssd.cur; i++) {
+ uint tile = ssd.tile[i];
+ byte bit = ssd.bit[i];
+ if (!PBSIsPbsSignal(tile, bit) && !PBSIsPbsSignal(tile, bit | 8))
+ return false;
+ result = true;
+ };
+
+ return result;
+}