src/water_cmd.cpp
branchNewGRF_ports
changeset 6877 889301acc299
parent 6873 86bf4ccb580d
child 6878 7d1ff2f621c7
--- a/src/water_cmd.cpp	Sun Feb 03 01:34:21 2008 +0000
+++ b/src/water_cmd.cpp	Sun Feb 03 20:34:26 2008 +0000
@@ -34,6 +34,7 @@
 #include "player_func.h"
 #include "settings_type.h"
 #include "clear_map.h"
+#include "tree_map.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -70,9 +71,28 @@
 };
 
 /**
- * Slopes that contain flat water and not only shore.
+ * Marks tile dirty if it is a canal or river tile.
+ * Called to avoid glitches when flooding tiles next to canal tile.
+ *
+ * @param tile tile to check
  */
-static const uint32 _active_water_slopes = (1 << SLOPE_FLAT) | (1 << SLOPE_W) | (1 << SLOPE_S) | (1 << SLOPE_E) | (1 << SLOPE_N);
+static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile)
+{
+	if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile);
+}
+
+/**
+ * Marks the tiles around a tile as dirty, if they are canals or rivers.
+ *
+ * @param tile The center of the tile where all other tiles are marked as dirty
+ * @ingroup dirty
+ */
+static void MarkCanalsAndRiversAroundDirty(TileIndex tile)
+{
+	for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
+		MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir));
+	}
+}
 
 /**
  * Makes a tile canal or water depending on the surroundings.
@@ -81,33 +101,46 @@
  * @param t the tile to change.
  * @param o the owner of the new tile.
  */
-void MakeWaterOrCanalDependingOnSurroundings(TileIndex t, Owner o)
+void SetWaterClassDependingOnSurroundings(TileIndex t)
 {
 	assert(GetTileSlope(t, NULL) == SLOPE_FLAT);
 
 	/* Mark tile dirty in all cases */
 	MarkTileDirtyByTile(t);
 
-	/* Non-sealevel -> canal */
-	if (TileHeight(t) != 0) {
-		MakeCanal(t, o, Random());
-		return;
-	}
-
 	bool has_water = false;
 	bool has_canal = false;
+	bool has_river = false;
 
 	for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
 		TileIndex neighbour = TileAddByDiagDir(t, dir);
-		if (IsTileType(neighbour, MP_WATER)) {
-			has_water |= IsSea(neighbour) || IsCoast(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) == OWNER_WATER);
-			has_canal |= IsCanal(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) != OWNER_WATER);
+		switch (GetTileType(neighbour)) {
+			case MP_WATER:
+				has_water |= IsSea(neighbour) || IsCoast(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) == OWNER_WATER);
+				has_canal |= IsCanal(neighbour) || (IsShipDepot(neighbour) && GetShipDepotWaterOwner(neighbour) != OWNER_WATER);
+				has_river |= IsRiver(neighbour);
+				break;
+
+			case MP_RAILWAY:
+				/* Shore or flooded halftile */
+				has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER);
+				break;
+
+			case MP_TREES:
+				/* trees on shore */
+				has_water |= (GetTreeGround(neighbour) == TREE_GROUND_SHORE);
+				break;
+
+			default: break;
 		}
 	}
-	if (has_canal || !has_water) {
-		MakeCanal(t, o, Random());
+
+	if (has_river && !has_canal) {
+		SetWaterClass(t, WATER_CLASS_RIVER);
+	} else if (has_canal || !has_water) {
+		SetWaterClass(t, WATER_CLASS_CANAL);
 	} else {
-		MakeWater(t);
+		SetWaterClass(t, WATER_CLASS_SEA);
 	}
 }
 
@@ -128,11 +161,19 @@
 
 	tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 
-	if (!IsWaterTile(tile) || !IsWaterTile(tile2))
+	if (!IsWaterTile(tile) || !IsWaterTile(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);
 
+	if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
+		/* Prevent depots on rapids */
+		return_cmd_error(STR_0239_SITE_UNSUITABLE);
+	}
+
+	WaterClass wc1 = GetWaterClass(tile);
+	WaterClass wc2 = GetWaterClass(tile2);
 	Owner o1 = GetTileOwner(tile);
 	Owner o2 = GetTileOwner(tile2);
 	ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
