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