(svn r5070) Merged the bridge branch
authorcelestar
Fri, 02 Jun 2006 13:05:41 +0000
changeset 3933 a5f08e17f4a0
parent 3932 882af4997b60
child 3934 6d178534fbaf
(svn r5070) Merged the bridge branch
-Feature: Bridges can now be placed above:
Any railway track combination (excluding depots and waypoints)
Any road combination (excluding depots)
Clear tiles (duh), including fields
Tunnel entrances
Bridge heads

Thanks to Tron for idea and implementation, KUDr for the yapf synchronization and many others for hours of testing

There are still a number of visual problems remaining, especially when electric railways are on or under the bridge.
DO NOT REPORT THOSE BUGS FOR THE TIME BEING please.
BUGS
ai/default/default.c
bridge.h
bridge_map.c
bridge_map.h
clear_cmd.c
elrail.c
landscape.c
misc.c
npf.c
openttd.c
pathfind.c
rail.c
rail_cmd.c
rail_map.h
road_cmd.c
road_map.c
roadveh_cmd.c
saveload.c
station_cmd.c
table/sprites.h
terraform_gui.c
town_cmd.c
train_cmd.c
tree_cmd.c
tunnelbridge_cmd.c
variables.h
vehicle.h
water_cmd.c
waypoint.c
yapf/follow_track.hpp
yapf/yapf.h
yapf/yapf_road.cpp
--- a/BUGS	Thu Jun 01 22:20:40 2006 +0000
+++ b/BUGS	Fri Jun 02 13:05:41 2006 +0000
@@ -1,7 +1,12 @@
-/* $Id */
+/* $Id$ */
 
 KNOWN BUGS / PROBLEMS:
 
+bridges:
+Graphical problems, especially in conjunction with signals and catenary
+
+electrified rails:
 Normal and elrail depots look the same. Use 'X' (transparent buildings)
    to distinguish between them
 Missing curors / icons for construction (currently using the conventional ones)
+
--- a/ai/default/default.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/ai/default/default.c	Fri Jun 02 13:05:41 2006 +0000
@@ -2158,9 +2158,7 @@
 				return false;
 			p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDir(p->ai.cur_dir_a));
 			return true;
-		}
-
-		if (IsBridgeRamp(tile)) {
+		} else {
 			// Check if the bridge points in the right direction.
 			// This is not really needed the first place AiRemoveTileAndGoForward is called.
 			if (DiagDirToAxis(GetBridgeRampDirection(tile)) != (p->ai.cur_dir_a & 1U)) return false;
@@ -3692,7 +3690,6 @@
 	} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 		if (!IsTileOwner(tile, _current_player) ||
 				!IsBridge(tile) ||
-				!IsBridgeRamp(tile) ||
 				GetBridgeTransportType(tile) != TRANSPORT_RAIL) {
 			return;
 		}
--- a/bridge.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/bridge.h	Fri Jun 02 13:05:41 2006 +0000
@@ -27,5 +27,6 @@
 extern Bridge _bridge[MAX_BRIDGES];
 
 uint GetBridgeFoundation(Slope tileh, Axis axis);
+uint SetSpeedLimitOnBridge(Vehicle *);
 
 #endif /* BRIDGE_H */
--- a/bridge_map.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/bridge_map.c	Fri Jun 02 13:05:41 2006 +0000
@@ -3,22 +3,25 @@
 #include "stdafx.h"
 #include "openttd.h"
 #include "bridge_map.h"
+#include "variables.h"
 
 
 TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
 {
 	TileIndexDiff delta = TileOffsByDir(dir);
 
-	assert(DiagDirToAxis(dir) == GetBridgeAxis(tile));
-
-	do {
-		tile += delta;
-	} while (!IsBridgeRamp(tile));
+	do { tile += delta; } while (IsBridgeAbove(tile) && IsBridgeOfAxis(tile, DiagDirToAxis(dir)));
 
 	return tile;
 }
 
 
+TileIndex GetNorthernBridgeEnd(TileIndex t)
+{
+	return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t))));
+}
+
+
 TileIndex GetSouthernBridgeEnd(TileIndex t)
 {
 	return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
@@ -27,11 +30,25 @@
 
 TileIndex GetOtherBridgeEnd(TileIndex tile)
 {
-	TileIndexDiff delta = TileOffsByDir(GetBridgeRampDirection(tile));
+	assert(IsBridgeTile(tile));
+	return GetBridgeEnd(tile, GetBridgeRampDirection(tile));
+}
 
-	do {
-		tile += delta;
-	} while (!IsBridgeRamp(tile));
+uint GetBridgeHeight(TileIndex tile, Axis a)
+{
+	uint h, f;
+	uint tileh = GetTileSlope(tile, &h);
 
-	return tile;
+	f = GetBridgeFoundation(tileh, a);
+
+	if (f) {
+		if (f < 15) {
+			h += TILE_HEIGHT;
+			tileh = SLOPE_FLAT;
+		} else {
+			tileh = _inclined_tileh[f - 15];
+		}
+	}
+
+	return h + TILE_HEIGHT;
 }
--- a/bridge_map.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/bridge_map.h	Fri Jun 02 13:05:41 2006 +0000
@@ -11,6 +11,9 @@
 #include "tile.h"
 
 
+void DrawBridgeMiddle(const TileInfo* ti); // XXX
+
+
 static inline bool IsBridge(TileIndex t)
 {
 	assert(IsTileType(t, MP_TUNNELBRIDGE));
@@ -23,28 +26,38 @@
 }
 
 
-static inline bool IsBridgeRamp(TileIndex t)
+static inline bool MayHaveBridgeAbove(TileIndex t)
 {
-	assert(IsBridgeTile(t));
-	return !HASBIT(_m[t].m5, 6);
-}
-
-static inline bool IsBridgeMiddle(TileIndex t)
-{
-	assert(IsBridgeTile(t));
-	return HASBIT(_m[t].m5, 6);
+	return
+		IsTileType(t, MP_CLEAR) ||
+		IsTileType(t, MP_RAILWAY) ||
+		IsTileType(t, MP_STREET) ||
+		IsTileType(t, MP_WATER) ||
+		IsTileType(t, MP_TUNNELBRIDGE);
 }
 
 
-/**
- * Determines which piece of a bridge is contained in the current tile
- * @param tile The tile to analyze
- * @return the piece
- */
-static inline uint GetBridgePiece(TileIndex t)
+static inline bool IsXBridgeAbove(TileIndex t)
 {
-	assert(IsBridgeMiddle(t));
-	return GB(_m[t].m2, 0, 4);
+	assert(MayHaveBridgeAbove(t));
+	return GB(_m[t].extra, 6, 1) != 0;
+}
+
+static inline bool IsYBridgeAbove(TileIndex t)
+{
+	assert(MayHaveBridgeAbove(t));
+	return GB(_m[t].extra, 7, 1) != 0;
+}
+
+static inline bool IsBridgeOfAxis(TileIndex t, Axis a)
+{
+	if (a == AXIS_X) return IsXBridgeAbove(t);
+	return IsYBridgeAbove(t);
+}
+
+static inline bool IsBridgeAbove(TileIndex t)
+{
+	return (IsXBridgeAbove(t) || IsYBridgeAbove(t));
 }
 
 
@@ -65,7 +78,6 @@
  */
 static inline DiagDirection GetBridgeRampDirection(TileIndex t)
 {
-	assert(IsBridgeRamp(t));
 	/* Heavy wizardry to convert the X/Y (bit 0) + N/S (bit 5) encoding of
 	 * bridges to a DiagDirection
 	 */
@@ -75,8 +87,9 @@
 
 static inline Axis GetBridgeAxis(TileIndex t)
 {
-	assert(IsBridgeMiddle(t));
-	return (Axis)GB(_m[t].m5, 0, 1);
+	static const Axis BridgeAxis[] = {AXIS_END, AXIS_X, AXIS_Y, AXIS_END};
+	assert(IsBridgeAbove(t));
+	return BridgeAxis[GB(_m[t].extra, 6, 2)];
 }
 
 
@@ -87,50 +100,17 @@
 }
 
 
-static inline bool IsClearUnderBridge(TileIndex t)
-{
-	assert(IsBridgeMiddle(t));
-	return GB(_m[t].m5, 3, 3) == 0;
-}
-
-static inline bool IsWaterUnderBridge(TileIndex t)
-{
-	assert(IsBridgeMiddle(t));
-	return GB(_m[t].m5, 3, 3) == 1;
-}
-
-
-static inline bool IsTransportUnderBridge(TileIndex t)
-{
-	assert(IsBridgeMiddle(t));
-	return HASBIT(_m[t].m5, 5);
-}
-
-static inline TransportType GetTransportTypeUnderBridge(TileIndex t)
-{
-	assert(IsTransportUnderBridge(t));
-	return (TransportType)GB(_m[t].m5, 3, 2);
-}
-
-static inline RoadBits GetRoadBitsUnderBridge(TileIndex t)
-{
-	assert(GetTransportTypeUnderBridge(t) == TRANSPORT_ROAD);
-	return GetBridgeAxis(t) == AXIS_X ? ROAD_Y : ROAD_X;
-}
-
-static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
-{
-	assert(GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL);
-	return GetBridgeAxis(t) == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X;
-}
-
-
 /**
  * Finds the end of a bridge in the specified direction starting at a middle tile
  */
 TileIndex GetBridgeEnd(TileIndex, DiagDirection);
 
 /**
+ * Finds the northern end of a bridge starting at a middle tile
+ */
+TileIndex GetNorthernBridgeEnd(TileIndex t);
+
+/**
  * Finds the southern end of a bridge starting at a middle tile
  */
 TileIndex GetSouthernBridgeEnd(TileIndex t);
@@ -141,38 +121,26 @@
  */
 TileIndex GetOtherBridgeEnd(TileIndex);
 
-uint GetBridgeHeight(TileIndex t);
+uint GetBridgeHeight(TileIndex tile, Axis a);
+uint GetBridgeFoundation(Slope tileh, Axis axis);
 
-static inline void SetClearUnderBridge(TileIndex t)
+static inline void ClearSingleBridgeMiddle(TileIndex t, Axis a)
 {
-	assert(IsBridgeMiddle(t));
-	SetTileOwner(t, OWNER_NONE);
-	SB(_m[t].m5, 3, 3, 0 << 2 | 0);
-	SB(_m[t].m3, 0, 4, 0);
+	assert(MayHaveBridgeAbove(t));
+	CLRBIT(_m[t].extra, 6 + a);
 }
 
-static inline void SetWaterUnderBridge(TileIndex t)
+
+static inline void ClearBridgeMiddle(TileIndex t)
 {
-	assert(IsBridgeMiddle(t));
-	SetTileOwner(t, OWNER_WATER);
-	SB(_m[t].m5, 3, 3, 0 << 2 | 1);
-	SB(_m[t].m3, 0, 4, 0);
+	ClearSingleBridgeMiddle(t, AXIS_X);
+	ClearSingleBridgeMiddle(t, AXIS_Y);
 }
 
-static inline void SetRailUnderBridge(TileIndex t, Owner o, RailType r)
+static inline void SetBridgeMiddle(TileIndex t, Axis a)
 {
-	assert(IsBridgeMiddle(t));
-	SetTileOwner(t, o);
-	SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_RAIL);
-	SB(_m[t].m3, 0, 4, r);
-}
-
-static inline void SetRoadUnderBridge(TileIndex t, Owner o)
-{
-	assert(IsBridgeMiddle(t));
-	SetTileOwner(t, o);
-	SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_ROAD);
-	SB(_m[t].m3, 0, 4, 0);
+	assert(MayHaveBridgeAbove(t));
+	SETBIT(_m[t].extra, 6 + a);
 }
 
 
