tunnelbridge_cmd.c
changeset 3977 edb5b94e2094
parent 3938 73c210a59c43
child 3996 5a1d1fc1bd07
--- a/tunnelbridge_cmd.c	Wed Jun 07 18:41:58 2006 +0000
+++ b/tunnelbridge_cmd.c	Wed Jun 07 19:35:21 2006 +0000
@@ -30,6 +30,11 @@
 
 #include "table/bridge_land.h"
 
+extern const byte _track_sloped_sprites[14];
+extern const SpriteID _water_shore_sprites[15];
+
+extern void DrawCanalWater(TileIndex tile);
+
 const Bridge orig_bridge[] = {
 /*
 	   year of availablity
@@ -192,6 +197,7 @@
 	TileIndex tile;
 	TileIndexDiff delta;
 	uint bridge_len;
+	uint odd_middle_part;
 	Axis direction;
 	uint i;
 	int32 cost, terraformcost, ret;
@@ -283,26 +289,6 @@
 		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 	cost += terraformcost;
 
-	{
-		TileIndex Heads[] = {tile_start, tile_end};
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			if (MayHaveBridgeAbove(Heads[i])) {
-				if (IsBridgeAbove(Heads[i])) {
-					TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
-					int z1, z2;
-
-					if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-
-					z1 = GetBridgeHeight(north_head, GetBridgeAxis(Heads[i]));
-					z2 = GetBridgeHeight(Heads[i], direction);
-
-					if (z1 == z2) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
-				}
-			}
-		}
-	}
 
 	/* do the drill? */
 	if (flags & DC_EXEC) {
@@ -319,42 +305,48 @@
 		MarkTileDirtyByTile(tile_end);
 	}
 
+	// position of middle part of the odd bridge (larger than MAX(i) otherwise)
+	odd_middle_part = (bridge_len % 2) ? (bridge_len / 2) : bridge_len;
+
 	tile = tile_start;
 	delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 	for (i = 0; i != bridge_len; i++) {
+		TransportType transport_under;
+		Owner owner_under = OWNER_NONE;
+		RailType rail_under = INVALID_RAILTYPE;
 		uint z;
 
 		tile += delta;
 
-		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
-
-		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
-			/* Disallow crossing bridges for the time being */
-			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+		if (GetTileSlope(tile, &z) != SLOPE_FLAT && z >= z_start) {
+			return_cmd_error(STR_5009_LEVEL_LAND_OR_WATER_REQUIRED);
 		}
 
 		switch (GetTileType(tile)) {
 			case MP_WATER:
 				if (!EnsureNoVehicle(tile)) return_cmd_error(STR_980E_SHIP_IN_THE_WAY);
 				if (!(IsWater(tile) || IsCoast(tile))) goto not_valid_below;
+				transport_under = TRANSPORT_WATER;
+				owner_under = GetTileOwner(tile);
 				break;
 
 			case MP_RAILWAY:
-				if (!IsPlainRailTile(tile)) goto not_valid_below;
+				if (GetRailTileType(tile) != RAIL_TILE_NORMAL ||
+						GetTrackBits(tile) != (direction == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X)) {
+					goto not_valid_below;
+				}
+				transport_under = TRANSPORT_RAIL;
+				owner_under = GetTileOwner(tile);
+				rail_under = GetRailType(tile);
 				break;
 
 			case MP_STREET:
-				if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) goto not_valid_below;
-				break;
-
-			case MP_TUNNELBRIDGE:
-				if (IsTunnel(tile)) break;
-				if (direction == DiagDirToAxis(GetBridgeRampDirection(tile))) goto not_valid_below;
-				if (GetBridgeHeight(tile_start, direction) == GetBridgeHeight(tile, DiagDirToAxis(GetBridgeRampDirection(tile)))) goto not_valid_below;
-				break;
-
-			case MP_CLEAR:
-				if (IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+				if (GetRoadTileType(tile) != ROAD_TILE_NORMAL ||
+						GetRoadBits(tile) != (direction == AXIS_X ? ROAD_Y : ROAD_X)) {
+					goto not_valid_below;
+				}
+				transport_under = TRANSPORT_ROAD;
+				owner_under = GetTileOwner(tile);
 				break;
 
 			default:
@@ -363,11 +355,58 @@
 				ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 				if (CmdFailed(ret)) return ret;
 				cost += ret;
+				transport_under = INVALID_TRANSPORT;
 				break;
 		}
 
 		if (flags & DC_EXEC) {
-			SetBridgeMiddle(tile, direction);
+			uint piece;
+
+			//bridges pieces sequence (middle parts)
+			// bridge len 1: 0
+			// bridge len 2: 0 1
+			// bridge len 3: 0 4 1
+			// bridge len 4: 0 2 3 1
+			// bridge len 5: 0 2 5 3 1
+			// bridge len 6: 0 2 3 2 3 1
+			// bridge len 7: 0 2 3 4 2 3 1
+			// #0 - always as first, #1 - always as last (if len>1)
+			// #2,#3 are to pair in order
+			// for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
+
+			if (i == 0) { // first tile
+				piece = 0;
+			} else if (i == bridge_len - 1) { // last tile
+				piece = 1;
+			} else if (i == odd_middle_part) { // we are on the middle of odd bridge: #5 on even pos, #4 on odd
+				piece = 5 - (i % 2);
+			} else {
+					// generate #2 and #3 in turns [i%2==0], after the middle of odd bridge
+					// this sequence swaps [... XOR (i>odd_middle_part)],
+					// for even bridges XOR does not apply as odd_middle_part==bridge_len
+					piece = 2 + ((i % 2 == 0) ^ (i > odd_middle_part));
+			}
+
+			if (transport == TRANSPORT_RAIL) {
+				MakeRailBridgeMiddle(tile, bridge_type, piece, direction, railtype);
+			} else {
+				MakeRoadBridgeMiddle(tile, bridge_type, piece, direction);
+			}
+			switch (transport_under) {
+				case TRANSPORT_RAIL: SetRailUnderBridge(tile, owner_under, rail_under); break;
+				case TRANSPORT_ROAD: SetRoadUnderBridge(tile, owner_under); break;
+
+				case TRANSPORT_WATER:
+					if (owner_under == OWNER_WATER) {
+						SetWaterUnderBridge(tile);
+					} else {
+						SetCanalUnderBridge(tile, owner_under);
+					}
+					break;
+
+				default: SetClearUnderBridge(tile); break;
+			}
+
 			MarkTileDirtyByTile(tile);
 		}
 	}
@@ -552,7 +591,7 @@
 	return _price.clear_tunnel * (length + 1);
 }
 