@@ -147,8 +188,8 @@
 	if (flags & DC_EXEC) {
 		depot->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
 
-		MakeShipDepot(tile,  _current_player, DEPOT_NORTH, axis, o1);
-		MakeShipDepot(tile2, _current_player, DEPOT_SOUTH, axis, o2);
+		MakeShipDepot(tile,  _current_player, DEPOT_NORTH, axis, wc1, o1);
+		MakeShipDepot(tile2, _current_player, DEPOT_SOUTH, axis, wc2, o2);
 		MarkTileDirtyByTile(tile);
 		MarkTileDirtyByTile(tile2);
 		d_auto_delete.Detach();
@@ -157,12 +198,14 @@
 	return CommandCost(EXPENSES_CONSTRUCTION, _price.build_ship_depot);
 }
 
-void MakeWaterOrCanalDependingOnOwner(TileIndex tile, Owner o)
+void MakeWaterKeepingClass(TileIndex tile, Owner o)
 {
-	if (o == OWNER_WATER) {
-		MakeWater(tile);
-	} else {
-		MakeCanal(tile, o, Random());
+	assert(IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_STATION) && (IsBuoy(tile) || IsDock(tile))));
+
+	switch (GetWaterClass(tile)) {
+		case WATER_CLASS_SEA:   MakeWater(tile);              break;
+		case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break;
+		case WATER_CLASS_RIVER: MakeRiver(tile, Random());    break;
 	}
 }
 
@@ -182,8 +225,8 @@
 		/* Kill the depot, which is registered at the northernmost tile. Use that one */
 		delete GetDepotByTile(tile2 < tile ? tile2 : tile);
 
-		MakeWaterOrCanalDependingOnOwner(tile,  GetShipDepotWaterOwner(tile));
-		MakeWaterOrCanalDependingOnOwner(tile2, GetShipDepotWaterOwner(tile2));
+		MakeWaterKeepingClass(tile,  GetShipDepotWaterOwner(tile));
+		MakeWaterKeepingClass(tile2, GetShipDepotWaterOwner(tile2));
 		MarkTileDirtyByTile(tile);
 		MarkTileDirtyByTile(tile2);
 	}
@@ -203,6 +246,8 @@
 
 	delta = TileOffsByDiagDir(dir);
 	/* lower tile */
+	WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL;
+
 	ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(ret)) return CMD_ERROR;
 	if (GetTileSlope(tile - delta, NULL) != SLOPE_FLAT) {
@@ -210,6 +255,8 @@
 	}
 
 	/* upper tile */
+	WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL;
+
 	ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(ret)) return CMD_ERROR;
 	if (GetTileSlope(tile + delta, NULL) != SLOPE_FLAT) {
@@ -223,10 +270,12 @@
 	}
 
 	if (flags & DC_EXEC) {
-		MakeLock(tile, _current_player, dir);
+		MakeLock(tile, _current_player, dir, wc_lower, wc_upper);
 		MarkTileDirtyByTile(tile);
 		MarkTileDirtyByTile(tile - delta);
 		MarkTileDirtyByTile(tile + delta);
+		MarkCanalsAndRiversAroundDirty(tile - delta);
+		MarkCanalsAndRiversAroundDirty(tile + delta);
 	}
 
 	return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 22 >> 3);
@@ -244,30 +293,17 @@
 
 	if (flags & DC_EXEC) {
 		DoClearSquare(tile);
-		MakeWaterOrCanalDependingOnSurroundings(tile + delta, _current_player);
-		MakeWaterOrCanalDependingOnSurroundings(tile - delta, _current_player);
+		MakeWaterKeepingClass(tile + delta, GetTileOwner(tile));
+		MakeWaterKeepingClass(tile - delta, GetTileOwner(tile));
+		MarkTileDirtyByTile(tile - delta);
+		MarkTileDirtyByTile(tile + delta);
+		MarkCanalsAndRiversAroundDirty(tile - delta);
+		MarkCanalsAndRiversAroundDirty(tile + delta);
 	}
 
 	return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water * 2);
 }
 