@@ -200,26 +168,4 @@
 }
 
 
-static inline void MakeBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, TransportType tt)
-{
-	SetTileType(t, MP_TUNNELBRIDGE);
-	SetTileOwner(t, OWNER_NONE);
-	_m[t].m2 = bridgetype << 4 | piece;
-	_m[t].m3 = 0;
-	_m[t].m4 = 0;
-	_m[t].m5 = 1 << 7 | 1 << 6 | 0 << 5 | 0 << 3 | tt << 1 | a;
-}
-
-static inline void MakeRoadBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a)
-{
-	MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_ROAD);
-}
-
-static inline void MakeRailBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, RailType r)
-{
-	MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_RAIL);
-	SB(_m[t].m3, 4, 4, r);
-}
-
-
 #endif
--- a/clear_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/clear_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -11,6 +11,7 @@
 #include "viewport.h"
 #include "command.h"
 #include "tunnel_map.h"
+#include "bridge_map.h"
 #include "variables.h"
 #include "table/sprites.h"
 #include "unmovable_map.h"
@@ -259,6 +260,14 @@
 				} else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
 			}
 
+			if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
+				byte height = GetBridgeHeight(GetNorthernBridgeEnd(tile), GetBridgeAxis(tile));
+
+				height /= TILE_HEIGHT;
+
+				if (a >= height || b >= height || c >= height || d >= height) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+			}
+
 			if (direction == -1 && IsTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
 
 			_terraform_err_tile = 0;
@@ -501,6 +510,7 @@
 	}
 
 	DrawClearLandFence(ti);
+	DrawBridgeMiddle(ti);
 }
 
 static uint GetSlopeZ_Clear(const TileInfo* ti)
--- a/elrail.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/elrail.c	Fri Jun 02 13:05:41 2006 +0000
@@ -91,18 +91,10 @@
 				return DiagDirToAxis(GetTunnelDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
 			} else {
 				if (GetRailType(t) != RAILTYPE_ELECTRIC) return 0;
-				if (IsBridgeMiddle(t)) {
-					if (IsTransportUnderBridge(t) &&
-						GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL) {
-						return GetRailBitsUnderBridge(t);
-					} else {
-						return 0;
-					}
-				} else {
-					if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) *override = 1 << GetBridgeRampDirection(t);
-
-					return DiagDirToAxis(GetBridgeRampDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
+				if (override != NULL && DistanceMax(t, GetOtherBridgeEnd(t)) > 1) {
+					*override = 1 << GetBridgeRampDirection(t);
 				}
+				return DiagDirToAxis(GetBridgeRampDirection(t)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y;
 			}
 		case MP_STREET:
 			if (GetRoadTileType(t) != ROAD_TILE_CROSSING) return 0;
@@ -125,7 +117,7 @@
 static void AdjustTileh(TileIndex tile, Slope* tileh)
 {
 	if (IsTunnelTile(tile)) *tileh = SLOPE_FLAT;
-	if (IsBridgeTile(tile) && IsBridgeRamp(tile)) {
+	if (IsBridgeTile(tile)) {
 		if (*tileh != SLOPE_FLAT) {
 			*tileh = SLOPE_FLAT;
 		} else {
@@ -193,9 +185,10 @@
 		for (k = 0; k < NUM_TRACKS_AT_PCP; k++) {
 			/* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */
 			if (TrackSourceTile[i][k] == TS_NEIGHBOUR &&
-			    IsBridgeTile(neighbour) && IsBridgeRamp(neighbour) &&
-			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)
-			   ) continue;
+			    IsBridgeTile(neighbour) &&
+			    GetBridgeRampDirection(neighbour) == ReverseDiagDir(i)) {
+				continue;
+			}
 
 			/* We check whether the track in question (k) is present in the tile
 			   (TrackSourceTile) */
@@ -219,7 +212,7 @@
 
 		/* Read the foundataions if they are present, and adjust the tileh */
 		if (IsTileType(neighbour, MP_RAILWAY)) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]);
-		if (IsBridgeTile(neighbour) && IsBridgeRamp(neighbour)) {
+		if (IsBridgeTile(neighbour)) {
 			foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour)));
 		}
 
@@ -247,6 +240,14 @@
 		   Remove those (simply by ANDing with allowed, since these markers are never allowed) */
 		if ( (PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i];
 
+		if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
+			Track bridgetrack = GetBridgeAxis(ti->tile) == AXIS_X ? TRACK_X : TRACK_Y;
+			uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile), GetBridgeAxis(ti->tile));
+
+			if ((height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) &&
+			(i == PCPpositions[bridgetrack][0] || i == PCPpositions[bridgetrack][1])) SETBIT(OverridePCP, i);
+		}
+
 		if (PPPallowed[i] != 0 && HASBIT(PCPstatus, i) && !HASBIT(OverridePCP, i)) {
 			for (k = 0; k < DIR_END; k++) {
 				byte temp = PPPorder[i][GetTLG(ti->tile)][k];
@@ -279,12 +280,11 @@
 			const SortableSpriteStruct *sss;
 			int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; /* tileh for the slopes, 0 otherwise */
 
-			if ( /* We are not drawing a wire under a low bridge */
-					IsBridgeTile(ti->tile) &&
-					IsBridgeMiddle(ti->tile) &&
-					!(_display_opt & DO_TRANS_BUILDINGS) &&
-					GetBridgeHeight(ti->tile) <= TilePixelHeight(ti->tile)
-			   ) return;
+			if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile) && !(_display_opt & DO_TRANS_BUILDINGS)) {
+				uint height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile), GetBridgeAxis(ti->tile));
+
+				if (height <= TilePixelHeight(ti->tile) + TILE_HEIGHT) return;
+			}
 
 			assert(PCPconfig != 0); /* We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) */
 			assert(!IsSteepSlope(tileh[TS_HOME]));