-#if 0
+
 static uint GetBridgeHeightRamp(TileIndex t)
 {
 	/* Return the height there (the height of the NORTH CORNER)
@@ -560,7 +599,6 @@
 	 * the z coordinate is 1 height level too low. Compensate for that */
 	return TilePixelHeight(t) + (GetTileSlope(t, NULL) == SLOPE_WSE ? TILE_HEIGHT : 0);
 }
-#endif
 
 
 static int32 DoClearBridge(TileIndex tile, uint32 flags)
@@ -568,10 +606,47 @@
 	DiagDirection direction;
 	TileIndexDiff delta;
 	TileIndex endtile;
+	Vehicle *v;
 	Town *t;
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
+	if (IsBridgeMiddle(tile)) {
+		if (IsTransportUnderBridge(tile)) {
+			/* delete transport route under the bridge */
+			int32 cost;
+
+			// check if we own the tile below the bridge..
+			if (_current_player != OWNER_WATER && (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile)))
+				return CMD_ERROR;
+
+			if (GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
+				cost = _price.remove_rail;
+			} else {
+				cost = _price.remove_road * 2;
+			}
+
+			if (flags & DC_EXEC) {
+				SetClearUnderBridge(tile);
+				MarkTileDirtyByTile(tile);
+			}
+			return cost;
+		} else if (IsWaterUnderBridge(tile) && TilePixelHeight(tile) != 0) {
+			/* delete canal under bridge */
+
+			// check for vehicles under bridge
+			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				SetClearUnderBridge(tile);
+				MarkTileDirtyByTile(tile);
+			}
+			return _price.clear_water;
+		}
+
+		tile = GetSouthernBridgeEnd(tile);
+	}
+
 	// floods, scenario editor can always destroy bridges
 	if (_current_player != OWNER_WATER && _game_mode != GM_EDITOR && !CheckTileOwnership(tile)) {
 		if (!(_patches.extra_dynamite || _cheats.magic_bulldozer.value) || !IsTileOwner(tile, OWNER_TOWN))
@@ -585,6 +660,18 @@
 	direction = GetBridgeRampDirection(tile);
 	delta = TileOffsByDir(direction);
 
+	/*	Make sure there's no vehicle on the bridge
+			Omit tile and endtile, since these are already checked, thus solving the problem
+			of bridges over water, or higher bridges, where z is not increased, eg level bridge
+	*/
+	/* Bridges on slopes might have their Z-value offset..correct this */
+	v = FindVehicleBetween(
+		tile    + delta,
+		endtile - delta,
+		GetBridgeHeightRamp(tile) + TILE_HEIGHT
+	);
+	if (v != NULL) return_cmd_error(VehicleInTheWayErrMsg(v));
+
 	t = ClosestTownFromTile(tile, (uint)-1); //needed for town rating penalty
 	// check if you're allowed to remove the bridge owned by a town.
 	// removal allowal depends on difficulty settings
@@ -603,8 +690,26 @@
 		DoClearSquare(tile);
 		DoClearSquare(endtile);
 		for (c = tile + delta; c != endtile; c += delta) {
-			ClearBridgeMiddle(c);
-			MarkTileDirtyByTile(c);
+			if (IsTransportUnderBridge(c)) {
+				if (GetTransportTypeUnderBridge(c) == TRANSPORT_RAIL) {
+					MakeRailNormal(c, GetTileOwner(c), GetRailBitsUnderBridge(c), GetRailType(c));
+				} else {
+					uint town = IsTileOwner(c, OWNER_TOWN) ? ClosestTownFromTile(c, (uint)-1)->index : 0;
+					MakeRoadNormal(c, GetTileOwner(c), GetRoadBitsUnderBridge(c), town);
+				}
+				MarkTileDirtyByTile(c);
+			} else {
+				if (IsClearUnderBridge(c)) {
+					DoClearSquare(c);
+				} else {
+					if (GetTileSlope(c, NULL) == SLOPE_FLAT) {
+						MakeWater(c);
+					} else {
+						MakeShore(c);
+					}
+					MarkTileDirtyByTile(c);
+				}
+			}
 		}
 
 		UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
@@ -657,7 +762,29 @@
 			YapfNotifyTrackLayoutChange(endtile, endtrack);
 		}
 		return (length + 1) * (_price.build_rail >> 1);