-/**
- * Marks the tiles around a tile as dirty.
- *
- * This functions marks the tiles around a given tile as dirty for repaint.
- *
- * @param tile The center of the tile where all other tiles are marked as dirty
- * @ingroup dirty
- * @see TerraformAddDirtyTileAround
- */
-static void MarkTilesAroundDirty(TileIndex tile)
-{
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, 1));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 0, -1));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, 1, 0));
-	MarkTileDirtyByTile(TILE_ADDXY(tile, -1, 0));
-}
-
 /** Builds a lock (ship-lift)
  * @param tile tile where to place the lock
  * @param flags type of operation
@@ -276,15 +312,12 @@
  */
 CommandCost CmdBuildLock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	DiagDirection dir;
+	DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
+	if (dir == INVALID_DIAGDIR) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
-	switch (GetTileSlope(tile, NULL)) {
-		case SLOPE_SW: dir = DIAGDIR_SW; break;
-		case SLOPE_SE: dir = DIAGDIR_SE; break;
-		case SLOPE_NW: dir = DIAGDIR_NW; break;
-		case SLOPE_NE: dir = DIAGDIR_NE; break;
-		default: return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-	}
+	/* Disallow building of locks on river rapids */
+	if (IsWaterTile(tile)) return_cmd_error(STR_0239_SITE_UNSUITABLE);
+
 	return DoBuildShiplift(tile, dir, flags);
 }
 
@@ -292,7 +325,7 @@
  * @param tile end tile of stretch-dragging
  * @param flags type of operation
  * @param p1 start tile of stretch-dragging
- * @param p2 ctrl pressed - toggles ocean / canals at sealevel (ocean only allowed in the scenario editor)
+ * @param p2 specifies canal (0), water (1) or river (2); last two can only be built in scenario editor
  */
 CommandCost CmdBuildCanal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
@@ -324,7 +357,7 @@
 		CommandCost ret;
 
 		Slope slope = GetTileSlope(tile, NULL);
-		if (slope != SLOPE_FLAT && (p2 != 2 || (slope != SLOPE_NW && slope != SLOPE_NE && slope != SLOPE_SW && slope != SLOPE_SE))) {
+		if (slope != SLOPE_FLAT && (p2 != 2 || !IsInclinedSlope(slope))) {
 			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 		}
 
@@ -344,7 +377,7 @@
 				MakeCanal(tile, _current_player, Random());
 			}
 			MarkTileDirtyByTile(tile);
-			MarkTilesAroundDirty(tile);
+			MarkCanalsAndRiversAroundDirty(tile);
 		}
 
 		cost.AddCost(_price.clear_water);
@@ -361,7 +394,6 @@
 {
 	switch (GetWaterTileType(tile)) {
 		case WATER_TILE_CLEAR:
-		case WATER_TILE_RIVER:
 			if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
 
 			/* Make sure it's not an edge tile. */
@@ -375,7 +407,10 @@
 
 			if (GetTileOwner(tile) != OWNER_WATER && GetTileOwner(tile) != OWNER_NONE && !CheckTileOwnership(tile)) return CMD_ERROR;
 
-			if (flags & DC_EXEC) DoClearSquare(tile);
+			if (flags & DC_EXEC) {
+				DoClearSquare(tile);
+				MarkCanalsAndRiversAroundDirty(tile);
+			}
 			return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
 
 		case WATER_TILE_COAST: {
@@ -384,8 +419,11 @@
 			/* Make sure no vehicle is on the tile */
 			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 
-			if (flags & DC_EXEC) DoClearSquare(tile);
-			if (slope == SLOPE_N || slope == SLOPE_E || slope == SLOPE_S || slope == SLOPE_W) {
+			if (flags & DC_EXEC) {
+				DoClearSquare(tile);
+				MarkCanalsAndRiversAroundDirty(tile);
+			}
+			if (IsSlopeWithOneCornerRaised(slope)) {
 				return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_water);
 			} else {
 				return CommandCost(EXPENSES_CONSTRUCTION, _price.clear_roughland);
@@ -414,26 +452,41 @@
 	}
 }
 
-/** return true if a tile is a water tile. */
-static bool IsWateredTile(TileIndex tile)
+/**
+ * return true if a tile is a water tile wrt. a certain direction.
+ *
+ * @param tile The tile of interest.
+ * @param from The direction of interest.
+ * @return true iff the tile is water in the view of 'from'.
+ *
+ */
+static bool IsWateredTile(TileIndex tile, Direction from)
 {
 	switch (GetTileType(tile)) {
 		case MP_WATER:
 			if (!IsCoast(tile)) return true;
-
 			switch (GetTileSlope(tile, NULL)) {
-				case SLOPE_W:
-				case SLOPE_S:
-				case SLOPE_E:
-				case SLOPE_N:
-					return true;
-
-				default:
-					return false;
+				case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
+				case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
+				case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
+				case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
+				default: return false;
 			}
 
-		case MP_RAILWAY:  return GetRailGroundType(tile) == RAIL_GROUND_WATER;
-		case MP_STATION:  return IsCustomFSMportsSpecIndex(tile) || IsOilRig(tile) || IsDock(tile) || IsBuoy(tile);
+		case MP_RAILWAY:
+			if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
+				assert(IsPlainRailTile(tile));
+				switch (GetTileSlope(tile, NULL)) {
+					case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE);
+					case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW);
+					case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW);
+					case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE);
+					default: return false;
+				}
+			}
+			return false;
+
+		case MP_STATION:  return IsCustomFSMportsSpecIndex(tile) || IsOilRig(tile) || (IsDock(tile) && GetTileSlope(tile, NULL) == SLOPE_FLAT) || IsBuoy(tile);
 		case MP_INDUSTRY: return (GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0;
 		default:          return false;
 	}
