295 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Id$ */
 | |
| 
 | |
| #include "stdafx.h"
 | |
| #include "openttd.h"
 | |
| #include "functions.h"
 | |
| #include "pbs.h"
 | |
| #include "debug.h"
 | |
| #include "map.h"
 | |
| #include "tile.h"
 | |
| #include "npf.h"
 | |
| #include "pathfind.h"
 | |
| #include "depot.h"
 | |
| #include "waypoint.h"
 | |
| 
 | |
| /** @file pbs.c Path-Based-Signalling implementation file
 | |
|  *  @see pbs.h */
 | |
| 
 | |
| /* reserved track encoding:
 | |
|  normal railway tracks:
 | |
|    map3hi bits 4..6 = 'Track'number of reserved track + 1, if this is zero it means nothing is reserved on this tile
 | |
|    map3hi 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 uint16 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 (IsRailWaypoint(tile)) {
 | |
| 				// waypoint
 | |
| 				SETBIT(_m[tile].m3, 6);
 | |
| 			} else {
 | |
| 				// normal rail track
 | |
| 				byte encrt = GB(_m[tile].m4, 4, 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;
 | |
| 
 | |
| 				SB(_m[tile].m4, 4, 4, encrt);
 | |
| 			}
 | |
| 			break;
 | |
| 		case MP_TUNNELBRIDGE:
 | |
| 			_m[tile].m4 |= (1 << track) & 3;
 | |
| 			break;
 | |
| 		case MP_STATION:
 | |
| 			SETBIT(_m[tile].m3, 6);
 | |
| 			break;
 | |
| 		case MP_STREET:
 | |
| 			// make sure it is a railroad crossing
 | |
| 			if (!IsLevelCrossing(tile)) return;
 | |
| 			SETBIT(_m[tile].m5, 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 (IsRailWaypoint(tile)) {
 | |
| 				// waypoint
 | |
| 				// check if its reserved
 | |
| 				if (!HASBIT(_m[tile].m3, 6)) return 0;
 | |
| 				// return the track for the correct direction
 | |
| 				return HASBIT(_m[tile].m5, 0) ? 2 : 1;
 | |
| 			} else {
 | |
| 				// normal track
 | |
| 				byte res = encrt_to_reserved[GB(_m[tile].m4, 4, 4)];
 | |
| 				assert(res != 0xFF);
 | |
| 				return res;
 | |
| 			}
 | |
| 		case MP_TUNNELBRIDGE:
 | |
| 			return GB(_m[tile].m4, 0, 2);
 | |
| 		case MP_STATION:
 | |
| 			// check if its reserved
 | |
| 			if (!HASBIT(_m[tile].m3, 6)) return 0;
 | |
| 			// return the track for the correct direction
 | |
| 			return HASBIT(_m[tile].m5, 0) ? 2 : 1;
 | |
| 		case MP_STREET:
 | |
| 			// make sure its a railroad crossing
 | |
| 			if (!IsLevelCrossing(tile)) return 0;
 | |
| 			// check if its reserved
 | |
| 			if (!HASBIT(_m[tile].m5, 0)) return 0;
 | |
| 			// return the track for the correct direction
 | |
| 			return HASBIT(_m[tile].m5, 3) ? 1 : 2;
 | |
| 		default:
 | |
| 			return 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| uint16 PBSTileUnavail(TileIndex tile) {
 | |
| 	assert(IsValidTile(tile));
 | |
| 	switch (GetTileType(tile)) {
 | |
| 		case MP_RAILWAY:
 | |
| 			if (IsRailWaypoint(tile)) {
 | |
| 				// waypoint
 | |
| 				return HASBIT(_m[tile].m3, 6) ? TRACKDIR_BIT_MASK : 0;
 | |
| 			} else {
 | |
| 				// normal track
 | |
| 				uint16 res = encrt_to_unavail[GB(_m[tile].m4, 4, 4)];
 | |
| 				assert(res != 0xFFFF);
 | |
| 				return res;
 | |
| 			}
 | |
| 		case MP_TUNNELBRIDGE:
 | |
| 			return GB(_m[tile].m4, 0, 2) | (GB(_m[tile].m4, 0, 2) << 8);
 | |
| 		case MP_STATION:
 | |
| 			return HASBIT(_m[tile].m3, 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(_m[tile].m5, 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 (IsRailWaypoint(tile)) {
 | |
| 				// waypoint
 | |
| 				CLRBIT(_m[tile].m3, 6);
 | |
| 			} else {
 | |
| 				// normal rail track
 | |
| 				byte encrt = GB(_m[tile].m4, 4, 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;
 | |
| 
 | |
| 				SB(_m[tile].m4, 4, 4, encrt);
 | |
| 			}
 | |
| 			break;
 | |
| 		case MP_TUNNELBRIDGE:
 | |
| 			_m[tile].m4 &= ~((1 << track) & 3);
 | |
| 			break;
 | |
| 		case MP_STATION:
 | |
| 			CLRBIT(_m[tile].m3, 6);
 | |
| 			break;
 | |
| 		case MP_STREET:
 | |
| 			// make sure it is a railroad crossing
 | |
| 			if (!IsLevelCrossing(tile)) return;
 | |
| 			CLRBIT(_m[tile].m5, 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, TileIndex end_tile, Trackdir end_trackdir) {
 | |
| 	uint16 res;
 | |
| 	FindLengthOfTunnelResult flotr;
 | |
| 	assert(IsValidTile(tile));
 | |
| 	assert(IsValidTrackdir(trackdir));
 | |
| 
 | |
| 	do {
 | |
| 		PBSClearTrack(tile, TrackdirToTrack(trackdir));
 | |
| 
 | |
| 		if (tile == end_tile && TrackdirToTrack(trackdir) == TrackdirToTrack(end_trackdir))
 | |
| 			return;
 | |
| 
 | |
| 		if (IsTileType(tile, MP_TUNNELBRIDGE) &&
 | |
| 				GB(_m[tile].m5, 4, 4) == 0 &&
 | |
| 				GB(_m[tile].m5, 0, 2) == TrackdirToExitdir(trackdir)) {
 | |
| 			// this is a tunnel
 | |
| 			flotr = FindLengthOfTunnel(tile, TrackdirToExitdir(trackdir));
 | |
| 
 | |
| 			tile = flotr.tile;
 | |
| 		} else {
 | |
| 			byte exitdir = TrackdirToExitdir(trackdir);
 | |
| 			tile = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(exitdir));
 | |
| 		}
 | |
| 
 | |
| 		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 PBSIsPbsSegment(uint tile, Trackdir trackdir)
 | |
| {
 | |
| 	SetSignalsDataPbs ssd;
 | |
| 	bool result = PBSIsPbsSignal(tile, trackdir);
 | |
| 	DiagDirection direction = TrackdirToExitdir(trackdir);//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;
 | |
| }
 | 