-	} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
+	} else if (IsBridge(tile) &&
+			IsBridgeMiddle(tile) &&
+			IsTransportUnderBridge(tile) &&
+			GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
+		// only check for train under bridge
+		if (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile))
+			return CMD_ERROR;
+
+		if (GetRailType(tile) == totype) return CMD_ERROR;
+
+		if (exec) {
+			TrackBits tracks;
+			SetRailType(tile, totype);
+			MarkTileDirtyByTile(tile);
+
+			// notify YAPF about the track layout change
+			for (tracks = GetRailBitsUnderBridge(tile); tracks != TRACK_BIT_NONE; tracks = KILL_FIRST_BIT(tracks))
+				YapfNotifyTrackLayoutChange(tile, FIND_FIRST_BIT(tracks));
+		}
+		return _price.build_rail >> 1;
+	} else if (IsBridge(tile) && IsBridgeRamp(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
+		TileIndexDiff delta;
+		int32 cost;
 		uint z = TilePixelHeight(tile);
 
 		z += TILE_HEIGHT;
@@ -678,29 +805,53 @@
 		if (GetRailType(tile) == totype) return CMD_ERROR;
 
 		if (exec) {
-			TileIndexDiff delta;
-
+			Track track, endtrack;
 			SetRailType(tile, totype);
 			SetRailType(endtile, totype);
 			MarkTileDirtyByTile(tile);
 			MarkTileDirtyByTile(endtile);
 
-			delta = TileOffsByDir(GetBridgeRampDirection(tile));
-			for (tile += delta; tile != endtile; tile += delta) {
-				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
+			// notify YAPF about the track layout change
+			track = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(tile)));
+			endtrack = TrackdirToTrack(DiagdirToDiagTrackdir(GetBridgeRampDirection(endtile)));
+			YapfNotifyTrackLayoutChange(tile, track);
+			YapfNotifyTrackLayoutChange(endtile, endtrack);
+		}
+		cost = 2 * (_price.build_rail >> 1);
+		delta = TileOffsByDir(GetBridgeRampDirection(tile));
+		for (tile += delta; tile != endtile; tile += delta) {
+			if (exec) {
+				SetRailTypeOnBridge(tile, totype);
+				MarkTileDirtyByTile(tile);
 			}
+			cost += _price.build_rail >> 1;
 		}
 
-		return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
+		return cost;
 	} else
 		return CMD_ERROR;
 }
 
 