@@ -444,10 +497,10 @@
 	uint wa;
 
 	/* determine the edges around with water. */
-	wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0)) << 0;
-	wa += IsWateredTile(TILE_ADDXY(tile,  0,  1)) << 1;
-	wa += IsWateredTile(TILE_ADDXY(tile,  1,  0)) << 2;
-	wa += IsWateredTile(TILE_ADDXY(tile,  0, -1)) << 3;
+	wa  = IsWateredTile(TILE_ADDXY(tile, -1,  0), DIR_SW) << 0;
+	wa += IsWateredTile(TILE_ADDXY(tile,  0,  1), DIR_NW) << 1;
+	wa += IsWateredTile(TILE_ADDXY(tile,  1,  0), DIR_NE) << 2;
+	wa += IsWateredTile(TILE_ADDXY(tile,  0, -1), DIR_SE) << 3;
 
 	if (!(wa & 1)) DrawGroundSprite(base,     PAL_NONE);
 	if (!(wa & 2)) DrawGroundSprite(base + 1, PAL_NONE);
@@ -457,31 +510,39 @@
 	/* right corner */
 	switch (wa & 0x03) {
 		case 0: DrawGroundSprite(base + 4, PAL_NONE); break;
-		case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(base + 8, PAL_NONE); break;
+		case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawGroundSprite(base + 8, PAL_NONE); break;
 	}
 
 	/* bottom corner */
 	switch (wa & 0x06) {
 		case 0: DrawGroundSprite(base + 5, PAL_NONE); break;
-		case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(base + 9, PAL_NONE); break;
+		case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawGroundSprite(base + 9, PAL_NONE); break;
 	}
 
 	/* left corner */
 	switch (wa & 0x0C) {
 		case  0: DrawGroundSprite(base + 6, PAL_NONE); break;
-		case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(base + 10, PAL_NONE); break;
+		case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawGroundSprite(base + 10, PAL_NONE); break;
 	}
 
 	/* upper corner */
 	switch (wa & 0x09) {
 		case 0: DrawGroundSprite(base + 7, PAL_NONE); break;
-		case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(base + 11, PAL_NONE); break;
+		case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawGroundSprite(base + 11, PAL_NONE); break;
 	}
 }
 
+/** Draw a plain sea water tile with no edges */
+void DrawSeaWater(TileIndex tile)
+{
+	DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
+}
+
 /** draw a canal styled water tile with dikes around */
-void DrawCanalWater(TileIndex tile)
+void DrawCanalWater(TileIndex tile, bool draw_base)
 {
+	if (draw_base) DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
+
 	/* Test for custom graphics, else use the default */
 	SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile);
 	if (dikes_base == 0) dikes_base = SPR_CANAL_DIKES_BASE;
@@ -527,7 +588,7 @@
 	}
 }
 