@@ -320,30 +320,37 @@
 	}
 
 	AddSortableSpriteToDraw( sss->image, ti->x + sss->x_offset, ti->y + sss->y_offset,
-			sss->x_size, sss->y_size, sss->z_size, GetBridgeHeight(ti->tile) + sss->z_offset + 8);
+			sss->x_size, sss->y_size, sss->z_size, GetBridgeHeight(end, axis) + sss->z_offset);
 
 	/* Finished with wires, draw pylons */
 	/* every other tile needs a pylon on the northern end */
 	if (num % 2) {
 		if (axis == AXIS_X) {
-			AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT);
+			AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(end, axis));
 		} else {
-			AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT);
+			AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, GetBridgeHeight(end, axis));
 		}
 	}
 
 	/* need a pylon on the southern end of the bridge */
 	if (DistanceMax(ti->tile, start) == length) {
 		if (axis == AXIS_X) {
-			AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT);
+			AddSortableSpriteToDraw( pylons_bridge[0 + HASBIT(tlg, 0)], ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, GetBridgeHeight(end, axis));
 		} else {
-			AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, GetBridgeHeight(ti->tile) + TILE_HEIGHT);
+			AddSortableSpriteToDraw( pylons_bridge[2 + HASBIT(tlg, 1)], ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, GetBridgeHeight(end, axis));
 		}
 	}
 }
 
 void DrawCatenary(const TileInfo *ti)
 {
+	if (MayHaveBridgeAbove(ti->tile) && IsBridgeAbove(ti->tile)) {
+		TileIndex head = GetNorthernBridgeEnd(ti->tile);
+
+		if (GetBridgeTransportType(head) == TRANSPORT_RAIL && GetRailType(head) == RAILTYPE_ELECTRIC) {
+			DrawCatenaryOnBridge(ti);
+		}
+	}
 	switch (GetTileType(ti->tile)) {
 		case MP_RAILWAY:
 			if (GetRailTileType(ti->tile) == RAIL_TILE_DEPOT_WAYPOINT && GetRailTileSubtype(ti->tile) == RAIL_SUBTYPE_DEPOT) {
@@ -354,9 +361,8 @@
 			}
 			/* Fall through */
 		case MP_TUNNELBRIDGE:
-			if (IsBridgeTile(ti->tile) && IsBridgeMiddle(ti->tile) && GetRailTypeOnBridge(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenaryOnBridge(ti);
-			/* Fall further */
-		case MP_STREET: case MP_STATION:
+		case MP_STREET:
+		case MP_STATION:
 			DrawCatenaryRailway(ti);
 			break;
 		default:
--- a/landscape.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/landscape.c	Fri Jun 02 13:05:41 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "bridge_map.h"
 #include "clear_map.h"
 #include "functions.h"
 #include "map.h"
@@ -387,6 +388,8 @@
 		for (x = 0; x < maxx; x++) {
 			MakeClear(sizex * y + x, CLEAR_GRASS, 3);
 			SetTileHeight(sizex * y + x, 0);
+			_m[sizex * y + x].extra = 0;
+			ClearBridgeMiddle(sizex * y + x);
 		}
 		MakeVoid(sizex * y + x);
 	}
--- a/misc.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/misc.c	Fri Jun 02 13:05:41 2006 +0000
@@ -859,16 +859,26 @@
 	uint size = MapSize();
 	uint i;
 
-	for (i = 0; i != size;) {
-		uint8 buf[1024];
-		uint j;
+	if (CheckSavegameVersion(29)) {
+		for (i = 0; i != size;) {
+			uint8 buf[1024];
+			uint j;
 
-		SlArray(buf, lengthof(buf), SLE_UINT8);
-		for (j = 0; j != lengthof(buf); j++) {
-			_m[i++].extra = GB(buf[j], 0, 2);
-			_m[i++].extra = GB(buf[j], 2, 2);
-			_m[i++].extra = GB(buf[j], 4, 2);
-			_m[i++].extra = GB(buf[j], 6, 2);
+			SlArray(buf, lengthof(buf), SLE_UINT8);
+			for (j = 0; j != lengthof(buf); j++) {
+				_m[i++].extra = GB(buf[j], 0, 2);
+				_m[i++].extra = GB(buf[j], 2, 2);
+				_m[i++].extra = GB(buf[j], 4, 2);
+				_m[i++].extra = GB(buf[j], 6, 2);
+			}
+		}
+	} else {
+		for (i = 0; i != size;) {
+			byte buf[4096];
+			uint j;
+
+			SlArray(buf, lengthof(buf), SLE_UINT8);
+			for (j = 0; j != lengthof(buf); j++) _m[i++].extra = buf[j];
 		}
 	}
 }
@@ -878,17 +888,12 @@
 	uint size = MapSize();
 	uint i;
 
-	SlSetLength(size / 4);
+	SlSetLength(size);
 	for (i = 0; i != size;) {
-		uint8 buf[1024];
+		uint8 buf[4096];
 		uint j;
 
-		for (j = 0; j != lengthof(buf); j++) {
-			buf[j]  = _m[i++].extra << 0;
-			buf[j] |= _m[i++].extra << 2;
-			buf[j] |= _m[i++].extra << 4;
-			buf[j] |= _m[i++].extra << 6;
-		}
+		for (j = 0; j != lengthof(buf); j++) buf[j] = _m[i++].extra;
 		SlArray(buf, lengthof(buf), SLE_UINT8);
 	}
 }
--- a/npf.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/npf.c	Fri Jun 02 13:05:41 2006 +0000
@@ -479,17 +479,7 @@
 
 		case MP_TUNNELBRIDGE:
 			if ((IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) ||
-					(IsBridge(tile) && (
-						(
-							IsBridgeRamp(tile) &&
-							GetBridgeTransportType(tile) == TRANSPORT_RAIL
-						) || (
-							IsBridgeMiddle(tile) &&
-							IsTransportUnderBridge(tile) &&
-							GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL &&
-							GetBridgeAxis(tile) != DiagDirToAxis(enterdir)
-						)
-					))) {
+					(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL)) {
 				return IsTileOwner(tile, owner);
 			}
 			break;
@@ -516,6 +506,7 @@
 	int i;
 	TrackdirBits trackdirbits, ts;
 	TransportType type = aystar->user_data[NPF_TYPE];
+	bool override_dst_check = false;
 	/* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */
 	aystar->num_neighbours = 0;
 	DEBUG(npf, 4)("Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile);
@@ -526,6 +517,10 @@
 		 * otherwise we wouldn't have got here. It is also facing us,
 		 * so we should skip it's body */
 		dst_tile = GetOtherTunnelEnd(src_tile);
+		override_dst_check = true;
+	} else if (IsBridgeTile(src_tile) && GetBridgeRampDirection(src_tile) == src_exitdir) {
+		dst_tile = GetOtherBridgeEnd(src_tile);
+		override_dst_check = true;
 	} else if (type != TRANSPORT_WATER && (IsRoadStopTile(src_tile) || IsTileDepotType(src_tile, type))) {
 		/* This is a road station or a train or road depot. We can enter and exit
 		 * those from one side only. Trackdirs don't support that (yet), so we'll
@@ -573,8 +568,14 @@
 	/* I can't enter a tunnel entry/exit tile from a tile above the tunnel. Note
 	 * that I can enter the tunnel from a tile below the tunnel entrance. This
 	 * solves the problem of vehicles wanting to drive off a tunnel entrance */
-	if (IsTunnelTile(dst_tile) && GetTileZ(dst_tile) < GetTileZ(src_tile)) {
-		return;
+	if (!override_dst_check) {
+		if (IsTileType(dst_tile, MP_TUNNELBRIDGE)) {
+			if (IsTunnel(dst_tile)) {
+				if (GetTunnelDirection(dst_tile) != src_exitdir) return;
+			} else {
+				if (GetBridgeRampDirection(dst_tile) != src_exitdir) return;
+			}
+		}
 	}
 
 	/* check correct rail type (mono, maglev, etc) */
--- a/openttd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/openttd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -49,6 +49,12 @@
 #include "yapf/yapf.h"
 #include "settings.h"
 
+#include "bridge_map.h"
+#include "clear_map.h"
+#include "rail_map.h"
+#include "road_map.h"
+#include "water_map.h"
+
 #include <stdarg.h>
 
 void GenerateWorld(int mode, uint size_x, uint size_y);
@@ -1256,6 +1262,72 @@
 		}
 	}
 
+	if (CheckSavegameVersion(29)) {
+		TileIndex map_end = MapSize();
+		TileIndex tile;
+		Vehicle* v;
+
+		for (tile = 0; tile != map_end; tile++) {
+			if (MayHaveBridgeAbove(tile)) ClearBridgeMiddle(tile);
+			if (IsTileType(tile, MP_TUNNELBRIDGE) &&
+					_m[tile].m5 & 0x80 && // bridge
+					_m[tile].m5 & 0x40) { // middle part
+				Axis axis = (Axis)GB(_m[tile].m5, 0, 1);
+
+				if (_m[tile].m5 & 0x20) { // transport route under bridge?
+					if (GB(_m[tile].m5, 3, 2) == TRANSPORT_RAIL) {
+						MakeRailNormal(
+							tile,
+							GetTileOwner(tile),
+							axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X,
+							GetRailType(tile)
+						);
+					} else {
+						uint town = IsTileOwner(tile, OWNER_TOWN) ? ClosestTownFromTile(tile, (uint)-1)->index : 0;
+
+						MakeRoadNormal(
+							tile,
+							GetTileOwner(tile),
+							axis == AXIS_X ? ROAD_Y : ROAD_X,
+							town
+						);
+					}
+				} else {
+					if (GB(_m[tile].m5, 3, 2) == 0) {
+						MakeClear(tile, CLEAR_GRASS, 3);
+					} else {
+						MakeWater(tile);
+					}
+				}
+				SetBridgeMiddle(tile, axis);
+			}
+		}
+
+		FOR_ALL_VEHICLES(v) {
+			if (v->type != VEH_Train && v->type != VEH_Road) continue;
+			if (IsBridgeTile(v->tile)) {
+				DiagDirection dir = GetBridgeRampDirection(v->tile);
+
+				if (dir != DirToDiagDir(v->direction)) continue;
+				switch (dir) {
+					default:
+					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0) continue;
+					case DIAGDIR_SE: if ((v->y_pos & 0xF) != 15) continue;
+					case DIAGDIR_SW: if ((v->x_pos & 0xF) != 15) continue;
+					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0) continue;
+				}
+			} else if (v->z_pos <= GetSlopeZ(v->x_pos, v->y_pos)) {
+				continue;
+			}
+			if (!IsBridgeTile(v->tile)) v->tile = GetNorthernBridgeEnd(v->tile);
+			if (v->type == VEH_Train) {
+				v->u.rail.track = 0x40;
+			} else {
+				v->u.road.state = 0xFF;
+			}
+		}
+	}
+
 	/* Elrails got added in rev 24 */
 	if (CheckSavegameVersion(24)) {
 		Vehicle* v;
@@ -1306,15 +1378,6 @@
 						}
 					} else {
 						if (GetBridgeTransportType(t) == TRANSPORT_RAIL) {
-							if (IsBridgeRamp(t)) {
-								SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
-							} else {
-								SetRailTypeOnBridge(t, UpdateRailType(GetRailTypeOnBridge(t), min_rail));
-							}
-						}
-						if (IsBridgeMiddle(t) &&
-								IsTransportUnderBridge(t) &&
-								GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL) {
 							SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 						}
 					}
--- a/pathfind.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/pathfind.c	Fri Jun 02 13:05:41 2006 +0000
@@ -256,21 +256,27 @@
 	RememberData rd;
 	TileIndex tile_org = tile;
 
