Changeset - r2115:556698050edb
[Not reviewed]
master
0 6 0
hackykid - 19 years ago 2005-07-17 20:09:02
hackykid@openttd.org
(svn r2625) - Fix: [pbs] Store the end of a train's reserved path explicitly. Prevents trains from unreserving eachothers paths in some cases.
- CodeChange: Use the TrackdirToTrack function instead of &7, and remove an unneeded variable.
6 files changed with 56 insertions and 28 deletions:
0 comments (0 inline, 0 general)
npf.c
Show inline comments
 
@@ -177,33 +177,41 @@ void NPFReservePBSPath(AyStar *as)
 
					 * found a path that is intersecting with itself, which is a very bad
 
					 * thing in a pbs block. Also there is not much we can do about it at
 
					 * this point....
 
					 * BUT, you have to have a pretty fucked up junction layout for this to happen,
 
					 * so we'll just stop this train, the user will eventually notice, so he can fix it.
 
					 */
 
					PBSClearPath(start, trackdir);
 
					PBSClearPath(start, trackdir, curr->node.tile, curr->node.direction);
 
					NPFSetFlag(&ftd->node, NPF_FLAG_PBS_BLOCKED, true);
 
					DEBUG(pbs, 1) ("PBS: Self-crossing path!!!");
 
					return;
 
				};
 

	
 
				PBSReserveTrack(curr->node.tile, (curr->node.direction & 7) );
 
				PBSReserveTrack(curr->node.tile, TrackdirToTrack(curr->node.direction) );
 

	
 
				/* we want to reserve the last tile (with the signal) on the path too */
 
				if (prev != NULL && start == INVALID_TILE) {
 
					PBSReserveTrack(prev->node.tile, (prev->node.direction & 7) );
 
					start = prev->node.tile;
 
					trackdir = ReverseTrackdir(prev->node.direction);
 
				/* we want to reserve the last tile (with the signal) on the path too
 
				   also remember this tile, cause its the end of the path (where we exit the block) */
 
				if (start == INVALID_TILE) {
 
					if (prev != NULL) {
 
						PBSReserveTrack(prev->node.tile, TrackdirToTrack(prev->node.direction) );
 
						start = prev->node.tile;
 
						trackdir = ReverseTrackdir(prev->node.direction);
 
					} else {
 
						start = curr->node.tile;
 
						trackdir = curr->node.direction;
 
					}
 
				}
 
			}
 

	
 
			prev = curr;
 
			curr = curr->parent;
 
		} while (curr != NULL);
 
		// we remember the tile/track where this path leaves the pbs junction
 
		ftd->node.tile = start;
 
		ftd->node.direction = trackdir;
 
	}
 

	
 
}
 

	
 

	
 
/* Calcs the heuristic to the target station or tile. For train stations, it
 
 * takes into account the direction of approach.
 
 */
pbs.c
Show inline comments
 
@@ -186,32 +186,32 @@ void PBSClearTrack(TileIndex tile, Track
 
	};
 
	// if debugging, mark tile dirty to show reserved status
 
	if (_debug_pbs_level >= 1)
 
		MarkTileDirtyByTile(tile);
 
};
 

	
 