-static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
+// fast routine for getting the height of a middle bridge tile. 'tile' MUST be a middle bridge tile.
+uint GetBridgeHeight(TileIndex t)
+{
+	return GetBridgeHeightRamp(GetSouthernBridgeEnd(t));
+}
+
+static const byte _bridge_foundations[2][16] = {
+// 0 1  2  3  4 5 6 7  8 9 10 11 12 13 14 15
+	{0,16,18,3,20,5,0,7,22,0,10,11,12,13,14},
+	{0,15,17,0,19,5,6,7,21,9,10,11, 0,13,14},
+};
+
+extern const byte _road_sloped_sprites[14];
+
+static void DrawBridgePillars(PalSpriteID image, const TileInfo *ti, int x, int y, int z)
 {
 	if (image != 0) {
-		bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
+		Axis axis = GetBridgeAxis(ti->tile);
+		bool drawfarpillar = !HASBIT(GetBridgeFlags(GetBridgeType(ti->tile)), 0);
 		int back_height, front_height;
 		int i = z;
 		const byte *p;
@@ -763,11 +914,17 @@
   * <li>Bit 2: Set if the bridge head is sloped</li>
   * <li>Bit 3 and more: Railtype Specific subset</li>
   * </ul>
+  * For middle parts:
+  * <ul><li>Bits 0-1: need to be 0</li>
+  * <li>Bit 2: direction</li>
+  * <li>Bit 3 and above: Railtype Specific subset</li>
+  * </ul>
   * Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3
   */
 static void DrawTile_TunnelBridge(TileInfo *ti)
 {
 	uint32 image;
+	const PalSpriteID *b;
 	bool ice = _m[ti->tile].m4 & 0x80;
 
 	if (IsTunnel(ti->tile)) {
@@ -784,12 +941,19 @@
 		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
 
 		AddSortableSpriteToDraw(image+1, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, 1, 1, 8, (byte)ti->z);
-		DrawBridgeMiddle(ti);
 	} else if (IsBridge(ti->tile)) { // XXX is this necessary?
 		int base_offset;
 
 		if (GetBridgeTransportType(ti->tile) == TRANSPORT_RAIL) {
-			base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
+			RailType rt;
+
+			if (IsBridgeRamp(ti->tile)) {
+				rt = GetRailType(ti->tile);
+			} else {
+				rt = GetRailTypeOnBridge(ti->tile);
+			}
+
+			base_offset = GetRailTypeInfo(rt)->bridge_offset;
 			assert(base_offset != 8); /* This one is used for roads */
 		} else {
 			base_offset = 8;
@@ -798,152 +962,124 @@
 		/* as the lower 3 bits are used for other stuff, make sure they are clear */
 		assert( (base_offset & 0x07) == 0x00);
 
-		if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
-			int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
-			if (f) DrawFoundation(ti, f);
-		}
-
-		// HACK Wizardry to convert the bridge ramp direction into a sprite offset
-		base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
-
-		if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
-
-		/* Table number 6 always refers to the bridge heads for any bridge type */
-		image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
-
-		if (!ice) {
-			DrawClearLandTile(ti, 3);
-		} else {
-			DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
-		}
-
-		if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-		// draw ramp
-		if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-		AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 7, ti->z);
+		if (IsBridgeRamp(ti->tile)) {
+			if (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
+				int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
+				if (f) DrawFoundation(ti, f);
+			}
 
-		DrawBridgeMiddle(ti);
-	}
-}
-
+			// HACK Wizardry to convert the bridge ramp direction into a sprite offset
+			base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
 
-//bridges pieces sequence (middle parts)
-// bridge len 1: 0
-// bridge len 2: 0 1
-// bridge len 3: 0 4 1
-// bridge len 4: 0 2 3 1
-// bridge len 5: 0 2 5 3 1
-// bridge len 6: 0 2 3 2 3 1
-// bridge len 7: 0 2 3 4 2 3 1
-// #0 - always as first, #1 - always as last (if len>1)
-// #2,#3 are to pair in order
-// for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
-static uint CalcBridgePiece(uint north, uint south)
-{
-	if (north == 1) {
-		return 0;
-	} else if (south == 1) {
-		return 1;
-	} else if (north < south) {
-		return north & 1 ? 3 : 2;
-	} else if (north > south) {
-		return south & 1 ? 2 : 3;
-	} else {
-		return north & 1 ? 5 : 4;
+			if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
+
+			/* Table number 6 always refers to the bridge heads for any bridge type */
+			image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
+
+			if (!ice) {
+				DrawClearLandTile(ti, 3);
+			} else {
+				DrawGroundSprite(SPR_FLAT_SNOWY_TILE + _tileh_to_sprite[ti->tileh]);
+			}
+
+			if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+			// draw ramp
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+			AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 16, 7, ti->z);
+		} else {
+			// bridge middle part.
+			Axis axis = GetBridgeAxis(ti->tile);
+			uint z;
+			int x,y;
+
+			if (IsTransportUnderBridge(ti->tile)) {
+				uint f = _bridge_foundations[axis][ti->tileh];
+
+				if (f != 0) DrawFoundation(ti, f);
+
+				if (GetTransportTypeUnderBridge(ti->tile) == TRANSPORT_RAIL) {
+					const RailtypeInfo* rti = GetRailTypeInfo(GetRailType(ti->tile));
+
+					if (ti->tileh == SLOPE_FLAT) {
+						image = (axis == AXIS_X ? SPR_RAIL_TRACK_Y : SPR_RAIL_TRACK_X);
+					} else {
+						image = SPR_RAIL_TRACK_Y + _track_sloped_sprites[ti->tileh - 1];
+					}
+					image += rti->total_offset;
+					if (ice) image += rti->snow_offset;
+				} else {
+					if (ti->tileh == SLOPE_FLAT) {
+						image = (axis == AXIS_X ? SPR_ROAD_Y : SPR_ROAD_X);
+					} else {
+						image = _road_sloped_sprites[ti->tileh - 1] + 0x53F;
+					}
+					if (ice) image += 19;
+				}
+				DrawGroundSprite(image);
+			} else {
+				if (IsClearUnderBridge(ti->tile)) {
+					image = (ice ? SPR_FLAT_SNOWY_TILE : SPR_FLAT_GRASS_TILE);
+					DrawGroundSprite(image + _tileh_to_sprite[ti->tileh]);
+				} else {
+					if (ti->tileh == SLOPE_FLAT) {
+						DrawGroundSprite(SPR_FLAT_WATER_TILE);
+						if (ti->z != 0) DrawCanalWater(ti->tile);
+					} else {
+						DrawGroundSprite(_water_shore_sprites[ti->tileh]);
+					}
+				}
+			}
+
+			if (axis != AXIS_X) base_offset += 4;
+
+			/*  base_offset needs to be 0 due to the structure of the sprite table see table/bridge_land.h */
+			assert( (base_offset & 0x03) == 0x00);
+			// get bridge sprites
+			b = GetBridgeSpriteTable(GetBridgeType(ti->tile), GetBridgePiece(ti->tile)) + base_offset;
+
+			z = GetBridgeHeight(ti->tile) + 5;
+
+			// draw rail or road component
+			image = b[0];
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+			if (axis == AXIS_X) {
+				AddSortableSpriteToDraw(image, ti->x, ti->y, 16, 11, 1, z);
+			} else {
+				AddSortableSpriteToDraw(image, ti->x, ti->y, 11, 16, 1, z);
+			}
+
+			x = ti->x;
+			y = ti->y;
+			image = b[1];
+			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+
+			// draw roof, the component of the bridge which is logically between the vehicle and the camera
+			if (axis == AXIS_X) {
+				y += 12;
+				if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
+			} else {
+				x += 12;
+				if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
+			}
+
+			if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC || GetRailTypeOnBridge(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
+
+			if (ti->z + 5 == z) {
+				// draw poles below for small bridges
+				image = b[2];
+				if (image != 0) {
+					if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
+					DrawGroundSpriteAt(image, x, y, z);
+				}
+			} else if (_patches.bridge_pillars) {
+				// draw pillars below for high bridges
+				DrawBridgePillars(b[2], ti, x, y, z);
+			}
+		}
 	}
 }
 
-void DrawBridgeMiddle(const TileInfo* ti)
-{
-	const PalSpriteID* b;
-	PalSpriteID image;
-	uint base_offset;
-	TileIndex rampnorth;
-	TileIndex rampsouth;
-	Axis axis;
-	uint piece;
-	uint type;
-	int x;
-	int y;
-	uint z;
-
-	if (!IsBridgeAbove(ti->tile)) return;
-
-	rampnorth = GetNorthernBridgeEnd(ti->tile);
-	rampsouth = GetSouthernBridgeEnd(ti->tile);
-
-	axis = GetBridgeAxis(ti->tile);
-	piece = CalcBridgePiece(
-		DistanceManhattan(ti->tile, rampnorth),
-		DistanceManhattan(ti->tile, rampsouth)
-	);
-	type = GetBridgeType(rampsouth);
-
-	if (GetBridgeTransportType(rampsouth) == TRANSPORT_RAIL) {
-		base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
-	} else {
-		base_offset = 8;
-	}
-
-	b = base_offset + GetBridgeSpriteTable(type, piece);
-	if (axis != AXIS_X) b += 4;
-
-	x = ti->x;
-	y = ti->y;
-	z = GetBridgeHeight(rampsouth, axis) - 3;
-
-	image = b[0];
-	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-	if (axis == AXIS_X) {
-		AddSortableSpriteToDraw(image, x, y, 16, 11, 1, z);
-	} else {
-		AddSortableSpriteToDraw(image, x, y, 11, 16, 1, z);
-	}
-
-	image = b[1];
-	if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-
-	// draw roof, the component of the bridge which is logically between the vehicle and the camera
-	if (axis == AXIS_X) {
-		y += 12;
-		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 16, 1, 0x28, z);
-	} else {
-		x += 12;
-		if (image & SPRITE_MASK) AddSortableSpriteToDraw(image, x, y, 1, 16, 0x28, z);
-	}
-
-	if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
-
-	if (ti->z + 5 == z) {
-		// draw poles below for small bridges
-		image = b[2];
-		if (image != 0) {
-			if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
-			DrawGroundSpriteAt(image, x, y, z);
-		}
-	} else if (_patches.bridge_pillars) {
-		// draw pillars below for high bridges
-		DrawBridgePillars(b[2], ti, axis, type, x, y, z);
-	}
-}
-
-
-uint SetSpeedLimitOnBridge(Vehicle *v)
-{
-	uint bridge_speed;
-	if (v->vehstatus & VS_HIDDEN) return v->max_speed; /* in tunnel */
-
-	bridge_speed = _bridge[GetBridgeType(v->tile)].speed;
-
-	if (v->type == VEH_Road) bridge_speed *= 2; /* XXX give vehicles proper speeds */
-
-	if (v->cur_speed > bridge_speed) v->cur_speed = bridge_speed;
-	return bridge_speed;
-}
-
-
-
 static uint GetSlopeZ_TunnelBridge(const TileInfo* ti)
 {
 	TileIndex tile = ti->tile;
@@ -958,30 +1094,44 @@
 		// In the tunnel entrance?
 		if (5 <= pos && pos <= 10) return z;
 	} else {
-		DiagDirection dir = GetBridgeRampDirection(tile);
-		uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
-
-		// On the bridge ramp?
-		if (5 <= pos && pos <= 10) {
-			uint delta;
-
-			if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
+		if (IsBridgeRamp(tile)) {
+			DiagDirection dir = GetBridgeRampDirection(tile);
+			uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x);
 
-			if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
-			switch (dir) {
-				default:
-				case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
-				case DIAGDIR_SE: delta = y / 2; break;
-				case DIAGDIR_SW: delta = x / 2; break;
-				case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
+			// On the bridge ramp?
+			if (5 <= pos && pos <= 10) {
+				uint delta;
+
+				if (HASBIT(BRIDGE_HORZ_RAMP, tileh)) return z + TILE_HEIGHT;
+
+				if (HASBIT(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) z += TILE_HEIGHT;
+				switch (dir) {
+					default:
+					case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break;
+					case DIAGDIR_SE: delta = y / 2; break;
+					case DIAGDIR_SW: delta = x / 2; break;
+					case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break;
+				}
+				return z + 1 + delta;
+			} else {
+				uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
+
+				if (f != 0) {
+					if (f < 15) return z + TILE_HEIGHT;
+					tileh = _inclined_tileh[f - 15];
+				}
 			}
-			return z + 1 + delta;
 		} else {
-			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
+			// HACK on the bridge?
+			if (_get_z_hint >= z + TILE_HEIGHT + (tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)) return _get_z_hint;
 
-			if (f != 0) {
-				if (f < 15) return z + TILE_HEIGHT;
-				tileh = _inclined_tileh[f - 15];
+			if (IsTransportUnderBridge(tile)) {
+				uint f = _bridge_foundations[GetBridgeAxis(tile)][tileh];
+
+				if (f != 0) {
+					if (f < 15) return z + TILE_HEIGHT;
+					tileh = _inclined_tileh[f - 15];
+				}
 			}
 		}
 	}
@@ -1040,6 +1190,9 @@
 			STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
 	} else {
 		td->str = _bridge_tile_str[GetBridgeTransportType(tile) << 4 | GetBridgeType(tile)];
+
+		// the owner is stored at the end of the bridge
+		if (IsBridgeMiddle(tile)) tile = GetSouthernBridgeEnd(tile);
 	}
 	td->owner = GetTileOwner(tile);
 }
@@ -1074,6 +1227,10 @@
 			}
 			break;
 	}