-	// check if the old tile can be left at that direction
-	if (tpf->tracktype == TRANSPORT_ROAD) {
-		// road stops and depots now have a track (r4419)
-		// don't enter road stop from the back
-		if (IsRoadStopTile(tile) && GetRoadStopDir(tile) != direction) return;
-		// don't enter road depot from the back
-		if (IsTileDepotType(tile, TRANSPORT_ROAD) && GetRoadDepotDirection(tile) != direction) return;
-	}
-
-	if (IsTunnelTile(tile)) {
-		if (GetTunnelDirection(tile) != direction ||
-				GetTunnelTransportType(tile) != tpf->tracktype) {
-			return;
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		if (IsTunnel(tile)) {
+			if (GetTunnelDirection(tile) != direction ||
+					GetTunnelTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+			tile = SkipToEndOfTunnel(tpf, tile, direction);
+		} else {
+			TileIndex tile_end;
+			if (GetBridgeRampDirection(tile) != direction ||
+					GetBridgeTransportType(tile) != tpf->tracktype) {
+				return;
+			}
+			//fprintf(stderr, "%s: Planning over bridge\n", __func__);
+			// TODO doesn't work - WHAT doesn't work?
+			TPFSetTileBit(tpf, tile, 14);
+			tile_end = GetOtherBridgeEnd(tile);
+			tpf->rd.cur_length += DistanceManhattan(tile, tile_end);
+			tile = tile_end;
+			TPFSetTileBit(tpf, tile, 14);
 		}
-		tile = SkipToEndOfTunnel(tpf, tile, direction);
 	}
 	tile += TileOffsByDir(direction);
 
@@ -281,11 +287,7 @@
 
 		if (IsTileType(tile_org, MP_RAILWAY) || IsTileType(tile_org, MP_STATION) || IsTileType(tile_org, MP_TUNNELBRIDGE))
 			if (IsTileType(tile, MP_RAILWAY) || IsTileType(tile, MP_STATION) || IsTileType(tile, MP_TUNNELBRIDGE))
-				/* Check if we are on a bridge (middle parts don't have an owner */
-				if (!IsBridgeTile(tile) || !IsBridgeMiddle(tile))
-					if (!IsBridgeTile(tile_org) || !IsBridgeMiddle(tile_org))
-						if (GetTileOwner(tile_org) != GetTileOwner(tile))
-							return;
+				if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
 	}
 
 	// check if the new tile can be entered from that direction
@@ -673,7 +675,6 @@
 	uint track;
 	TileIndex tile_org;
 	StackedItem si;
-	FindLengthOfTunnelResult flotr;
 	int estimation;
 
 
@@ -711,22 +712,40 @@
 start_at:
 		// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
 		//   need to find the exit of the tunnel.
-		if (IsTunnelTile(tile) &&
-				GetTunnelDirection(tile) != ReverseDiagDir(direction)) {
-			/* We are not just driving out of the tunnel */
-			if (GetTunnelDirection(tile) != direction ||
-					GetTunnelTransportType(tile) != tpf->tracktype) {
-				// We are not driving into the tunnel, or it is an invalid tunnel
-				continue;
+		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+			if (IsTunnel(tile)) {
+				if (GetTunnelDirection(tile) != ReverseDiagDir(direction)) {
+					FindLengthOfTunnelResult flotr;
+
+					/* We are not just driving out of the tunnel */
+					if (GetTunnelDirection(tile) != direction ||
+							GetTunnelTransportType(tile) != tpf->tracktype) {
+						// We are not driving into the tunnel, or it is an invalid tunnel
+						continue;
+					}
+					if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
+						bits = 0;
+						break;
+					}
+					flotr = FindLengthOfTunnel(tile, direction);
+					si.cur_length += flotr.length * DIAG_FACTOR;
+					tile = flotr.tile;
+					// tile now points to the exit tile of the tunnel
+				}
+			} else {
+				TileIndex tile_end;
+				if (GetBridgeRampDirection(tile) != ReverseDiagDir(direction)) {
+					// We are not just leaving the bridge
+					if (GetBridgeRampDirection(tile) != direction ||
+							GetBridgeTransportType(tile) != tpf->tracktype) {
+						// Not entering the bridge or not compatible
+						continue;
+					}
+				}
+				tile_end = GetOtherBridgeEnd(tile);
+				si.cur_length += DistanceManhattan(tile, tile_end) * DIAG_FACTOR;
+				tile = tile_end;
 			}
-			if (!HASBIT(tpf->railtypes, GetRailType(tile))) {
-				bits = 0;
-				break;
-			}
-			flotr = FindLengthOfTunnel(tile, direction);
-			si.cur_length += flotr.length * DIAG_FACTOR;
-			tile = flotr.tile;
-			// tile now points to the exit tile of the tunnel
 		}
 
 		// This is a special loop used to go through
@@ -754,13 +773,9 @@
 				// Check that the tile contains exactly one track
 				if (bits == 0 || KILL_FIRST_BIT(bits) != 0) break;
 
-				/* Check the rail type only if the train is *NOT* on top of
-				 * a bridge. */
-				if (!(IsBridgeTile(tile) && IsBridgeMiddle(tile) && GetBridgeAxis(tile) == DiagDirToAxis(direction))) {
-					if (IsTileType(tile, MP_STREET) ? !HASBIT(tpf->railtypes, GetRailTypeCrossing(tile)) : !HASBIT(tpf->railtypes, GetRailType(tile))) {
-						bits = 0;
-						break;
-					}
+				if (IsTileType(tile, MP_STREET) ? !HASBIT(tpf->railtypes, GetRailTypeCrossing(tile)) : !HASBIT(tpf->railtypes, GetRailType(tile))) {
+					bits = 0;
+					break;
 				}
 
 				///////////////////
--- a/rail.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/rail.c	Fri Jun 02 13:05:41 2006 +0000
@@ -104,7 +104,6 @@
 
 RailType GetTileRailType(TileIndex tile, Trackdir trackdir)
 {
-	DiagDirection exitdir = TrackdirToExitdir(trackdir);
 	switch (GetTileType(tile)) {
 		case MP_RAILWAY:
 			return GetRailType(tile);
@@ -124,21 +123,8 @@
 					return GetRailType(tile);
 				}
 			} else {
-				if (IsBridgeRamp(tile)) {
-					if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
-						return GetRailType(tile);
-					}
-				} else {
-					if (GetBridgeAxis(tile) == DiagDirToAxis(exitdir)) {
-						if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
-							return GetRailTypeOnBridge(tile);
-						}
-					} else {
-						if (IsTransportUnderBridge(tile) &&
-								GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
-							return GetRailType(tile);
-						}
-					}
+				if (GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
+					return GetRailType(tile);
 				}
 			}
 			break;
--- a/rail_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/rail_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -231,29 +231,6 @@
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
 	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-			if (!IsBridge(tile) ||
-					!IsBridgeMiddle(tile) ||
-					(GetBridgeAxis(tile) == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X) != trackbit) {
-				// Get detailed error message
-				return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			}
-
-			if (IsClearUnderBridge(tile)) {
-				ret = CheckRailSlope(tileh, trackbit, 0, tile);
-				if (CmdFailed(ret)) return ret;
-				cost += ret;
-
-				if (flags & DC_EXEC) SetRailUnderBridge(tile, _current_player, p1);
-			} else if (IsTransportUnderBridge(tile) &&
-					GetTransportTypeUnderBridge(tile) == TRANSPORT_RAIL) {
-				return_cmd_error(STR_1007_ALREADY_BUILT);
-			} else {
-				// Get detailed error message
-				return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-			}
-			break;
-
 		case MP_RAILWAY:
 			if (!CheckTrackCombination(tile, trackbit, flags) ||
 					!EnsureNoVehicle(tile)) {
@@ -341,20 +318,6 @@
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
 	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-			if (!IsBridge(tile) ||
-					!IsBridgeMiddle(tile) ||
-					!IsTransportUnderBridge(tile) ||
-					GetTransportTypeUnderBridge(tile) != TRANSPORT_RAIL ||
-					GetRailBitsUnderBridge(tile) != trackbit ||
-					(_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
-					!EnsureNoVehicleOnGround(tile)) {
-				return CMD_ERROR;
-			}
-
-			if (flags & DC_EXEC) SetClearUnderBridge(tile);
-			break;
-
 		case MP_STREET: {
 			if (!IsLevelCrossing(tile) ||
 					GetCrossingRailBits(tile) != trackbit ||
@@ -591,6 +554,8 @@
 	if (CmdFailed(ret)) return CMD_ERROR;
 	cost = ret;
 
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
 	d = AllocateDepot();
 	if (d == NULL) return CMD_ERROR;
 
@@ -1416,6 +1381,7 @@
 			);
 		}
 	}
+	DrawBridgeMiddle(ti);
 }
 
 void DrawTrainDepotSprite(int x, int y, int image, RailType railtype)
@@ -1525,19 +1491,11 @@
 static void *SignalVehicleCheckProc(Vehicle *v, void *data)
 {
 	const SignalVehicleCheckStruct* dest = data;
-	TileIndex tile;
 
 	if (v->type != VEH_Train) return NULL;
 
-	/* Find the tile outside the tunnel, for signalling */
-	if (v->u.rail.track == 0x40) {
-		tile = GetVehicleOutOfTunnelTile(v);
-	} else {
-		tile = v->tile;
-	}
-
 	/* Wrong tile, or no train? Not a match */
-	if (tile != dest->tile) return NULL;
+	if (v->tile != dest->tile) return NULL;
 
 	/* Are we on the same piece of track? */
 	if (dest->track & (v->u.rail.track + (v->u.rail.track << 8))) return v;
@@ -1553,15 +1511,18 @@
 	dest.tile = tile;
 	dest.track = track;
 
-	/** @todo "Hackish" fix for the tunnel problems. This is needed because a tunnel
-	 * is some kind of invisible black hole, and there is some special magic going
-	 * on in there. This 'workaround' can be removed once the maprewrite is done.
-	 */
-	if (IsTunnelTile(tile)) {
-		// It is a tunnel we're checking, we need to do some special stuff
-		// because VehicleFromPos will not find the vihicle otherwise
-		TileIndex end = GetOtherTunnelEnd(tile);
-		DiagDirection direction = GetTunnelDirection(tile);
+	/* Locate vehicles in tunnels or on bridges */
+	if (IsTunnelTile(tile) || IsBridgeTile(tile)) {
+		TileIndex end;
+		DiagDirection direction;
+
+		if (IsTunnelTile(tile)) {
+			end = GetOtherTunnelEnd(tile);
+			direction = GetTunnelDirection(tile);
+		} else {
+			end = GetOtherBridgeEnd(tile);
+			direction = GetBridgeRampDirection(tile);
+		}
 
 		dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible)
 
@@ -1571,9 +1532,9 @@
 		// check for a vehicle with that trackdir on the end tile of the tunnel
 		if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
 
-		// now check all tiles from start to end for a "hidden" vehicle
+		// now check all tiles from start to end for a warping vehicle
 		// NOTE: the hashes for tiles may overlap, so this could maybe be optimised a bit by not checking every tile?
-		dest.track = 0x40; // trackbit for vehicles "hidden" inside a tunnel
+		dest.track = 0x40;
 		for (; tile != end; tile += TileOffsByDir(direction)) {
 			if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL)
 				return true;
--- a/rail_map.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/rail_map.h	Fri Jun 02 13:05:41 2006 +0000
@@ -81,11 +81,6 @@
 	return (RailType)GB(_m[t].m4, 0, 4);
 }
 
-static inline RailType GetRailTypeOnBridge(TileIndex t)
-{
-	return (RailType)GB(_m[t].m3, 4, 4);
-}
-
 static inline void SetRailType(TileIndex t, RailType r)
 {
 	SB(_m[t].m3, 0, 4, r);
@@ -97,11 +92,6 @@
 	SB(_m[t].m4, 0, 4, r);
 }
 
-static inline void SetRailTypeOnBridge(TileIndex t, RailType r)
-{
-	SB(_m[t].m3, 4, 4, r);
-}
-
 
 /** These are used to specify a single track.
  * Can be translated to a trackbit with TrackToTrackbit */
--- a/road_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/road_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -108,97 +108,70 @@
 	if (p1 >> 4) return CMD_ERROR;
 	pieces = p1;
 
-	if (!IsTileType(tile, MP_STREET) && !IsTileType(tile, MP_TUNNELBRIDGE)) return CMD_ERROR;
+	if (!IsTileType(tile, MP_STREET)) return CMD_ERROR;
 
 	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
 
 	if (owner == OWNER_TOWN && _game_mode != GM_EDITOR) {
-		if (IsTileType(tile, MP_TUNNELBRIDGE)) { // index of town is not saved for bridge (no space)
-			t = ClosestTownFromTile(tile, _patches.dist_local_authority);
-		} else {
-			t = GetTownByTile(tile);
-		}
+		t = GetTownByTile(tile);
 	} else {
 		t = NULL;
 	}
 
 	if (!CheckAllowRemoveRoad(tile, pieces, &edge_road)) return CMD_ERROR;
 
-	switch (GetTileType(tile)) {
-		case MP_TUNNELBRIDGE:
-			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
+	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 
-			if (!IsBridge(tile) ||
-					!IsBridgeMiddle(tile) ||
-					!IsTransportUnderBridge(tile) ||
-					GetTransportTypeUnderBridge(tile) != TRANSPORT_ROAD ||
-					(pieces & ComplementRoadBits(GetRoadBitsUnderBridge(tile))) != 0) {
+	// check if you're allowed to remove the street owned by a town
+	// removal allowance depends on difficulty setting
+	if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
+
+	switch (GetRoadTileType(tile)) {
+		case ROAD_TILE_NORMAL: {
+			RoadBits present = GetRoadBits(tile);
+			RoadBits c = pieces;
+
+			if (GetTileSlope(tile, NULL) != SLOPE_FLAT  &&
+					(present == ROAD_Y || present == ROAD_X)) {
+				c |= (c & 0xC) >> 2;
+				c |= (c & 0x3) << 2;
+			}
+
+			// limit the bits to delete to the existing bits.
+			c &= present;
+			if (c == 0) return CMD_ERROR;
+
+			if (flags & DC_EXEC) {
+				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
+
+				present ^= c;
+				if (present == 0) {
+					DoClearSquare(tile);
+				} else {
+					SetRoadBits(tile, present);
+					MarkTileDirtyByTile(tile);
+				}
+			}
+			return CountRoadBits(c) * _price.remove_road;
+		}
+
+		case ROAD_TILE_CROSSING: {
+			if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
 				return CMD_ERROR;
 			}
 
 			if (flags & DC_EXEC) {
 				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
-				SetClearUnderBridge(tile);
+
+				MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
 				MarkTileDirtyByTile(tile);
 			}
 			return _price.remove_road * 2;
-
-		case MP_STREET:
-			if (!EnsureNoVehicle(tile)) return CMD_ERROR;
-
-			// check if you're allowed to remove the street owned by a town
-			// removal allowance depends on difficulty setting
-			if (!CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
-
-			switch (GetRoadTileType(tile)) {
-				case ROAD_TILE_NORMAL: {
-					RoadBits present = GetRoadBits(tile);
-					RoadBits c = pieces;
-
-					if (GetTileSlope(tile, NULL) != SLOPE_FLAT &&
-							(present == ROAD_Y || present == ROAD_X)) {
-						c |= (c & 0xC) >> 2;
-						c |= (c & 0x3) << 2;
-					}
-
-					// limit the bits to delete to the existing bits.
-					c &= present;
-					if (c == 0) return CMD_ERROR;
-
-					if (flags & DC_EXEC) {
-						ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
+		}
 
-						present ^= c;
-						if (present == 0) {
-							DoClearSquare(tile);
-						} else {
-							SetRoadBits(tile, present);
-							MarkTileDirtyByTile(tile);
-						}
-					}
-					return CountRoadBits(c) * _price.remove_road;
-				}
-
-				case ROAD_TILE_CROSSING: {
-					if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) {
-						return CMD_ERROR;
-					}
-
-					if (flags & DC_EXEC) {
-						ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
-
-						MakeRailNormal(tile, GetTileOwner(tile), GetCrossingRailBits(tile), GetRailTypeCrossing(tile));
-						MarkTileDirtyByTile(tile);
-					}
-					return _price.remove_road * 2;
-				}
-
-				default:
-				case ROAD_TILE_DEPOT:
-					return CMD_ERROR;
-			}
-
-		default: return CMD_ERROR;
+		case ROAD_TILE_DEPOT:
+		default:
+			return CMD_ERROR;
 	}
 }
 
@@ -348,37 +321,6 @@
 			return _price.build_road * 2;
 		}
 
-		case MP_TUNNELBRIDGE:
-			/* check for flat land */
-			if (IsSteepSlope(tileh)) {
-				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-			}
-
-			if (!IsBridge(tile) || !IsBridgeMiddle(tile)) goto do_clear;
-
-			/* only allow roads pertendicular to bridge */
-			if ((pieces & (GetBridgeAxis(tile) == AXIS_X ? ROAD_X : ROAD_Y)) != 0) {
-				goto do_clear;
-			}
-
-			/* check if clear land under bridge */
-			if (IsTransportUnderBridge(tile)) {
-				switch (GetTransportTypeUnderBridge(tile)) {
-					case TRANSPORT_ROAD: return_cmd_error(STR_1007_ALREADY_BUILT);
-					default: return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
-				}
-			} else {
-				if (IsWaterUnderBridge(tile)) {
-					return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
-				}
-			}
-
-			if (flags & DC_EXEC) {
-				SetRoadUnderBridge(tile, _current_player);
-				MarkTileDirtyByTile(tile);
-			}
-			return _price.build_road * 2;
-
 		default:
 do_clear:;
 			ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
@@ -575,6 +517,8 @@
 	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(cost)) return CMD_ERROR;
 
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
 	dep = AllocateDepot();
 	if (dep == NULL) return CMD_ERROR;
 
