(svn r7720) [cbh] - Fix: Trains can now access bridges from, and depart bridge onto, non X- and Y-direction Tracks.
--- 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?