(svn r13464) -Codechange: support NewGRF Action 0x05, type 12.
authorrubidium
Wed, 11 Jun 2008 13:54:01 +0000
changeset 10913 af60a6eda0a0
parent 10911 dc3cb3bb6113
child 10914 7ca27172ba4c
(svn r13464) -Codechange: support NewGRF Action 0x05, type 12.
bin/data/openttdd.grf
bin/data/openttdw.grf
src/bridge_map.h
src/dock_gui.cpp
src/newgrf.cpp
src/pathfind.cpp
src/ship_cmd.cpp
src/table/bridge_land.h
src/table/files.h
src/table/sprites.h
src/tunnelbridge_cmd.cpp
src/water_cmd.cpp
src/yapf/follow_track.hpp
src/yapf/yapf_ship.cpp
Binary file bin/data/openttdd.grf has changed
Binary file bin/data/openttdw.grf has changed
--- a/src/bridge_map.h	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/bridge_map.h	Wed Jun 11 13:54:01 2008 +0000
@@ -200,5 +200,15 @@
 	MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r);
 }
 
+/**
+ * Make a bridge ramp for aqueducts.
+ * @param t          the tile to make a bridge ramp
+ * @param o          the new owner of the bridge ramp
+ * @param d          the direction this ramp must be facing
+ */
+static inline void MakeAqueductBridgeRamp(TileIndex t, Owner o, DiagDirection d)
+{
+	MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0);
+}
 
 #endif /* BRIDGE_MAP_H */
--- a/src/dock_gui.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/dock_gui.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -69,6 +69,12 @@
 	DoCommandP(tile, 0, 0, CcBuildDocks, CMD_BUILD_LOCK | CMD_MSG(STR_CANT_BUILD_LOCKS));
 }
 
+static void PlaceDocks_Bridge(TileIndex tile)
+{
+	VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
+}
+
+
 /** Enum referring to the widgets of the build dock toolbar */
 enum DockToolbarWidgets {
 	DTW_BEGIN = 0,                 ///< Start of toolbar widgets
@@ -83,6 +89,7 @@
 	DTW_DEPOT,                     ///< Build depot button
 	DTW_STATION,                   ///< Build station button
 	DTW_BUOY,                      ///< Build buoy button
+	DTW_BUILD_BRIDGE,              ///< Build bride button
 	DTW_END,                       ///< End of toolbar widgets
 };
 
@@ -120,6 +127,11 @@
 	HandlePlacePushButton(w, DTW_BUOY, SPR_CURSOR_BOUY, VHM_RECT, PlaceDocks_Buoy);
 }
 
+static void BuildDocksClick_Bridge(Window *w)
+{
+	HandlePlacePushButton(w, DTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, VHM_RECT, PlaceDocks_Bridge);
+}
+
 
 typedef void OnButtonClick(Window *w);
 static OnButtonClick * const _build_docks_button_proc[] = {
@@ -129,7 +141,8 @@
 	BuildDocksClick_Demolish,
 	BuildDocksClick_Depot,
 	BuildDocksClick_Dock,
-	BuildDocksClick_Buoy
+	BuildDocksClick_Buoy,
+	BuildDocksClick_Bridge
 };
 
 struct BuildDocksToolbarWindow : Window {
@@ -164,6 +177,7 @@
 			case '4': BuildDocksClick_Depot(this); break;
 			case '5': BuildDocksClick_Dock(this); break;
 			case '6': BuildDocksClick_Buoy(this); break;
+			case '7': BuildDocksClick_Bridge(this); break;
 			default:  return ES_NOT_HANDLED;
 		}
 		return ES_HANDLED;