@@ -798,6 +742,7 @@
 			break;
 		}
 	}
+	DrawBridgeMiddle(ti);
 }
 
 void DrawRoadDepotSprite(int x, int y, int image)
--- a/road_map.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/road_map.c	Fri Jun 02 13:05:41 2006 +0000
@@ -27,22 +27,12 @@
 			return DiagDirToRoadBits(GetRoadStopDir(tile));
 
 		case MP_TUNNELBRIDGE:
-			if (IsBridge(tile)) {
-				if (IsBridgeMiddle(tile)) {
-					if (!IsTransportUnderBridge(tile) ||
-							GetBridgeTransportType(tile) != TRANSPORT_ROAD) {
-						return 0;
-					}
-					return GetRoadBitsUnderBridge(tile);
-				} else {
-					// ending
-					if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
-					return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
-				}
-			} else {
-				// tunnel
+			if (IsTunnel(tile)) {
 				if (GetTunnelTransportType(tile) != TRANSPORT_ROAD) return 0;
 				return DiagDirToRoadBits(ReverseDiagDir(GetTunnelDirection(tile)));
+			} else {
+				if (GetBridgeTransportType(tile) != TRANSPORT_ROAD) return 0;
+				return DiagDirToRoadBits(ReverseDiagDir(GetBridgeRampDirection(tile)));
 			}
 
 		default: return 0;
--- a/roadveh_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/roadveh_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -20,7 +20,9 @@
 #include "player.h"
 #include "sound.h"
 #include "depot.h"
+#include "bridge.h"
 #include "tunnel_map.h"
+#include "bridge_map.h"
 #include "vehicle_gui.h"
 #include "newgrf_engine.h"
 #include "yapf/yapf.h"
@@ -313,8 +315,6 @@
 {
 	TileIndex tile = v->tile;
 
-	if (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v);
-
 	if (_patches.yapf.road_use_yapf) {
 		Depot* ret = YapfFindNearestRoadDepot(v);
 		return ret;
@@ -411,14 +411,19 @@
 
 	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
 
-	if (v->vehstatus & (VS_HIDDEN | VS_STOPPED) ||
+	if (v->vehstatus & VS_STOPPED ||
 			v->u.road.crashed_ctr != 0 ||
 			v->breakdown_ctr != 0 ||
 			v->u.road.overtaking != 0 ||
+			v->u.road.state == 255 ||
+			v->u.road.state == 254 ||
 			v->cur_speed < 5) {
 		return CMD_ERROR;
 	}
 
+	if (IsTunnelTile(v->tile) && DirToDiagDir(v->direction) == GetTunnelDirection(v->tile)) return CMD_ERROR;
+	if (IsBridgeTile(v->tile) && DirToDiagDir(v->direction) == GetBridgeRampDirection(v->tile)) return CMD_ERROR;
+
 	if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
 
 	return 0;
@@ -485,11 +490,9 @@
 	byte new_z, old_z;
 
 	// need this hint so it returns the right z coordinate on bridges.
-	_get_z_hint = v->z_pos;
 	v->x_pos = x;
 	v->y_pos = y;
 	new_z = GetSlopeZ(x, y);
-	_get_z_hint = 0;
 
 	old_z = v->z_pos;
 	v->z_pos = new_z;
@@ -824,6 +827,7 @@
 
 	// Clamp
 	spd = min(spd, v->max_speed);
+	if (v->u.road.state == 255) spd = min(spd, SetSpeedLimitOnBridge(v));
 
 	//updates statusbar only if speed have changed to save CPU time
 	if (spd != v->cur_speed) {
@@ -1285,8 +1289,7 @@
 			return;
 		}
 
-		if (IsTunnelTile(gp.new_tile) &&
-				VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
+		if ((IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) && VehicleEnterTile(v, gp.new_tile, gp.x, gp.y) & 4) {
 			//new_dir = RoadGetNewDirection(v, gp.x, gp.y)
 			v->cur_image = GetRoadVehImage(v, v->direction);
 			UpdateRoadVehDeltaXY(v);
@@ -1297,6 +1300,7 @@
 		v->x_pos = gp.x;
 		v->y_pos = gp.y;
 		VehiclePositionChanged(v);
+		if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
 		return;
 	}
 
--- a/saveload.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/saveload.c	Fri Jun 02 13:05:41 2006 +0000
@@ -30,7 +30,7 @@
 #include "variables.h"
 #include <setjmp.h>
 
-const uint16 SAVEGAME_VERSION = 28;
+const uint16 SAVEGAME_VERSION = 29;
 uint16 _sl_version;       /// the major savegame version identifier
 byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 
--- a/station_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/station_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -5,6 +5,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "bridge_map.h"
 #include "debug.h"
 #include "functions.h"
 #include "station_map.h"
@@ -782,6 +783,10 @@
 	int flat_z;
 
 	BEGIN_TILE_LOOP(tile_cur, w, h, tile)
+		if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) {
+			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+		}
+
 		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;
 
 		tileh = GetTileSlope(tile_cur, &z);
--- a/table/sprites.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/table/sprites.h	Fri Jun 02 13:05:41 2006 +0000
@@ -708,6 +708,27 @@
 	SPR_BTTUB_X_RAIL_REAR_BEG   = 2569,
 	SPR_BTTUB_X_RAIL_REAR_MID   = 2570,
 	SPR_BTTUB_X_RAIL_REAR_END   = 2571,
+	SPR_BTTUB_Y_RAIL_REAR_BEG   = 2572,
+	SPR_BTTUB_Y_RAIL_REAR_MID   = 2573,
+	SPR_BTTUB_Y_RAIL_REAR_END   = 2574,
+	SPR_BTTUB_X_ROAD_REAR_BEG   = 2575,
+	SPR_BTTUB_X_ROAD_REAR_MID   = 2576,
+	SPR_BTTUB_X_ROAD_REAR_END   = 2577,
+	SPR_BTTUB_Y_ROAD_REAR_BEG   = 2578,
+	SPR_BTTUB_Y_ROAD_REAR_MID   = 2579,
+	SPR_BTTUB_Y_ROAD_REAR_END   = 2580,
+	SPR_BTTUB_X_MONO_REAR_BEG   = 2581,
+	SPR_BTTUB_X_MONO_REAR_MID   = 2582,
+	SPR_BTTUB_X_MONO_REAR_END   = 2583,
+	SPR_BTTUB_Y_MONO_REAR_BEG   = 2584,
+	SPR_BTTUB_Y_MONO_REAR_MID   = 2585,
+	SPR_BTTUB_Y_MONO_REAR_END   = 2586,
+	SPR_BTTUB_X_MGLV_REAR_BEG   = 2587,
+	SPR_BTTUB_X_MGLV_REAR_MID   = 2588,
+	SPR_BTTUB_X_MGLV_REAR_END   = 2589,
+	SPR_BTTUB_Y_MGLV_REAR_BEG   = 2590,
+	SPR_BTTUB_Y_MGLV_REAR_MID   = 2591,
+	SPR_BTTUB_Y_MGLV_REAR_END   = 2592,
 
 
 	/* ramps (for all bridges except wood and tubular?)*/
--- a/terraform_gui.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/terraform_gui.c	Fri Jun 02 13:05:41 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "bridge_map.h"
 #include "clear_map.h"
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -81,11 +82,20 @@
 	size_y = (ey - sy) + 1;
 
 	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
-		if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
-			MakeClear(tile, CLEAR_ROCKS, 3);
-			MarkTileDirtyByTile(tile);
-			success = true;
+		switch (GetTileType(tile)) {
+			case MP_CLEAR:
+				MakeClear(tile, CLEAR_ROCKS, 3);
+				break;
+
+			case MP_TREES:
+				MakeClear(tile, CLEAR_ROCKS, 3);
+				ClearBridgeMiddle(tile);
+				break;
+
+			default: continue;
 		}
+		MarkTileDirtyByTile(tile);
+		success = true;
 	} END_TILE_LOOP(tile, size_x, size_y, 0);
 
 	if (success) SndPlayTileFx(SND_1F_SPLAT, end);
--- a/town_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/town_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -26,6 +26,7 @@
 #include "water_map.h"
 #include "variables.h"
 #include "bridge.h"
+#include "bridge_map.h"
 #include "table/town_land.h"
 
 enum {
@@ -1093,6 +1094,8 @@
 	slope = GetTileSlope(tile, NULL);
 	if (IsSteepSlope(slope)) return false;
 
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
+
 	b = 0;
 	if ((slope != SLOPE_FLAT && ~slope & _masks[mode])) b = ~b;
 	if ((tileh != SLOPE_FLAT && ~tileh & _masks[mode+4])) b = ~b;
@@ -1136,6 +1139,8 @@
 
 		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return false;
 
+		if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
+
 		if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
 			return false;
 	}
@@ -1270,6 +1275,7 @@
 	// make sure it's possible
 	if (!EnsureNoVehicle(tile)) return false;
 	if (IsSteepSlope(GetTileSlope(tile, NULL))) return false;
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return false;
 
 	r = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(r)) return false;
--- a/train_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/train_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -25,6 +25,7 @@
 #include "waypoint.h"
 #include "vehicle_gui.h"
 #include "train.h"
+#include "bridge.h"
 #include "newgrf_callbacks.h"
 #include "newgrf_engine.h"
 #include "newgrf_text.h"
@@ -91,10 +92,7 @@
 		/* Power is not added for articulated parts */
 		if (IsArticulatedPart(u)) continue;
 
-		if (IsBridgeTile(u->tile) && IsBridgeMiddle(u->tile) && DiagDirToAxis(DirToDiagDir(u->direction)) == GetBridgeAxis(u->tile)) {
-			if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeOnBridge(u->tile))) engine_has_power = false;
-			if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeOnBridge(u->tile))) wagon_has_power = false;
-		} else if (IsLevelCrossingTile(u->tile)) {
+		if (IsLevelCrossingTile(u->tile)) {
 			if (!HasPowerOnRail(u->u.rail.railtype, GetRailTypeCrossing(u->tile)))	engine_has_power = false;
 			if (!HasPowerOnRail(v->u.rail.railtype, GetRailTypeCrossing(u->tile)))	wagon_has_power = false;
 		} else {
@@ -1529,13 +1527,14 @@
 		UpdateVarsAfterSwap(a);
 		UpdateVarsAfterSwap(b);
 
-		VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
-		VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
+		/* call the proper EnterTile function unless we are in a wormhole */
+		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
+		if (!(b->u.rail.track & 0x40)) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
 	} else {
 		if (!(a->u.rail.track & 0x80)) a->direction = ReverseDir(a->direction);
 		UpdateVarsAfterSwap(a);
 
-		VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
+		if (!(a->u.rail.track & 0x40)) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
 	}
 
 	/* Update train's power incase tiles were different rail type */
@@ -1848,8 +1847,6 @@
 		return tfdd;
 	}
 
