(svn r7720) [cbh] - Fix: Trains can now access bridges from, and depart bridge onto, non X- and Y-direction Tracks. custombridgeheads
authorcelestar
Mon, 01 Jan 2007 16:10:01 +0000
branchcustombridgeheads
changeset 5622 2f0cb276d32a
parent 5621 6ce400c0a2f4
child 5623 ef2a8a524a95
(svn r7720) [cbh] - Fix: Trains can now access bridges from, and depart bridge onto, non X- and Y-direction Tracks.
bridge_cmd.c
train_cmd.c
--- a/bridge_cmd.c	Mon Jan 01 16:07:21 2007 +0000
+++ b/bridge_cmd.c	Mon Jan 01 16:10:01 2007 +0000
@@ -982,6 +982,12 @@
 	return 0;
 }
 
+/**
+  * @retval 0 The vehicle can proceed
+  * @retval 4 The vehicle changed onto of off the bridge (depending on the
+  *           status before, check with v->u.rail.track == 0x40)
+  * @retval 8 The vehicle cannot enter the tile
+  */
 static uint32 VehicleEnter_Railway_Bridge(Vehicle *v, TileIndex tile, int x, int y)
 {
 	int z = GetSlopeZ(x, y) - v->z_pos;
@@ -1004,26 +1010,36 @@
 	}
 
 	dir = GetBridgeRampDirection(tile);
-	if (DirToDiagDir(v->direction) == dir ||
-			(IsTileType(tile, MP_RAILWAY_BRIDGE) && DirToDiagDir(v->direction) != ReverseDiagDir(dir))) {
+
+	/* We are entering the bridge head from the bridge itself */
+	if (v->direction == DiagDirToDir(ReverseDiagDir(dir))) {
+		v->tile = tile;
+		if (v->u.rail.track == 0x40) {
+			/* Get the vehicle out of the wormhole, the track will be chosen later
+			   by the pathfinder */
+			v->u.rail.track = 0;
+			return 4;
+		}
+		return 0;
+
+	/* We are on the bridge head itself */
+	} else {
 		switch (dir) {
 			default: NOT_REACHED();
+			/* Should any of these ifs be true, we're not near the edge which
+			   faces the bridge body. In that case, do nothing */
 			case DIAGDIR_NE: if ((x & 0xF) != 0)             return 0; break;
 			case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return 0; break;
 			case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return 0; break;
 			case DIAGDIR_NW: if ((y & 0xF) != 0)             return 0; break;
 		}
+
+		/* We're about to enter the bridge body, clear all up/down flags just in case */
 		v->u.rail.track = 0x40;
+		v->direction = DiagDirToDir(dir);
 		CLRBIT(v->u.rail.flags, VRF_GOINGUP);
 		CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
 		return 4;
-	} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
-		v->tile = tile;
-		if (v->u.rail.track == 0x40) {
-			v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
-			return 4;
-		}
-		return 0;
 	}
 	return 0;
 }
--- a/train_cmd.c	Mon Jan 01 16:07:21 2007 +0000
+++ b/train_cmd.c	Mon Jan 01 16:10:01 2007 +0000
@@ -3068,6 +3068,7 @@
 				dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
 				enterdir = DirToDiagDir(dir);
 				assert(enterdir==0 || enterdir==1 || enterdir==2 || enterdir==3);
+new_tile:
 
 				/* Get the status of the tracks in the new tile and mask
 				 * away the bits that aren't reachable. */
@@ -3159,18 +3160,27 @@
 				v->direction = chosen_dir;
 			}
 		} else {
+			uint32 res;
 			/* in tunnel on on a bridge */
 			GetNewVehiclePos(v, &gp);
 
 			SetSpeedLimitOnBridge(v);
 
-			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 0x4)) {
+			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !((res = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)) & 0x4)) {
 				v->x_pos = gp.x;
 				v->y_pos = gp.y;
 				VehiclePositionChanged(v);
 				if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
 				continue;
 			}
+
+			if (IsBridgeTile(gp.new_tile) && res & 0x4) {
+				/* ok we have just left the bridge (because the status was "onbridge" before and we got
+				   a return value of 4 from VehicleEnterTile. we know the enterdir from the bridge ramp
+				   direction, and act as if we entered the tile normally (hence the goto) */
+				enterdir = ReverseDiagDir(GetBridgeRampDirection(gp.new_tile));
+				goto new_tile;
+			}
 		}
 
 		/* update image of train, as well as delta XY */
@@ -3405,11 +3415,21 @@
 
 	tile = v->tile;
 
-	if (IsTileType(tile, MP_TUNNEL) || IsTileType(tile, MP_RAILWAY_BRIDGE)) {
-		DiagDirection dir;
-
-		dir = IsTunnelTile(tile) ? GetTunnelDirection(tile) : GetBridgeRampDirection(tile);
-		if (DiagDirToDir(dir) == v->direction) return true;
+	if (IsTileType(tile, MP_TUNNEL) && DiagDirToDir(GetTunnelDirection(tile)) == v->direction) return true;
+
+	if (IsTileType(tile, MP_RAILWAY_BRIDGE)) {
+		/* on a bridge ramp, we can always access the bridge body if we are driving in the right direction */
+		DiagDirection dir = GetBridgeRampDirection(tile);
+		Direction vdir = v->direction;
+
+		switch (dir) {
+			/* XXX - Isn't there a simpler way to do this? */
+			case DIAGDIR_NE: if (vdir == DIR_N || vdir == DIR_NE || vdir == DIR_E) return true; break;
+			case DIAGDIR_SE: if (vdir == DIR_S || vdir == DIR_SE || vdir == DIR_E) return true; break;
+			case DIAGDIR_SW: if (vdir == DIR_S || vdir == DIR_SW || vdir == DIR_W) return true; break;
+			case DIAGDIR_NW: if (vdir == DIR_N || vdir == DIR_NW || vdir == DIR_W) return true; break;
+			default: NOT_REACHED();
+		}
 	}
 
 	// depot?