@@ -183,6 +197,11 @@
 	{
 		if (pt.x != -1) {
 			switch (select_proc) {
+				case DDSP_BUILD_BRIDGE:
+					ResetObjectToPlace();
+					extern void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2);
+					DoCommandP(end_tile, start_tile, TRANSPORT_WATER << 15, CcBuildBridge, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
+
 				case DDSP_DEMOLISH_AREA:
 					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
@@ -214,8 +233,8 @@
 
 static const Widget _build_docks_toolb_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},                   // DTW_CLOSEBOX
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   123,     0,    13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},         // DTW_CAPTION
-{  WWT_STICKYBOX,   RESIZE_NONE,     7,   124,   135,     0,    13, 0x0,                        STR_STICKY_BUTTON},                       // DTW_STICKY
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   166,     0,    13, STR_9801_DOCK_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},         // DTW_CAPTION
+{  WWT_STICKYBOX,   RESIZE_NONE,     7,   167,   178,     0,    13, 0x0,                        STR_STICKY_BUTTON},                       // DTW_STICKY
 {     WWT_IMGBTN,   RESIZE_NONE,     7,     0,    21,    14,    35, SPR_IMG_BUILD_CANAL,        STR_BUILD_CANALS_TIP},                    // DTW_CANAL
 {     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_BUILD_LOCK,         STR_BUILD_LOCKS_TIP},                     // DTW_LOCK
 
@@ -225,11 +244,12 @@
 {     WWT_IMGBTN,   RESIZE_NONE,     7,    70,    91,    14,    35, SPR_IMG_SHIP_DEPOT,         STR_981E_BUILD_SHIP_DEPOT_FOR_BUILDING},  // DTW_DEPOT
 {     WWT_IMGBTN,   RESIZE_NONE,     7,    92,   113,    14,    35, SPR_IMG_SHIP_DOCK,          STR_981D_BUILD_SHIP_DOCK},                // DTW_STATION
 {     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_BOUY,               STR_9834_POSITION_BUOY_WHICH_CAN},        // DTW_BUOY