-	if (v->u.rail.track == 0x40) tile = GetVehicleOutOfTunnelTile(v);
-
 	if (_patches.yapf.rail_use_yapf) {
 		bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
 		tfdd.best_length = found ? max_distance / 2 : -1; // some fake distance or NOT_FOUND
@@ -2567,9 +2564,7 @@
 	byte new_z, old_z;
 
 	// need this hint so it returns the right z coordinate on bridges.
-	_get_z_hint = v->z_pos;
 	new_z = GetSlopeZ(v->x_pos, v->y_pos);
-	_get_z_hint = 0;
 
 	old_z = v->z_pos;
 	v->z_pos = new_z;
@@ -2645,13 +2640,6 @@
 			// normal tracks, jump to owner check
 			break;
 
-		case MP_TUNNELBRIDGE:
-			if (IsBridge(tile) && IsBridgeMiddle(tile)) {
-				// is train going over the bridge?
-				if (v->z_pos > GetTileMaxZ(tile)) return true;
-			}
-			break;
-
 		case MP_STREET:
 			// tracks over roads, do owner check of tracks
 			return
@@ -2992,15 +2980,16 @@
 				v->direction = chosen_dir;
 			}
 		} else {
-			/* in tunnel */
+			/* in tunnel on on a bridge */
 			GetNewVehiclePos(v, &gp);
 
-			// Check if to exit the tunnel...
-			if (!IsTunnelTile(gp.new_tile) ||
-					!(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)&0x4) ) {
+			SetSpeedLimitOnBridge(v);
+
+			if (!(IsTunnelTile(gp.new_tile) || IsBridgeTile(gp.new_tile)) || !(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;
 			}
 		}
@@ -3097,7 +3086,7 @@
 	 * others are on it */
 	DisableTrainCrossing(v->tile);
 
-	if (v->u.rail.track == 0x40) { // inside a tunnel
+	if ( (v->u.rail.track == 0x40 && v->vehstatus & VS_HIDDEN) ) { // inside a tunnel
 		TileIndex endtile = CheckTunnelBusy(v->tile, NULL);
 
 		if (endtile == INVALID_TILE) return; // tunnel is busy (error returned)
@@ -3128,15 +3117,16 @@
 	};
 
 	do {
-		//I need to buffer the train direction
-		if (!(v->u.rail.track & 0x40)) {
+		/* We don't need to twist around vehicles if they're not visible */
+		if (!(v->vehstatus & VS_HIDDEN)) {
 			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
-		}
-		if (!(v->vehstatus & VS_HIDDEN)) {
 			BeginVehicleMove(v);
 			UpdateTrainDeltaXY(v, v->direction);
 			v->cur_image = GetTrainImage(v, v->direction);
-			AfterSetTrainPos(v, false);
+			/* Refrain from updating the z position of the vehicle when on
+			   a bridge, because AfterSetTrainPos will put the vehicle under
+			   the bridge in that case */
+			if (!(v->u.rail.track & 0x40)) AfterSetTrainPos(v, false);
 		}
 	} while ((v = v->next) != NULL);
 }
@@ -3147,7 +3137,7 @@
 	uint32 r;
 	Vehicle *u;
 
-	if (state == 4 && v->u.rail.track != 0x40) {
+	if (state == 4 && !(v->u.rail.track & VS_HIDDEN)) {
 		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
 	}
 
@@ -3234,10 +3224,15 @@
 
 	tile = v->tile;
 
-	// tunnel entrance?
-	if (IsTunnelTile(tile) &&
-			DiagDirToDir(GetTunnelDirection(tile)) == v->direction) {
-		return true;
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		DiagDirection dir;
+
+		if (IsTunnel(tile)) {
+			dir = GetTunnelDirection(tile);
+		} else {
+			dir = GetBridgeRampDirection(tile);
+		}
+		if (DiagDirToDir(dir) == v->direction) return true;
 	}
 
 	// depot?
--- a/tree_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/tree_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -2,6 +2,7 @@
 
 #include "stdafx.h"
 #include "openttd.h"
+#include "bridge_map.h"
 #include "clear_map.h"
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -68,6 +69,7 @@
 
 		if (dist <= 13 &&
 				IsTileType(cur_tile, MP_CLEAR) &&
+				!IsBridgeAbove(cur_tile) &&
 				!IsClearGround(cur_tile, CLEAR_FIELDS) &&
 				!IsClearGround(cur_tile, CLEAR_ROCKS)) {
 			PlaceTree(cur_tile, r);
@@ -92,6 +94,7 @@
 		uint32 r = Random();
 		TileIndex tile = RandomTileSeed(r);
 		if (IsTileType(tile, MP_CLEAR) &&
+				!IsBridgeAbove(tile) &&
 				!IsClearGround(tile, CLEAR_FIELDS) &&
 				!IsClearGround(tile, CLEAR_ROCKS)) {
 			PlaceTree(tile, r);
@@ -105,7 +108,9 @@
 		do {
 			uint32 r = Random();
 			TileIndex tile = RandomTileSeed(r);
-			if (IsTileType(tile, MP_CLEAR) && GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
+			if (IsTileType(tile, MP_CLEAR) &&
+					!IsBridgeAbove(tile) &&
+					GetTropicZone(tile) == TROPICZONE_RAINFOREST) {
 				PlaceTree(tile, r);
 			}
 		} while (--i);
@@ -175,7 +180,8 @@
 					break;
 
 				case MP_CLEAR:
-					if (!IsTileOwner(tile, OWNER_NONE)) {
+					if (!IsTileOwner(tile, OWNER_NONE) ||
+							IsBridgeAbove(tile)) {
 						msg = STR_2804_SITE_UNSUITABLE;
 						continue;
 					}
@@ -480,7 +486,7 @@
 
 						tile += ToTileIndexDiff(_tileloop_trees_dir[Random() & 7]);
 
-						if (!IsTileType(tile, MP_CLEAR)) return;
+						if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return;
 
 						switch (GetClearGround(tile)) {
 							case CLEAR_GRASS:
@@ -513,6 +519,7 @@
 					case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break;
 					default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break;
 				}
+				ClearBridgeMiddle(tile);
 			}
 			break;
 
@@ -535,6 +542,7 @@
 	if (_opt.landscape == LT_DESERT &&
 			(r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) &&
 			IsTileType(tile, MP_CLEAR) &&
+			!IsBridgeAbove(tile) &&
 			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) &&
 			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
 		MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0);
@@ -547,6 +555,7 @@
 	r = Random();
 	tile = TILE_MASK(r);
 	if (IsTileType(tile, MP_CLEAR) &&
+			!IsBridgeAbove(tile) &&
 			(ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) &&
 			(tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) {
 		switch (ct) {
--- a/tunnelbridge_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/tunnelbridge_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -30,11 +30,6 @@
 
 #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
@@ -197,7 +192,6 @@
 	TileIndex tile;
 	TileIndexDiff delta;
 	uint bridge_len;
-	uint odd_middle_part;
 	Axis direction;
 	uint i;
 	int32 cost, terraformcost, ret;
@@ -289,6 +283,26 @@
 		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) {
@@ -305,47 +319,42 @@
 		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 (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);
 		}
 
 		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;
 				break;
 
 			case MP_RAILWAY:
-				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);
+				if (!IsPlainRailTile(tile)) goto not_valid_below;
 				break;
 
 			case MP_STREET:
-				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);
+				if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) 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);
 				break;
 
 			default:
@@ -354,50 +363,11 @@
 				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) {
-			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: SetWaterUnderBridge(tile); break;
-				default:              SetClearUnderBridge(tile); break;
-			}
-
+			SetBridgeMiddle(tile, direction);
 			MarkTileDirtyByTile(tile);
 		}
 	}