void PBSClearPath(TileIndex tile, Trackdir trackdir) {
 
void PBSClearPath(TileIndex tile, Trackdir trackdir, TileIndex end_tile, Trackdir end_trackdir) {
 
	uint16 res;
 
	FindLengthOfTunnelResult flotr;
 
	assert(IsValidTile(tile));
 
	assert((trackdir & ~8) <= 5);
 
	assert(IsValidTrackdir(trackdir));
 

	
 
	do {
 
		PBSClearTrack(tile, trackdir & 7);
 
		PBSClearTrack(tile, TrackdirToTrack(trackdir));
 

	
 
		if (tile == end_tile && TrackdirToTrack(trackdir) == TrackdirToTrack(end_trackdir))
 
			return;
 

	
 
		if (IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0xF0)==0 && (unsigned)(_m[tile].m5 & 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);
pbs.h
Show inline comments
 
@@ -53,17 +53,19 @@ void PBSClearTrack(TileIndex tile, Track
 
/**<
 
 * Unreserves a track.
 
 * @param tile The tile of the track.
 
 * @param track The track to unreserve, valid values 0-5.
 
 */
 

	
 
void PBSClearPath(TileIndex tile, Trackdir trackdir);
 
void PBSClearPath(TileIndex tile, Trackdir trackdir, TileIndex end_tile, Trackdir end_trackdir);
 
/**<
 
 * Follows a planned(reserved) path, and unreserves the tracks.
 
 * @param tile The tile on which the path starts
 
 * @param trackdir The trackdirection in which the path starts
 
 * @param end_tile The tile on which the path ends
 
 * @param end_trackdir The trackdirection in which the path ends
 
 */
 

	
 
bool PBSIsPbsSignal(TileIndex tile, Trackdir trackdir);
 
/**<
 
 * Checks if there are pbs signals on a track.
 
 * @param tile The tile you want to check
train_cmd.c
Show inline comments
 
@@ -1318,19 +1318,21 @@ TileIndex GetVehicleTileOutOfTunnel(cons
 

	
 
static void ReverseTrainDirection(Vehicle *v)
 
{
 
	int l = 0, r = -1;
 
	Vehicle *u;
 
	TileIndex tile;
 
	byte trackdir;
 
	Trackdir trackdir;
 
	TileIndex pbs_end_tile = v->u.rail.pbs_end_tile; // these may be changed, and we may need
 
	Trackdir pbs_end_trackdir = v->u.rail.pbs_end_trackdir; // the old values, so cache them
 

	
 
	u = GetLastVehicleInChain(v);
 
	tile = GetVehicleTileOutOfTunnel(u, false);
 
	trackdir = ReverseTrackdir(GetVehicleTrackdir(u));
 

	
 
	if (PBSTileReserved(tile) & (1 << (trackdir&7))) {
 
	if (PBSTileReserved(tile) & (1 << TrackdirToTrack(trackdir))) {
 
		NPFFindStationOrTileData fstd;
 
		NPFFoundTargetData ftd;
 

	
 
		NPFFillWithOrderData(&fstd, v);
 

	
 
		tile = GetVehicleTileOutOfTunnel(u, true);
 
@@ -1348,30 +1350,32 @@ static void ReverseTrainDirection(Vehicl
 
		if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) {
 
			if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED)) {
 
				CLRBIT(v->u.rail.flags, VRF_REVERSING);
 
				return;
 
			}
 
		}
 

	
 
		v->u.rail.pbs_end_tile = ftd.node.tile;
 
		v->u.rail.pbs_end_trackdir = ftd.node.direction;
 
	}
 

	
 
	tile = GetVehicleTileOutOfTunnel(v, false);
 
	trackdir = GetVehicleTrackdir(v);
 

	
 
	if (v->u.rail.pbs_status == PBS_STAT_HAS_PATH) {
 
		byte trackdir = GetVehicleTrackdir(v);
 
		TileIndex tile = AddTileIndexDiffCWrap(v->tile, TileIndexDiffCByDir(TrackdirToExitdir(trackdir)));
 
		uint32 ts;
 
		assert(tile != INVALID_TILE);
 
		ts = GetTileTrackStatus(tile, TRANSPORT_RAIL);
 
		ts &= TrackdirReachesTrackdirs(trackdir);
 
		assert(ts != 0 && KillFirstBit2x64(ts) == 0);
 
		trackdir = FindFirstBit2x64(ts);
 
		PBSClearPath(tile, trackdir);
 
		PBSClearPath(tile, trackdir, pbs_end_tile, pbs_end_trackdir);
 
		v->u.rail.pbs_status = PBS_STAT_NONE;
 
	} else if (PBSTileReserved(tile) & (1 << (trackdir&7))) {
 
		PBSClearPath(tile, trackdir);
 
	} else if (PBSTileReserved(tile) & (1 << TrackdirToTrack(trackdir))) {
 
		PBSClearPath(tile, trackdir, pbs_end_tile, pbs_end_trackdir);
 
		if (v->u.rail.track != 0x40)
 
			PBSReserveTrack(tile, trackdir & 7);
 
	};
 

	
 
	if (IsTileDepotType(v->tile, TRANSPORT_RAIL))
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
@@ -1835,14 +1839,17 @@ static bool CheckTrainStayInDepot(Vehicl
 
			ftd = NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_GREEN);
 

	
 
			// we found a way out of the pbs block
 
			if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) {
 
				if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED))
 
					return true;
 
				else
 
				else {
 
					v->u.rail.pbs_end_tile = ftd.node.tile;
 
					v->u.rail.pbs_end_trackdir = ftd.node.direction;
 
					goto green;
 
				}
 
			}
 
		}
 

	
 

	
 
		if (UpdateSignalsOnSegment(v->tile, v->direction)) {
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
 
@@ -2004,17 +2011,20 @@ static byte ChooseTrainTrack(Vehicle *v,
 
		pbs_tracks = PBSTileReserved(tile);
 
		pbs_tracks |= pbs_tracks << 8;
 
		pbs_tracks &= TrackdirReachesTrackdirs(trackdir);
 
		if (pbs_tracks || (v->u.rail.pbs_status == PBS_STAT_NEED_PATH)) {
 
			DEBUG(pbs, 2) ("pbs: (%i) choosefromblock, tile_org:%x tile_dst:%x  trackdir:%i  pbs_tracks:%i",v->unitnumber, tile,tile - TileOffsByDir(enterdir), trackdir, pbs_tracks);
 
			// clear the currently planned path
 
			if (v->u.rail.pbs_status != PBS_STAT_NEED_PATH) PBSClearPath(tile, FindFirstBit2x64(pbs_tracks));
 
			if (v->u.rail.pbs_status != PBS_STAT_NEED_PATH) PBSClearPath(tile, FindFirstBit2x64(pbs_tracks), v->u.rail.pbs_end_tile, v->u.rail.pbs_end_trackdir);
 

	
 
			// try to find a route to a green exit signal
 
			ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_ANY);
 

	
 
			v->u.rail.pbs_end_tile = ftd.node.tile;
 
			v->u.rail.pbs_end_trackdir = ftd.node.direction;
 

	
 
		} else
 
			ftd = NPFRouteToStationOrTile(tile - TileOffsByDir(enterdir), trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_NONE);
 

	
 
		if (ftd.best_trackdir == 0xff) {
 
			/* We are already at our target. Just do something */
 
			//TODO: maybe display error?
 
@@ -2776,12 +2786,14 @@ static void TrainController(Vehicle *v)
 

	
 
							// we found a way out of the pbs block
 
							if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) {
 
								if (NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED))
 
									goto red_light;
 
								else {
 
									v->u.rail.pbs_end_tile = ftd.node.tile;
 
									v->u.rail.pbs_end_trackdir = ftd.node.direction;
 
									goto green_light;
 
								}
 

	
 
							};
 

	
 
						} else {
 
@@ -2952,14 +2964,14 @@ static void DeleteLastWagon(Vehicle *v)
 
	EndVehicleMove(v);
 
	DeleteVehicle(v);
 

	
 
	// clear up reserved pbs tracks
 
	if (PBSTileReserved(v->tile) & v->u.rail.track) {
 
		if (v == u) {
 
			PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track));
 
			PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track) + 8);
 
			PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track), v->u.rail.pbs_end_tile, v->u.rail.pbs_end_trackdir);
 
			PBSClearPath(v->tile, FIND_FIRST_BIT(v->u.rail.track) + 8, v->u.rail.pbs_end_tile, v->u.rail.pbs_end_trackdir);
 
		};
 
		if (v->tile != u->tile) {
 
			PBSClearTrack(v->tile, FIND_FIRST_BIT(v->u.rail.track));
 
		};
 
	}
 

	
 