+{     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   178,    14,    35, SPR_IMG_BRIDGE,             STR_180F_BUILD_ROAD_BRIDGE},              // DTW_BUILD_BRIDGE
 {   WIDGETS_END},
 };
 
 static const WindowDesc _build_docks_toolbar_desc = {
-	WDP_ALIGN_TBR, 22, 136, 36, 136, 36,
+	WDP_ALIGN_TBR, 22, 179, 36, 179, 36,
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_docks_toolb_widgets,
--- a/src/newgrf.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/newgrf.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -3451,7 +3451,7 @@
 		/* 0x0F */ { A5BLOCK_INVALID,      0,                  12, 0,                                           "Sloped rail track"     }, // Not yet used by OTTD.
 		/* 0x10 */ { A5BLOCK_FIXED,        SPR_AIRPORTX_BASE,  15, AIRPORTX_SPRITE_COUNT,                       "Airport graphics"      },
 		/* 0x11 */ { A5BLOCK_FIXED,        SPR_ROADSTOP_BASE,   8, ROADSTOP_SPRITE_COUNT,                       "Road stop graphics"    },
-		/* 0x12 */ { A5BLOCK_INVALID,      0,                   8, 0,                                           "Aqueduct graphics"     }, // Not yet used by OTTD.
+		/* 0x12 */ { A5BLOCK_FIXED,        SPR_AQUEDUCT_BASE,   8, AQUEDUCT_SPRITE_COUNT,                       "Aqueduct graphics"     },
 		/* 0x13 */ { A5BLOCK_FIXED,        SPR_AUTORAIL_BASE,  55, AUTORAIL_SPRITE_COUNT,                       "Autorail graphics"     },
 		/* 0x14 */ { A5BLOCK_ALLOW_OFFSET, SPR_FLAGS_BASE,      1, FLAGS_SPRITE_COUNT,                          "Flag graphics"         },
 		/* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE,    1, OPENTTD_SPRITE_COUNT,                        "OpenTTD GUI graphics"  },
--- a/src/pathfind.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/pathfind.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -112,9 +112,28 @@
 
 static void TPFModeShip(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
 {
-	RememberData rd;
+	assert(tpf->tracktype == TRANSPORT_WATER);
 
-	assert(tpf->tracktype == TRANSPORT_WATER);
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		/* wrong track type */
+		if (GetTunnelBridgeTransportType(tile) != tpf->tracktype) return;
+
+		DiagDirection dir = GetTunnelBridgeDirection(tile);
+		/* entering tunnel / bridge? */
+		if (dir == direction) {
+			TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
+
+			tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
+
+			TPFSetTileBit(tpf, tile, 14);
+			TPFSetTileBit(tpf, endtile, 14);
+
+			tile = endtile;
+		} else {
+			/* leaving tunnel / bridge? */
+			if (ReverseDiagDir(dir) != direction) return;
+		}
+	}
 
 	/* This addition will sometimes overflow by a single tile.
 	 * The use of TILE_MASK here makes sure that we still point at a valid
@@ -133,7 +152,7 @@
 	do {
 		Track track = RemoveFirstTrack(&bits);
 		if (bits != TRACK_BIT_NONE) only_one_track = false;
-		rd = tpf->rd;
+		RememberData rd = tpf->rd;
 
 		/* Change direction 4 times only */
 		if (!only_one_track && track != tpf->rd.last_choosen_track) {
--- a/src/ship_cmd.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/ship_cmd.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -599,90 +599,102 @@
 	BeginVehicleMove(v);
 
 	GetNewVehiclePosResult gp = GetNewVehiclePos(v);
-	if (gp.old_tile == gp.new_tile) {
-		/* Staying in tile */
-		if (v->IsInDepot()) {
-			gp.x = v->x_pos;
-			gp.y = v->y_pos;
-		} else {
-			/* Not inside depot */
-			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-			if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction;
+	if (v->u.ship.state != TRACK_BIT_WORMHOLE) {
+		/* Not on a bridge */
+		if (gp.old_tile == gp.new_tile) {
+			/* Staying in tile */
+			if (v->IsInDepot()) {
+				gp.x = v->x_pos;
+				gp.y = v->y_pos;
+			} else {
+				/* Not inside depot */
+				r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+				if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction;
 
-			/* A leave station order only needs one tick to get processed, so we can
-			 * always skip ahead. */
-			if (v->current_order.IsType(OT_LEAVESTATION)) {
-				v->current_order.Free();
-				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
-			} else if (v->dest_tile != 0) {
-				/* We have a target, let's see if we reached it... */
-				if (v->current_order.IsType(OT_GOTO_STATION) &&
-						IsBuoyTile(v->dest_tile) &&
-						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
-					/* We got within 3 tiles of our target buoy, so let's skip to our
-					 * next order */
-					UpdateVehicleTimetable(v, true);
-					v->cur_order_index++;
-					v->current_order.MakeDummy();
-					InvalidateVehicleOrder(v);
-				} else {
-					/* Non-buoy orders really need to reach the tile */
-					if (v->dest_tile == gp.new_tile) {
-						if (v->current_order.IsType(OT_GOTO_DEPOT)) {
-							if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
-								VehicleEnterDepot(v);
-								return;
-							}
-						} else if (v->current_order.IsType(OT_GOTO_STATION)) {
-							v->last_station_visited = v->current_order.GetDestination();
+				/* A leave station order only needs one tick to get processed, so we can
+				* always skip ahead. */
+				if (v->current_order.IsType(OT_LEAVESTATION)) {
+					v->current_order.Free();
+					InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+				} else if (v->dest_tile != 0) {
+					/* We have a target, let's see if we reached it... */
+					if (v->current_order.IsType(OT_GOTO_STATION) &&
+							IsBuoyTile(v->dest_tile) &&
+							DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
+						/* We got within 3 tiles of our target buoy, so let's skip to our
+						* next order */
+						UpdateVehicleTimetable(v, true);
+						v->cur_order_index++;
+						v->current_order.MakeDummy();
+						InvalidateVehicleOrder(v);
+					} else {
+						/* Non-buoy orders really need to reach the tile */
+						if (v->dest_tile == gp.new_tile) {
+							if (v->current_order.IsType(OT_GOTO_DEPOT)) {
+								if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) {
+									VehicleEnterDepot(v);
+									return;
+								}
+							} else if (v->current_order.IsType(OT_GOTO_STATION)) {
+								v->last_station_visited = v->current_order.GetDestination();
 
-							/* Process station in the orderlist. */
-							Station *st = GetStation(v->current_order.GetDestination());
-							if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
-								ShipArrivesAt(v, st);
-								v->BeginLoading();
-							} else { // leave stations without docks right aways
-								v->current_order.MakeLeaveStation();
-								v->cur_order_index++;
-								InvalidateVehicleOrder(v);
+								/* Process station in the orderlist. */
+								Station *st = GetStation(v->current_order.GetDestination());
+								if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations
+									ShipArrivesAt(v, st);
+									v->BeginLoading();
+								} else { // leave stations without docks right aways
+									v->current_order.MakeLeaveStation();
+									v->cur_order_index++;
+									InvalidateVehicleOrder(v);
+								}
 							}
 						}
 					}
 				}
 			}
+		} else {
+			DiagDirection diagdir;
+			/* New tile */
+			if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY()) {
+				goto reverse_direction;
+			}
+
+			dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
+			assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
+			diagdir = DirToDiagDir(dir);
+			tracks = GetAvailShipTracks(gp.new_tile, diagdir);
+			if (tracks == TRACK_BIT_NONE) goto reverse_direction;
+
+			/* Choose a direction, and continue if we find one */
+			track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
+			if (track == INVALID_TRACK) goto reverse_direction;
+
+			b = _ship_subcoord[diagdir][track];
+
+			gp.x = (gp.x & ~0xF) | b[0];
+			gp.y = (gp.y & ~0xF) | b[1];
+
+			/* Call the landscape function and tell it that the vehicle entered the tile */
+			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
+			if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction;
+
+			if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
+				v->tile = gp.new_tile;
+				v->u.ship.state = TrackToTrackBits(track);
+			}
+
+			v->direction = (Direction)b[2];
 		}
 	} else {
-		DiagDirection diagdir;
-		/* New tile */
-		if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY()) {
-			goto reverse_direction;
+		/* On a bridge */
+		if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
+			v->x_pos = gp.x;
+			v->y_pos = gp.y;
+			VehiclePositionChanged(v);
+			if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
+			return;
 		}
-
-		dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
-		assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
-		diagdir = DirToDiagDir(dir);
-		tracks = GetAvailShipTracks(gp.new_tile, diagdir);
-		if (tracks == TRACK_BIT_NONE) goto reverse_direction;
-
-		/* Choose a direction, and continue if we find one */
-		track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
-		if (track == INVALID_TRACK) goto reverse_direction;
-
-		b = _ship_subcoord[diagdir][track];
-
-		gp.x = (gp.x & ~0xF) | b[0];
-		gp.y = (gp.y & ~0xF) | b[1];
-
-		/* Call the landscape function and tell it that the vehicle entered the tile */
-		r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
-		if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction;
-
-		if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
-			v->tile = gp.new_tile;
-			v->u.ship.state = TrackToTrackBits(track);
-		}
-
-		v->direction = (Direction)b[2];
 	}
 
 	/* update image of ship, as well as delta XY */