@@ -582,7 +552,7 @@
 	return _price.clear_tunnel * (length + 1);
 }
 
-
+#if 0
 static uint GetBridgeHeightRamp(TileIndex t)
 {
 	/* Return the height there (the height of the NORTH CORNER)
@@ -590,6 +560,7 @@
 	 * 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)
@@ -597,47 +568,10 @@
 	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))
@@ -651,18 +585,6 @@
 	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
@@ -681,26 +603,8 @@
 		DoClearSquare(tile);
 		DoClearSquare(endtile);
 		for (c = tile + delta; c != endtile; c += delta) {
-			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);
-				}
-			}
+			ClearBridgeMiddle(c);
+			MarkTileDirtyByTile(c);
 		}
 
 		UpdateSignalsOnSegment(tile, ReverseDiagDir(direction));
@@ -753,29 +657,7 @@
 			YapfNotifyTrackLayoutChange(endtile, endtrack);
 		}
 		return (length + 1) * (_price.build_rail >> 1);
-	} 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;
+	} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
 		uint z = TilePixelHeight(tile);
 
 		z += TILE_HEIGHT;
@@ -796,53 +678,29 @@
 		if (GetRailType(tile) == totype) return CMD_ERROR;
 
 		if (exec) {
-			Track track, endtrack;
+			TileIndexDiff delta;
+
 			SetRailType(tile, totype);
 			SetRailType(endtile, totype);
 			MarkTileDirtyByTile(tile);
 			MarkTileDirtyByTile(endtile);
 
-			// 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);
+			delta = TileOffsByDir(GetBridgeRampDirection(tile));
+			for (tile += delta; tile != endtile; tile += delta) {
+				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
 			}
-			cost += _price.build_rail >> 1;
 		}
 
-		return cost;
+		return (DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1);
 	} else
 		return CMD_ERROR;
 }
 
 
-// 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)
+static void DrawBridgePillars(PalSpriteID image, const TileInfo* ti, Axis axis, uint type, int x, int y, int z)
 {
 	if (image != 0) {
-		Axis axis = GetBridgeAxis(ti->tile);
-		bool drawfarpillar = !HASBIT(GetBridgeFlags(GetBridgeType(ti->tile)), 0);
+		bool drawfarpillar = !HASBIT(GetBridgeFlags(type), 0);
 		int back_height, front_height;
 		int i = z;
 		const byte *p;
@@ -905,17 +763,11 @@
   * <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)) {
@@ -932,19 +784,12 @@
 		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) {
-			RailType rt;
-
-			if (IsBridgeRamp(ti->tile)) {
-				rt = GetRailType(ti->tile);
-			} else {
-				rt = GetRailTypeOnBridge(ti->tile);
-			}
-
-			base_offset = GetRailTypeInfo(rt)->bridge_offset;
+			base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
 			assert(base_offset != 8); /* This one is used for roads */
 		} else {
 			base_offset = 8;
@@ -953,124 +798,152 @@
 		/* as the lower 3 bits are used for other stuff, make sure they are clear */
 		assert( (base_offset & 0x07) == 0x00);
 
-		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);
-			}
-
-			// 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);
-		} 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 (!HASBIT(BRIDGE_NO_FOUNDATION, ti->tileh)) {
+			int f = GetBridgeFoundation(ti->tileh, DiagDirToAxis(GetBridgeRampDirection(ti->tile)));
+			if (f) DrawFoundation(ti, f);
+		}
 
-					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;
+		// HACK Wizardry to convert the bridge ramp direction into a sprite offset
+		base_offset += (6 - GetBridgeRampDirection(ti->tile)) % 4;
 
-			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);
+		if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
 
-			// 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);
+		/* Table number 6 always refers to the bridge heads for any bridge type */
+		image = GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
 
-			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);
-			}
+		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);
+
+		DrawBridgeMiddle(ti);
 	}
 }
 
+
+//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;
+	}
+}
+
+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;
@@ -1085,44 +958,30 @@
 		// In the tunnel entrance?
 		if (5 <= pos && pos <= 10) return z;
 	} else {
-		if (IsBridgeRamp(tile)) {
-			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;
+		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;
-				}
-				return z + 1 + delta;
-			} else {
-				uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
+		// On the bridge ramp?
+		if (5 <= pos && pos <= 10) {
+			uint delta;
 
-				if (f != 0) {
-					if (f < 15) return z + TILE_HEIGHT;
-					tileh = _inclined_tileh[f - 15];
-				}
+			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 {
-			// HACK on the bridge?
-			if (_get_z_hint >= z + TILE_HEIGHT + (tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)) return _get_z_hint;
+			uint f = GetBridgeFoundation(tileh, DiagDirToAxis(dir));
 
-			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];
-				}
+			if (f != 0) {
+				if (f < 15) return z + TILE_HEIGHT;
+				tileh = _inclined_tileh[f - 15];
 			}
 		}
 	}
@@ -1181,9 +1040,6 @@
 			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);
 }
@@ -1218,10 +1074,6 @@
 			}
 			break;
 	}
-
-	if (IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile)) {
-		TileLoop_Water(tile);
-	}
 }
 
 static void ClickTile_TunnelBridge(TileIndex tile)
@@ -1232,37 +1084,13 @@
 
 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 (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;
+		if (GetBridgeTransportType(tile) != mode) return 0;
+		return (DiagDirToAxis(GetBridgeRampDirection(tile)) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y) * 0x101;
 	} else {
 		assert(0); /* This should never occur */
 	}
@@ -1276,16 +1104,7 @@
 	if (new_player != OWNER_SPECTATOR) {
 		SetTileOwner(tile, new_player);
 	}	else {
-		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);
-		}
+		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 	}
 }
 
@@ -1305,14 +1124,15 @@
 
 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);
 
@@ -1373,30 +1193,53 @@
 			}
 		}
 	} else if (IsBridge(tile)) { // XXX is this necessary?
+		DiagDirection dir;
+
 		if (v->type == VEH_Road || (v->type == VEH_Train && IsFrontEngine(v))) {
-			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;
+			/* 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 (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 */
--- a/variables.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/variables.h	Fri Jun 02 13:05:41 2006 +0000
@@ -309,7 +309,6 @@
 VARDEF SmallFiosItem _file_to_saveload;
 VARDEF byte _make_screenshot;
 
-VARDEF byte _get_z_hint; // used as a hint to getslopez to return the right height at a bridge.
 
 VARDEF char *_newgrf_files[32];
 
--- a/vehicle.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/vehicle.h	Fri Jun 02 13:05:41 2006 +0000
@@ -286,7 +286,6 @@
 
 StringID VehicleInTheWayErrMsg(const Vehicle* v);
 Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z);
-TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v);
 
 bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction);
 void SetSignalsOnBothDir(TileIndex tile, byte track);
--- a/water_cmd.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/water_cmd.c	Fri Jun 02 13:05:41 2006 +0000
@@ -20,7 +20,7 @@
 #include "train.h"
 #include "water_map.h"
 