-static void DrawRiverWater(const TileInfo *ti)
+void DrawRiverWater(const TileInfo *ti, bool draw_base)
 {
 	SpriteID image = SPR_FLAT_WATER_TILE;
 	SpriteID edges_base = GetCanalSprite(CF_RIVER_EDGE, ti->tile);
@@ -535,7 +596,13 @@
 	if (ti->tileh != SLOPE_FLAT) {
 		image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile);
 		if (image == 0) {
-			image = SPR_FLAT_WATER_TILE;
+			switch (ti->tileh) {
+				case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break;
+				case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP;   break;
+				case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP;   break;
+				case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break;
+				default:       image = SPR_FLAT_WATER_TILE;    break;
+			}
 		} else {
 			switch (ti->tileh) {
 				default: NOT_REACHED();
@@ -547,11 +614,10 @@
 		}
 	}
 
-	DrawGroundSprite(image, PAL_NONE);
+	if (draw_base) DrawGroundSprite(image, PAL_NONE);
 
-	/* Draw canal dikes if there are no river edges to draw. */
-	if (edges_base <= 48) edges_base = SPR_CANAL_DIKES_BASE;
-	DrawWaterEdges(edges_base, ti->tile);
+	/* Draw river edges if available. */
+	if (edges_base > 48) DrawWaterEdges(edges_base, ti->tile);
 }
 
 void DrawShoreTile(Slope tileh)
@@ -575,8 +641,11 @@
 {
 	switch (GetWaterTileType(ti->tile)) {
 		case WATER_TILE_CLEAR:
-			DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
-			if (IsCanal(ti->tile)) DrawCanalWater(ti->tile);
+			switch (GetWaterClass(ti->tile)) {
+				case WATER_CLASS_SEA:   DrawSeaWater(ti->tile); break;
+				case WATER_CLASS_CANAL: DrawCanalWater(ti->tile, true); break;
+				case WATER_CLASS_RIVER: DrawRiverWater(ti, true); break;
+			}
 			DrawBridgeMiddle(ti);
 			break;
 
@@ -593,11 +662,6 @@
 		case WATER_TILE_DEPOT:
 			DrawWaterStuff(ti, _shipdepot_display_seq[GetSection(ti->tile)], PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile)), 0);
 			break;
-
-		case WATER_TILE_RIVER:
-			DrawRiverWater(ti);
-			DrawBridgeMiddle(ti);
-			break;
 	}
 }
 