--- a/src/table/bridge_land.h	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/table/bridge_land.h	Wed Jun 11 13:54:01 2008 +0000
@@ -28,6 +28,12 @@
 # define MW(a) {a, PALETTE_TO_STRUCT_WHITE}
 # define MC(a) {a, PALETTE_TO_STRUCT_CONCRETE}
 
+static const PalSpriteID _aqueduct_sprites[] = {
+	{ SPR_AQUEDUCT_MIDDLE_X, PAL_NONE }, {                  0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_X, PAL_NONE }, {                  0x0, PAL_NONE },
+	{ SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE }, {                  0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_Y, PAL_NONE }, {                  0x0, PAL_NONE },
+	{  SPR_AQUEDUCT_RAMP_SW, PAL_NONE }, { SPR_AQUEDUCT_RAMP_SE, PAL_NONE }, {  SPR_AQUEDUCT_RAMP_NE, PAL_NONE }, { SPR_AQUEDUCT_RAMP_NW, PAL_NONE },
+};
+
 static const PalSpriteID _bridge_sprite_table_4_0[] = {
 	{  0x9A9, PAL_NONE }, {  0x99F, PAL_NONE }, {  0x9B1, PAL_NONE }, {    0x0, PAL_NONE },
 	{  0x9A5, PAL_NONE }, {  0x997, PAL_NONE }, {  0x9AD, PAL_NONE }, {    0x0, PAL_NONE },
--- a/src/table/files.h	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/table/files.h	Wed Jun 11 13:54:01 2008 +0000
@@ -35,7 +35,7 @@
 		{ "TRGT.GRF",      {0xfc, 0xde, 0x1d, 0x7e, 0x8a, 0x74, 0x19, 0x7d, 0x72, 0xa6, 0x26, 0x95, 0x88, 0x4b, 0x90, 0x9e} }
 	},
 	{ "SAMPLE.CAT",    {0x42, 0x2e, 0xa3, 0xdd, 0x07, 0x4d, 0x28, 0x59, 0xbb, 0x51, 0x63, 0x9a, 0x6e, 0x0e, 0x85, 0xda} },