+
+	if (IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile)) {
+		TileLoop_Water(tile);
+	}
 }
 
 static void ClickTile_TunnelBridge(TileIndex tile)
@@ -1084,13 +1241,37 @@
 
 static uint32 GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode)
 {
+	uint32 result;
+
 	if (IsTunnel(tile)) {
 		if (GetTunnelTransportType(tile) == mode) {
 			return DiagDirToAxis(GetTunnelDirection(tile)) == AXIS_X ? 0x101 : 0x202;
 		}
 	} else if (IsBridge(tile)) { // XXX is this necessary?
-		if (GetBridgeTransportType(tile) != mode) return 0;
-		return (DiagDirToAxis(GetBridgeRampDirection(tile)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
+		if (IsBridgeRamp(tile)) {
+			if (GetBridgeTransportType(tile) != mode) return 0;
+			return (DiagDirToAxis(GetBridgeRampDirection(tile)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
+		} else {
+			result = 0;
+			if (GetBridgeTransportType(tile) == mode) {
+				result = (GetBridgeAxis(tile) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
+			}
+			if (IsTransportUnderBridge(tile)) {
+				if (GetTransportTypeUnderBridge(tile) != mode) return result;
+			} else {
+				if (IsClearUnderBridge(tile)) {
+					return result;
+				} else {
+					if (mode != TRANSPORT_WATER) return result;
+				}
+			}
+			/* If we've not returned yet, there is a compatible
+			 * transport or water beneath, so we can add it to
+			 * result */
+			/* Why is this xor'd ? Can't it just be or'd? */
+			result ^= (GetBridgeAxis(tile) == AXIS_X ? 0x202 : 0x101);
+		}
+		return result;
 	} else {
 		assert(0); /* This should never occur */
 	}
@@ -1104,7 +1285,16 @@
 	if (new_player != OWNER_SPECTATOR) {
 		SetTileOwner(tile, new_player);
 	}	else {
-		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		if (IsBridge(tile) && IsBridgeMiddle(tile) && IsTransportUnderBridge(tile)) {
+			// the stuff BELOW the middle part is owned by the deleted player.
+			if (GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
+				SetClearUnderBridge(tile);
+			} else {
+				SetTileOwner(tile, OWNER_NONE);
+			}
+		} else {
+			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+		}
 	}
 }
 
@@ -1124,15 +1314,14 @@
 
 static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
 {
-	int z = GetSlopeZ(x, y) - v->z_pos;
-
-	if (myabs(z) > 2) return 8;
-
 	if (IsTunnel(tile)) {
+		int z = GetSlopeZ(x, y) - v->z_pos;
 		byte fc;
 		DiagDirection dir;
 		DiagDirection vdir;
 
+		if (myabs(z) > 2) return 8;
+
 		if (v->type == VEH_Train) {
 			fc = (x & 0xF) + (y << 4);
 
@@ -1193,53 +1382,30 @@
 			}
 		}
 	} else if (IsBridge(tile)) { // XXX is this necessary?
-		DiagDirection dir;
-
 		if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
-			/* modify speed of vehicle */
-			uint16 spd = _bridge[GetBridgeType(tile)].speed;
-
-			if (v->type == VEH_Road) spd *= 2;
-			if (v->cur_speed > spd) v->cur_speed = spd;
-		}
-
-		dir = GetBridgeRampDirection(tile);
-		if (DirToDiagDir(v->direction) == dir) {
-			switch (dir) {
-				default:
-				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;
+			if (IsBridgeRamp(tile) || v->z_pos > GetTileMaxZ(tile)) {
+				/* modify speed of vehicle */
+				uint16 spd = _bridge[GetBridgeType(tile)].speed;
+				if (v->type == VEH_Road) spd *= 2;
+				if (v->cur_speed > spd) v->cur_speed = spd;
 			}
-			if (v->type == VEH_Train) {
-				v->u.rail.track = 0x40;
-				CLRBIT(v->u.rail.flags, VRF_GOINGUP);
-				CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
-			} else {
-				v->u.road.state = 0xFF;
-			}
-			return 4;
-		} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
-			v->tile = tile;
-			if (v->type == VEH_Train) {
-				if (v->u.rail.track == 0x40) {
-					v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
-					return 4;
-				}
-			} else {
-				if (v->u.road.state == 0xFF) {
-					v->u.road.state = _road_exit_tunnel_state[dir];
-					v->u.road.frame = 0;
-					return 4;
-				}
-			}
-			return 0;
 		}
 	}
 	return 0;
 }
 
+TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v)
+{
+	TileIndex tile;
+	TileIndexDiff delta = (v->direction & 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
+	byte z = v->z_pos;
+
+	for (tile = v->tile;; tile += delta) {
+		if (IsTunnelTile(tile) && GetTileZ(tile) == z) break;
+	}
+	return tile;
+}
+
 const TileTypeProcs _tile_type_tunnelbridge_procs = {
 	DrawTile_TunnelBridge,					/* draw_tile_proc */
 	GetSlopeZ_TunnelBridge,					/* get_slope_z_proc */