@@ -636,7 +700,6 @@
 {
 	switch (GetWaterTileType(tile)) {
 		case WATER_TILE_CLEAR:
-		case WATER_TILE_RIVER:
 			if (!IsCanal(tile)) {
 				td->str = STR_3804_WATER;
 			} else {
@@ -657,17 +720,6 @@
 	/* not used */
 }
 
-/**
- * Marks tile dirty if it is a canal tile.
- * Called to avoid glitches when flooding tiles next to canal tile.
- *
- * @param tile tile to check
- */
-static inline void MarkTileDirtyIfCanal(TileIndex tile)
-{
-	if (IsTileType(tile, MP_WATER) && IsCanal(tile)) MarkTileDirtyByTile(tile);
-}
-
 
 /**
  * Finds a vehicle to flood.
@@ -803,7 +855,7 @@
 static FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
 {
 	/* FLOOD_ACTIVE:  'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, rail with flooded halftile
-	 * FLOOD_DRYUP:   coast with more than one corner raised
+	 * FLOOD_DRYUP:   coast with more than one corner raised, coast with rail-track, coast with trees
 	 * FLOOD_PASSIVE: oilrig, dock, water-industries
 	 * FLOOD_NONE:    canals, rivers, everything else
 	 */
@@ -811,16 +863,22 @@
 		case MP_WATER:
 			if (IsCoast(tile)) {
 				Slope tileh = GetTileSlope(tile, NULL);
-				return (HasBit(_active_water_slopes, tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
+				return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
 			} else {
-				return ((IsSea(tile) || (IsShipDepot(tile) && (GetShipDepotWaterOwner(tile) == OWNER_WATER))) ? FLOOD_ACTIVE : FLOOD_NONE);
+				return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
 			}
 
 		case MP_RAILWAY:
-			return ((GetRailGroundType(tile) == RAIL_GROUND_WATER) ? FLOOD_ACTIVE : FLOOD_NONE);
+			if (GetRailGroundType(tile) == RAIL_GROUND_WATER) {
+				return (IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)) ? FLOOD_ACTIVE : FLOOD_DRYUP);
+			}
+			return FLOOD_NONE;
+
+		case MP_TREES:
+			return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
 
 		case MP_STATION:
-			if (IsSeaBuoyTile(tile)) return FLOOD_ACTIVE;
+			if (IsBuoy(tile) && GetWaterClass(tile) == WATER_CLASS_SEA) return FLOOD_ACTIVE;
 			if (IsOilRig(tile) || IsDock(tile)) return FLOOD_PASSIVE;
 			if (GetStationByTile(tile)->FSMport_flood_protected) return FLOOD_PASSIVE;
 			return FLOOD_NONE;
@@ -844,7 +902,8 @@
 
 	_current_player = OWNER_WATER;
 
-	if (GetTileSlope(target, NULL) != SLOPE_FLAT) {
+	Slope tileh = GetTileSlope(target, NULL);
+	if (tileh != SLOPE_FLAT) {
 		/* make coast.. */
 		switch (GetTileType(target)) {
 			case MP_RAILWAY: {
@@ -858,8 +917,15 @@
 				break;
 			}
 
+			case MP_TREES:
+				if (!IsSlopeWithOneCornerRaised(tileh)) {
+					SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3);
+					MarkTileDirtyByTile(target);
+					flooded = true;
+					break;
+				}
+			/* FALL THROUGH */
 			case MP_CLEAR:
-			case MP_TREES:
 				if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
 					MakeShore(target);
 					MarkTileDirtyByTile(target);
@@ -888,9 +954,7 @@
 
 	if (flooded) {
 		/* Mark surrounding canal tiles dirty too to avoid glitches */
-		for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
-			MarkTileDirtyIfCanal(target + TileOffsByDir(dir));
-		}
+		MarkCanalsAndRiversAroundDirty(target);
 
 		/* update signals if needed */
 		UpdateSignalsInBuffer();
@@ -904,12 +968,40 @@
  */
 static void DoDryUp(TileIndex tile)
 {
-	assert(IsTileType(tile, MP_WATER) && IsCoast(tile));
 	_current_player = OWNER_WATER;
 
-	if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
-		MakeClear(tile, CLEAR_GRASS, 3);
-		MarkTileDirtyByTile(tile);
+	switch (GetTileType(tile)) {
+		case MP_RAILWAY:
+			assert(IsPlainRailTile(tile));
+			assert(GetRailGroundType(tile) == RAIL_GROUND_WATER);
+
+			RailGroundType new_ground;
+			switch (GetTrackBits(tile)) {
+				case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
+				case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
+				case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
+				case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
+				default: NOT_REACHED();
+			}
+			SetRailGroundType(tile, new_ground);
+			MarkTileDirtyByTile(tile);
+			break;
+
+		case MP_TREES:
+			SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3);
+			MarkTileDirtyByTile(tile);
+			break;
+
+		case MP_WATER:
+			assert(IsCoast(tile));
+
+			if (CmdSucceeded(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
+				MakeClear(tile, CLEAR_GRASS, 3);
+				MarkTileDirtyByTile(tile);
+			}
+			break;
+
+		default: NOT_REACHED();
 	}
 
 	_current_player = OWNER_NONE;
@@ -988,7 +1080,7 @@
 					FOR_EACH_SET_BIT(dir, check_dirs) {
 						TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir));
 						Slope slope_dest = (Slope)(GetTileSlope(dest, NULL) & ~SLOPE_STEEP);
-						if (HasBit(_active_water_slopes, slope_dest)) {
+						if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) {
 							MakeShore(tile);
 							break;
 						}
@@ -1008,11 +1100,10 @@
 	if (mode != TRANSPORT_WATER) return 0;
 
 	switch (GetWaterTileType(tile)) {
-		case WATER_TILE_CLEAR: ts = TRACK_BIT_ALL; break;
+		case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
 		case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
 		case WATER_TILE_LOCK:  ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
 		case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
-		case WATER_TILE_RIVER: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
 		default: return 0;
 	}
 	if (TileX(tile) == 0) {