-	{ "OPENTTDD.GRF",  {0xb6, 0xed, 0x9a, 0x20, 0x89, 0xad, 0x6e, 0xa1, 0x55, 0x10, 0xad, 0x00, 0x53, 0xa3, 0xd5, 0xbc} }
+	{ "OPENTTDD.GRF",  {0x43, 0x3d, 0x38, 0xa9, 0x7a, 0xd7, 0x5a, 0xc2, 0x52, 0xf6, 0x52, 0x49, 0x38, 0x15, 0x0a, 0x71} }
 };
 
 
@@ -49,5 +49,5 @@
 		{ "TRGTR.GRF",     {0xde, 0x53, 0x65, 0x05, 0x17, 0xfe, 0x66, 0x1c, 0xea, 0xa3, 0x13, 0x8c, 0x6e, 0xdb, 0x0e, 0xb8} }
 	},
 	{ "SAMPLE.CAT",    {0x92, 0x12, 0xe8, 0x1e, 0x72, 0xba, 0xdd, 0x4b, 0xbe, 0x1e, 0xae, 0xae, 0x66, 0x45, 0x8e, 0x10} },
-	{ "OPENTTDW.GRF",  {0x41, 0x1e, 0xb6, 0xb2, 0xd2, 0xc4, 0x30, 0x6e, 0x7b, 0xc7, 0xdc, 0x39, 0xd4, 0x40, 0x46, 0xfb} }
+	{ "OPENTTDW.GRF",  {0x40, 0xb4, 0x75, 0xe2, 0xd9, 0x55, 0x6e, 0x30, 0x5f, 0x3f, 0x8d, 0xb3, 0xbe, 0x10, 0x36, 0x17} }
 };
--- a/src/table/sprites.h	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/table/sprites.h	Wed Jun 11 13:54:01 2008 +0000
@@ -132,7 +132,18 @@
 	SPR_CANALS_BASE   = SPR_SIGNALS_BASE + PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT,
 	CANALS_SPRITE_COUNT = 65,
 