-const SpriteID _water_shore_sprites[15] = {
+static const SpriteID _water_shore_sprites[] = {
 	0,
 	SPR_SHORE_TILEH_1,
 	SPR_SHORE_TILEH_2,
@@ -65,6 +65,8 @@
 	if (!IsClearWaterTile(tile) || !IsClearWaterTile(tile2))
 		return_cmd_error(STR_3801_MUST_BE_BUILT_ON_WATER);
 
+	if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
 	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(ret)) return CMD_ERROR;
 	ret = DoCommand(tile2, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
@@ -139,6 +141,8 @@
 		return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 	}
 
+	if (IsBridgeAbove(tile) || IsBridgeAbove(tile - delta) || IsBridgeAbove(tile + delta)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
 	if (flags & DC_EXEC) {
 		MakeLock(tile, dir);
 		MarkTileDirtyByTile(tile);
@@ -227,6 +231,8 @@
 
 	cost = 0;
 	BEGIN_TILE_LOOP(tile, size_x, size_y, TileXY(sx, sy)) {
+		int32 ret;
+
 		if (GetTileSlope(tile, NULL) != SLOPE_FLAT) {
 			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 		}
@@ -234,26 +240,12 @@
 		// can't make water of water!
 		if (IsTileType(tile, MP_WATER)) continue;
 
-		/* is middle piece of a bridge? */
-		if (IsBridgeTile(tile) && IsBridgeMiddle(tile)) {
-			if (IsTransportUnderBridge(tile)) {
-				return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
-			}
-
-			if (IsWaterUnderBridge(tile)) return_cmd_error(STR_1007_ALREADY_BUILT);
-
-			if (flags & DC_EXEC) SetWaterUnderBridge(tile);
-		} else {
-			/* no bridge, try to clear it. */
-			int32 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
-
-			if (CmdFailed(ret)) return ret;
-			cost += ret;
-
-			if (flags & DC_EXEC) MakeWater(tile);
-		}
+		ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+		if (CmdFailed(ret)) return ret;
+		cost += ret;
 
 		if (flags & DC_EXEC) {
+			MakeWater(tile);
 			MarkTileDirtyByTile(tile);
 			MarkTilesAroundDirty(tile);
 		}
@@ -336,17 +328,9 @@
 static bool IsWateredTile(TileIndex tile)
 {
 	switch (GetTileType(tile)) {
-		case MP_WATER:
-			return !IsCoast(tile);
-
-		case MP_STATION:
-			return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
-
-		case MP_TUNNELBRIDGE:
-			return IsBridge(tile) && IsBridgeMiddle(tile) && IsWaterUnderBridge(tile);
-
-		default:
-			return false;
+		case MP_WATER:   return !IsCoast(tile);
+		case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy_(tile);
+		default:         return false;
 	}
 }
 
@@ -422,11 +406,13 @@
 		case WATER_CLEAR:
 			DrawGroundSprite(SPR_FLAT_WATER_TILE);
 			if (ti->z != 0) DrawCanalWater(ti->tile);
+			DrawBridgeMiddle(ti);
 			break;
 
 		case WATER_COAST:
 			assert(!IsSteepSlope(ti->tileh));
 			DrawGroundSprite(_water_shore_sprites[ti->tileh]);
+			DrawBridgeMiddle(ti);
 			break;
 
 		case WATER_LOCK: {
@@ -536,27 +522,10 @@
 				}
 				break;
 
-			case MP_TUNNELBRIDGE:
-				if (IsBridge(target) && IsBridgeMiddle(target) && IsClearUnderBridge(target)) {
-					SetWaterUnderBridge(target);
-					MarkTileDirtyByTile(target);
-				}
-				break;
-
 			default:
 				break;
 		}
 	} else {
-		if (IsBridgeTile(target) && IsBridgeMiddle(target)) {
-			if (IsWaterUnderBridge(target) ||
-					(IsTransportUnderBridge(target) && GetTransportTypeUnderBridge(target) == TRANSPORT_WATER)) { // XXX does this happen at all?
-				return;
-			}
-			SetWaterUnderBridge(target);
-			MarkTileDirtyByTile(target);
-			return;
-		}
-
 		_current_player = OWNER_WATER;
 		{
 			Vehicle *v = FindVehicleOnTileZ(target, 0);
--- a/waypoint.c	Thu Jun 01 22:20:40 2006 +0000
+++ b/waypoint.c	Fri Jun 02 13:05:41 2006 +0000
@@ -9,6 +9,7 @@
 #include "map.h"
 #include "order.h"
 #include "rail_map.h"
+#include "bridge_map.h"
 #include "saveload.h"
 #include "station.h"
 #include "tile.h"
@@ -201,6 +202,8 @@
 			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 	}
 
+	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
+
 	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
 	wp = FindDeletedWaypointCloseTo(tile);
 	if (wp == NULL) {
--- a/yapf/follow_track.hpp	Thu Jun 01 22:20:40 2006 +0000
+++ b/yapf/follow_track.hpp	Fri Jun 02 13:05:41 2006 +0000
@@ -27,7 +27,7 @@
 		m_new_tile = INVALID_TILE;
 		m_new_td_bits = TRACKDIR_BIT_NONE;
 		m_exitdir = INVALID_DIAGDIR;
-		m_is_station = m_is_tunnel = false;
+		m_is_station = m_is_bridge = m_is_tunnel = false;
 		m_tiles_skipped = 0;
 	}
 
@@ -60,6 +60,9 @@
 	/** Follow the m_exitdir from m_old_tile and fill m_new_tile and m_tiles_skipped */
 	FORCEINLINE void FollowTileExit()
 	{
+		m_is_station = m_is_bridge = m_is_tunnel = false;
+		m_tiles_skipped = 0;
+
 		// extra handling for tunnels in our direction
 		if (IsTunnelTile(m_old_tile)) {
 			DiagDirection tunnel_enterdir = GetTunnelDirection(m_old_tile);
@@ -73,11 +76,22 @@
 			}
 			assert(ReverseDiagDir(tunnel_enterdir) == m_exitdir);
 		}
-		// not a tunnel or station
-		m_is_tunnel = false;
-		m_tiles_skipped = 0;
 
-		// normal or station tile
+		// extra handling for bridge ramp in our direction
+		if (IsBridgeTile(m_old_tile)) {
+			DiagDirection bridge_enterdir = GetBridgeRampDirection(m_old_tile);
+			if (bridge_enterdir == m_exitdir) {
+				// we are entering the bridge ramp
+				m_new_tile = GetOtherBridgeEnd(m_old_tile);
+				uint32 bridge_length = GetBridgeLength(m_old_tile, m_new_tile);
+				m_tiles_skipped = bridge_length;
+				m_is_bridge = true;
+				return;
+			}
+			assert(ReverseDiagDir(bridge_enterdir) == m_exitdir);
+		}
+
+		// normal or station tile, do one step
 		TileIndexDiff diff = TileOffsByDir(m_exitdir);
 		m_new_tile = TILE_ADD(m_old_tile, diff);
 
@@ -148,22 +162,7 @@
 		// rail transport is possible only on tiles with the same owner as vehicle
 		if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh->owner) {
 			// different owner
-			if (IsBridgeTile(m_new_tile)) {
-				if (IsBridgeMiddle(m_new_tile)) {
-						// bridge middle has no owner - tile is owned by the owner of the under-bridge track
-					if (GetBridgeAxis(m_new_tile) != DiagDirToAxis(m_exitdir)) {
-						// so it must be under bridge track (and wrong owner)
-						return false;
-					}
-					// in the middle of the bridge - when we came here, it should be ok
-				} else {
-					// different owner, on the bridge ramp
-					return false;
-				}
-			} else {
-				// different owner, not a bridge
-				return false;
-			}
+			return false;
 		}
 
 		// rail transport is possible only on compatible rail types
@@ -224,20 +223,10 @@
 		int max_speed = INT_MAX; // no limit
 
 		// for now we handle only on-bridge speed limit
-		if (IsBridgeTile(m_old_tile) && !IsWaterTT() && IsDiagonalTrackdir(m_old_td)) {
-			bool is_on_bridge = true;
-			if (IsBridgeMiddle(m_old_tile)) {
-				// get track axis
-				Axis track_axis = DiagDirToAxis(TrackdirToExitdir(m_old_td));
-				// get under-bridge axis
-				Axis bridge_axis =  GetBridgeAxis(m_old_tile);
-				if (track_axis != bridge_axis) is_on_bridge = false;
-			}
-			if (is_on_bridge) {
-				int spd = _bridge[GetBridgeType(m_old_tile)].speed;
-				if (IsRoadTT()) spd *= 2;
-				if (max_speed > spd) max_speed = spd;
-			}
+		if (!IsWaterTT() && IsBridgeTile(m_old_tile)) {
+			int spd = _bridge[GetBridgeType(m_old_tile)].speed;
+			if (IsRoadTT()) spd *= 2;
+			if (max_speed > spd) max_speed = spd;
 		}
 
 		// if min speed was requested, return it
--- a/yapf/yapf.h	Thu Jun 01 22:20:40 2006 +0000
+++ b/yapf/yapf.h	Fri Jun 02 13:05:41 2006 +0000
@@ -34,9 +34,9 @@
 	Trackdir      m_old_td;
 	TileIndex     m_new_tile;
 	TrackdirBits  m_new_td_bits;
-//	TrackdirBits  m_red_td_bits;
 	DiagDirection m_exitdir;
 	bool          m_is_tunnel;
+	bool          m_is_bridge;
 	bool          m_is_station;
 	int           m_tiles_skipped;
 } FollowTrack_t;
--- a/yapf/yapf_road.cpp	Thu Jun 01 22:20:40 2006 +0000
+++ b/yapf/yapf_road.cpp	Fri Jun 02 13:05:41 2006 +0000
@@ -423,7 +423,9 @@
 Depot* YapfFindNearestRoadDepot(const Vehicle *v)
 {
 	TileIndex tile = v->tile;
+#if 0 /* NOT NEEDED, function does/did nothing */
 	if (v->u.road.state == 255) tile = GetVehicleOutOfTunnelTile(v);
+#endif
 	Trackdir trackdir = GetVehicleTrackdir(v);
 	if ((GetTileTrackStatus(tile, TRANSPORT_ROAD) & TrackdirToTrackdirBits(trackdir)) == 0)
 		return NULL;