@@ -3203,12 +3215,14 @@ static bool TrainCheckIfLineEnds(Vehicle
 
		DEBUG(pbs, 2) ("pbs: (%i) choose signal (CEOL), tile:%x  trackdir:%i", v->unitnumber, tile, trackdir);
 
		ftd = NPFRouteToStationOrTile(tile, trackdir, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype, PBS_MODE_GREEN);
 

	
 
		if (ftd.best_trackdir != 0xFF && NPFGetFlag(&ftd.node, NPF_FLAG_PBS_EXIT)) {
 
			if (!(NPFGetFlag(&ftd.node, NPF_FLAG_PBS_BLOCKED) || NPFGetFlag(&ftd.node, NPF_FLAG_PBS_RED))) {
 
				v->u.rail.pbs_status = PBS_STAT_HAS_PATH;
 
				v->u.rail.pbs_end_tile = ftd.node.tile;
 
				v->u.rail.pbs_end_trackdir = ftd.node.direction;
 
				return true;
 
			}
 
		};
 
	};
 

	
 
	// slow down
vehicle.c
Show inline comments
 
@@ -1944,14 +1944,16 @@ static const SaveLoad _train_desc[] = {
 
	SLE_VARX(offsetof(Vehicle,u)+offsetof(VehicleRail,track), SLE_UINT8),
 

	
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,flags), SLE_UINT8, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,days_since_order_progr), SLE_UINT16, 2, 255),
 

	
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_status), SLE_UINT8, 2, 255),
 
	// reserve extra space in savegame here. (currently 12 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 12, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_tile), SLE_UINT32, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_trackdir), SLE_UINT8, 2, 255),
 
	// reserve extra space in savegame here. (currently 7 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 7, 2, 255),
 

	
 
	SLE_END()
 
};
 

	
 
static const SaveLoad _roadveh_desc[] = {
 
	SLE_WRITEBYTE(Vehicle,type,VEH_Road, 1), // Road type. VEH_Road in mem, 1 in file.
vehicle.h
Show inline comments
 
@@ -67,12 +67,14 @@ typedef struct VehicleRail {
 
	byte force_proceed;
 
	byte railtype;
 

	
 
	byte flags;
 

	
 
	byte pbs_status;
 
	TileIndex pbs_end_tile;
 
	Trackdir pbs_end_trackdir;
 
} VehicleRail;
 

	
 
enum {
 
	VRF_REVERSING = 0,
 

	
 
	// used to calculate if train is going up or down
0 comments (0 inline, 0 general)