-	SPR_SLOPES_BASE              = SPR_CANALS_BASE + CANALS_SPRITE_COUNT,
+	SPR_AQUEDUCT_BASE     = SPR_CANALS_BASE + CANALS_SPRITE_COUNT,
+	SPR_AQUEDUCT_RAMP_SW  = SPR_AQUEDUCT_BASE + 0,
+	SPR_AQUEDUCT_RAMP_SE  = SPR_AQUEDUCT_BASE + 1,
+	SPR_AQUEDUCT_RAMP_NE  = SPR_AQUEDUCT_BASE + 2,
+	SPR_AQUEDUCT_RAMP_NW  = SPR_AQUEDUCT_BASE + 3,
+	SPR_AQUEDUCT_MIDDLE_X = SPR_AQUEDUCT_BASE + 4,
+	SPR_AQUEDUCT_MIDDLE_Y = SPR_AQUEDUCT_BASE + 5,
+	SPR_AQUEDUCT_PILLAR_X = SPR_AQUEDUCT_BASE + 6,
+	SPR_AQUEDUCT_PILLAR_Y = SPR_AQUEDUCT_BASE + 7,
+	AQUEDUCT_SPRITE_COUNT = 8,
+
+	SPR_SLOPES_BASE              = SPR_AQUEDUCT_BASE + AQUEDUCT_SPRITE_COUNT,
 	SPR_SLOPES_INCLINED_OFFSET   = 15,
 	SPR_SLOPES_VIRTUAL_BASE      = SPR_SLOPES_BASE - SPR_SLOPES_INCLINED_OFFSET, // The original foundations (see SPR_FOUNDATION_BASE below) are mapped before the additional foundations.
 	SPR_TRKFOUND_BLOCK_SIZE      = 22, // The normal track foundation sprites are organized in blocks of 22.
--- a/src/tunnelbridge_cmd.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/tunnelbridge_cmd.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -227,9 +227,11 @@
 			if (!ValParamRailtype(railtype)) return CMD_ERROR;
 			break;
 
+		case TRANSPORT_WATER:
+			break;
+
 		default:
-			/* For now, only TRANSPORT_RAIL and TRANSPORT_ROAD are allowed.
-			 * But let not this stops us for preparing the future */
+			/* Airports don't have tunnels. */
 			return CMD_ERROR;
 	}
 
@@ -250,9 +252,11 @@
 		return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
 	}
 
-	/* set and test bridge length, availability */
 	bridge_len = sx + sy - x - y - 1;
-	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
+	if (transport_type != TRANSPORT_WATER) {
+		/* set and test bridge length, availability */
+		if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
+	}
 
 	/* retrieve landscape height and ensure it's on land */
 	tile_start = TileXY(x, y);
@@ -368,6 +372,11 @@
 				MakeRoadBridgeRamp(tile_end,   owner, bridge_type, ReverseDiagDir(dir), roadtypes);
 				break;
 
+			case TRANSPORT_WATER:
+				MakeAqueductBridgeRamp(tile_start, owner, dir);
+				MakeAqueductBridgeRamp(tile_end,   owner, ReverseDiagDir(dir));
+				break;
+
 			default:
 				NOT_REACHED();
 				break;
@@ -926,7 +935,11 @@
 		if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
 
 		/* Table number 6 always refers to the bridge heads for any bridge type */
-		psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
+		if (transport_type != TRANSPORT_WATER) {
+			psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
+		} else {
+			psid = _aqueduct_sprites + base_offset;
+		}
 
 		if (!ice) {
 			DrawClearLandTile(ti, 3);
@@ -1023,7 +1036,7 @@
 	/* Z position of the bridge sprites relative to bridge height (downwards) */
 	static const int BRIDGE_Z_START = 3;
 
-	const PalSpriteID* psid;
+	const PalSpriteID *psid;
 	uint base_offset;
 	TileIndex rampnorth;
 	TileIndex rampsouth;
@@ -1048,13 +1061,17 @@
 	);
 	type = GetBridgeType(rampsouth);
 
-	if (transport_type == TRANSPORT_RAIL) {
-		base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
+	if (transport_type != TRANSPORT_WATER) {
+		if (transport_type == TRANSPORT_RAIL) {
+			base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
+		} else {
+			base_offset = 8;
+		}
+
+		psid = base_offset + GetBridgeSpriteTable(type, piece);
 	} else {
-		base_offset = 8;
+		psid = _aqueduct_sprites;
 	}
-
-	psid = base_offset + GetBridgeSpriteTable(type, piece);
 	if (axis != AXIS_X) psid += 4;
 
 	x = ti->x;
@@ -1342,7 +1359,7 @@
 		}
 	} else { // IsBridge(tile)
 
-		if (v->IsPrimaryVehicle()) {
+		if (v->IsPrimaryVehicle() && v->type != VEH_SHIP) {
 			/* modify speed of vehicle */
 			uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;
 
@@ -1358,29 +1375,51 @@
 				case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
 				case DIAGDIR_NW: if ((y & 0xF) != 0)             return VETSB_CONTINUE; break;
 			}
-			if (v->type == VEH_TRAIN) {
-				v->u.rail.track = TRACK_BIT_WORMHOLE;
-				ClrBit(v->u.rail.flags, VRF_GOINGUP);
-				ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
-			} else {
-				v->u.road.state = RVSB_WORMHOLE;
+			switch (v->type) {
+				case VEH_TRAIN:
+					v->u.rail.track = TRACK_BIT_WORMHOLE;
+					ClrBit(v->u.rail.flags, VRF_GOINGUP);
+					ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
+					break;
+
+				case VEH_ROAD:
+					v->u.road.state = RVSB_WORMHOLE;
+					break;
+
+				case VEH_SHIP:
+					v->u.ship.state = TRACK_BIT_WORMHOLE;
+					break;
+
+				default: NOT_REACHED();
 			}
 			return VETSB_ENTERED_WORMHOLE;
 		} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
 			v->tile = tile;
-			if (v->type == VEH_TRAIN) {
-				if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
-					v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
-					return VETSB_ENTERED_WORMHOLE;
-				}
-			} else {
-				if (v->u.road.state == RVSB_WORMHOLE) {
-					v->u.road.state = _road_exit_tunnel_state[dir];
-					v->u.road.frame = 0;
-					return VETSB_ENTERED_WORMHOLE;
-				}
+			switch (v->type) {
+				case VEH_TRAIN:
+					if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
+						v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
+						return VETSB_ENTERED_WORMHOLE;
+					}
+					break;
+
+				case VEH_ROAD:
+					if (v->u.road.state == RVSB_WORMHOLE) {
+						v->u.road.state = _road_exit_tunnel_state[dir];
+						v->u.road.frame = 0;
+						return VETSB_ENTERED_WORMHOLE;
+					}
+					break;
+
+				case VEH_SHIP:
+					if (v->u.ship.state == TRACK_BIT_WORMHOLE) {
+						v->u.ship.state = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
+						return VETSB_ENTERED_WORMHOLE;
+					}
+					break;
+
+				default: NOT_REACHED();
 			}
-			return VETSB_CONTINUE;
 		}
 	}
 	return VETSB_CONTINUE;
--- a/src/water_cmd.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/water_cmd.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -40,6 +40,7 @@
 #include "newgrf_cargo.h"
 #include "effectvehicle_func.h"
 #include "oldpool_func.h"
+#include "tunnelbridge_map.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -506,6 +507,7 @@
 
 		case MP_STATION:  return IsOilRig(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
 		case MP_INDUSTRY: return (GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0;
+		case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER;
 		default:          return false;
 	}
 }
--- a/src/yapf/follow_track.hpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/yapf/follow_track.hpp	Wed Jun 11 13:54:01 2008 +0000
@@ -264,7 +264,7 @@
 		}
 
 		// tunnel holes and bridge ramps can be entered only from proper direction
-		if (!IsWaterTT() && IsTileType(m_new_tile, MP_TUNNELBRIDGE)) {
+		if (IsTileType(m_new_tile, MP_TUNNELBRIDGE)) {
 			if (IsTunnel(m_new_tile)) {
 				if (!m_is_tunnel) {
 					DiagDirection tunnel_enterdir = GetTunnelBridgeDirection(m_new_tile);
--- a/src/yapf/yapf_ship.cpp	Wed Jun 11 12:46:28 2008 +0000
+++ b/src/yapf/yapf_ship.cpp	Wed Jun 11 13:54:01 2008 +0000
@@ -109,6 +109,9 @@
 			/* new trackdir does not match the next one when going straight */
 			c += 10;
 		}
+
+		c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
+
 		// apply it
 		n.m_cost = n.m_parent->m_cost + c;
 		return true;