(svn r11947) -Feature: Make use of new sprites added by Action5 type 0D.
authorfrosch
Tue, 22 Jan 2008 17:48:08 +0000
changeset 8380 174326093caa
parent 8379 94fcc26a241a
child 8381 9f861b4e8f48
(svn r11947) -Feature: Make use of new sprites added by Action5 type 0D.
Tiles which only consist of shore do not flood anymore, instead they get removed if they are no longer connected to flooding water.
src/genworld.cpp
src/landscape.cpp
src/landscape.h
src/map_func.h
src/water.h
src/water_cmd.cpp
--- a/src/genworld.cpp	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/genworld.cpp	Tue Jan 22 17:48:08 2008 +0000
@@ -24,6 +24,7 @@
 #include "engine.h"
 #include "settings_type.h"
 #include "newgrf_storage.h"
+#include "water.h"
 
 #include "table/sprites.h"
 
--- a/src/landscape.cpp	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/landscape.cpp	Tue Jan 22 17:48:08 2008 +0000
@@ -23,6 +23,7 @@
 #include "date_func.h"
 #include "vehicle_func.h"
 #include "settings_type.h"
+#include "water.h"
 
 #include "table/sprites.h"
 
@@ -292,11 +293,12 @@
 	if ((tileh & ~SLOPE_HALFTILE_MASK) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
 }
 
-static Slope GetFoundationSlope(TileIndex tile, uint* z)
+Slope GetFoundationSlope(TileIndex tile, uint* z)
 {
 	Slope tileh = GetTileSlope(tile, z);
 	Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
-	*z += ApplyFoundationToSlope(f, &tileh);
+	uint z_inc = ApplyFoundationToSlope(f, &tileh);
+	if (z != NULL) *z += z_inc;
 	return tileh;
 }
 
@@ -637,53 +639,6 @@
 	for (x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
 }
 
-void ConvertGroundTilesIntoWaterTiles()
-{
-	TileIndex tile;
-	uint z;
-	Slope slope;
-
-	for (tile = 0; tile < MapSize(); ++tile) {
-		slope = GetTileSlope(tile, &z);
-		if (IsTileType(tile, MP_CLEAR) && z == 0) {
-			/* Make both water for tiles at level 0
-			 * and make shore, as that looks much better
-			 * during the generation. */
-			switch (slope) {
-				case SLOPE_FLAT:
-					MakeWater(tile);
-					break;
-
-				case SLOPE_N:
-				case SLOPE_E:
-				case SLOPE_S:
-				case SLOPE_W:
-					MakeShore(tile);
-					break;
-
-				case SLOPE_NW:
-					if (GetTileSlope(TileAddByDiagDir(tile, DIAGDIR_SE), NULL) != SLOPE_SE) MakeShore(tile);
-					break;
-
-				case SLOPE_SW:
-					if (GetTileSlope(TileAddByDiagDir(tile, DIAGDIR_NE), NULL) != SLOPE_NE) MakeShore(tile);
-					break;
-
-				case SLOPE_SE:
-					if (GetTileSlope(TileAddByDiagDir(tile, DIAGDIR_NW), NULL) != SLOPE_NW) MakeShore(tile);
-					break;
-
-				case SLOPE_NE:
-					if (GetTileSlope(TileAddByDiagDir(tile, DIAGDIR_SW), NULL) != SLOPE_SW) MakeShore(tile);
-					break;
-
-				default:
-					break;
-			}
-		}
-	}
-}
-
 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
 
--- a/src/landscape.h	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/landscape.h	Tue Jan 22 17:48:08 2008 +0000
@@ -32,6 +32,7 @@
 uint GetSlopeZ(int x, int y);
 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2);
 int GetSlopeZInCorner(Slope tileh, Corner corner);
+Slope GetFoundationSlope(TileIndex tile, uint* z);
 
 static inline Point RemapCoords(int x, int y, int z)
 {
@@ -55,8 +56,6 @@
 void InitializeLandscape();
 void GenerateLandscape(byte mode);
 
-void ConvertGroundTilesIntoWaterTiles();
-
 TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng);
 
 #endif /* LANDSCAPE_H */
--- a/src/map_func.h	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/map_func.h	Tue Jan 22 17:48:08 2008 +0000
@@ -244,6 +244,20 @@
 }
 
 /**
+ * Returns the TileIndexDiffC offset from a Direction.
+ *
+ * @param dir The given direction
+ * @return The offset as TileIndexDiffC value
+ */
+static inline TileIndexDiffC TileIndexDiffCByDir(Direction dir)
+{
+	extern const TileIndexDiffC _tileoffs_by_dir[DIR_END];
+
+	assert(IsValidDirection(dir));
+	return _tileoffs_by_dir[dir];
+}
+
+/**
  * Add a TileIndexDiffC to a TileIndex and returns the new one.
  *
  * Returns tile + the diff given in diff. If the result tile would end up
--- a/src/water.h	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/water.h	Tue Jan 22 17:48:08 2008 +0000
@@ -6,10 +6,15 @@
 #define WATER_H
 
 void TileLoop_Water(TileIndex tile);
+bool FloodHalftile(TileIndex t);
+
+void ConvertGroundTilesIntoWaterTiles();
+
 void DrawShipDepotSprite(int x, int y, int image);
 void DrawCanalWater(TileIndex tile);
+void DrawShoreTile(Slope tileh);
+
 void MakeWaterOrCanalDependingOnOwner(TileIndex tile, Owner o);
 void MakeWaterOrCanalDependingOnSurroundings(TileIndex t, Owner o);
-bool FloodHalftile(TileIndex t);
 
 #endif /* WATER_H */
--- a/src/water_cmd.cpp	Tue Jan 22 16:08:17 2008 +0000
+++ b/src/water_cmd.cpp	Tue Jan 22 17:48:08 2008 +0000
@@ -33,12 +33,46 @@
 #include "variables.h"
 #include "player_func.h"
 #include "settings_type.h"
+#include "clear_map.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
 
-static Vehicle *FindFloodableVehicleOnTile(TileIndex tile);
-static void FloodVehicle(Vehicle *v);
+/**
+ * Describes the behaviour of a tile during flooding.
+ */
+enum FloodingBehaviour {
+	FLOOD_NONE,    ///< The tile does not flood neighboured tiles.
+	FLOOD_ACTIVE,  ///< The tile floods neighboured tiles.
+	FLOOD_PASSIVE, ///< The tile does not actively flood neighboured tiles, but it prevents them from drying up.
+	FLOOD_DRYUP,   ///< The tile drys up if it is not constantly flooded from neighboured tiles.
+};
+
+/**
+ * Describes from which directions a specific slope can be flooded (if the tile is floodable at all).
+ */
+static const uint8 _flood_from_dirs[] = {
+	(1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT
+	(1 << DIR_NE) | (1 << DIR_SE),                                 // SLOPE_W
+	(1 << DIR_NW) | (1 << DIR_NE),                                 // SLOPE_S
+	(1 << DIR_NE),                                                 // SLOPE_SW
+	(1 << DIR_NW) | (1 << DIR_SW),                                 // SLOPE_E
+	0,                                                             // SLOPE_EW
+	(1 << DIR_NW),                                                 // SLOPE_SE
+	(1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE),                 // SLOPE_WSE, SLOPE_STEEP_S
+	(1 << DIR_SW) | (1 << DIR_SE),                                 // SLOPE_N
+	(1 << DIR_SE),                                                 // SLOPE_NW
+	0,                                                             // SLOPE_NS
+	(1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE),                 // SLOPE_NWS, SLOPE_STEEP_W
+	(1 << DIR_SW),                                                 // SLOPE_NE
+	(1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE),                 // SLOPE_ENW, SLOPE_STEEP_N
+	(1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW),                 // SLOPE_SEN, SLOPE_STEEP_E
+};
+
+/**
+ * Slopes that contain flat water and not only shore.
+ */
+static const uint32 _active_water_slopes = (1 << SLOPE_FLAT) | (1 << SLOPE_W) | (1 << SLOPE_S) | (1 << SLOPE_E) | (1 << SLOPE_N);
 
 /**
  * Makes a tile canal or water depending on the surroundings.
@@ -520,6 +554,23 @@
 	DrawWaterEdges(edges_base, ti->tile);
 }
 
+void DrawShoreTile(Slope tileh)
+{
+	/* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
+	 * This allows to calculate the proper sprite to display for this Slope */
+	static const byte tileh_to_shoresprite[32] = {
+		0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
+		0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
+	};
+
+	assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier.
+	assert(tileh != SLOPE_FLAT);     // Shore is never flat
+
+	assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour
+
+	DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE);
+}
+
 static void DrawTile_Water(TileInfo *ti)
 {
 	switch (GetWaterTileType(ti->tile)) {
@@ -530,15 +581,7 @@
 			break;
 
 		case WATER_TILE_COAST: {
-			/* Converts the enum Slope into an offset based on SPR_SHORE_BASE.
-			 * This allows to calculate the proper sprite to display for this Slope */
-			static const byte tileh_to_shoresprite[32] = {
-				0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0,
-				0, 0, 0, 0, 0,  0, 0, 0, 0, 0,  0,  5,  0, 10, 15, 0,
-			};
-
-			assert(!IsSteepSlope(ti->tileh));
-			DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[ti->tileh], PAL_NONE);
+			DrawShoreTile(ti->tileh);
 			DrawBridgeMiddle(ti);
 		} break;
 
@@ -625,84 +668,6 @@
 	if (IsTileType(tile, MP_WATER) && IsCanal(tile)) MarkTileDirtyByTile(tile);
 }
 
-/**
- * Floods neighboured floodable tiles
- *
- * @param tile The water source tile that causes the flooding.
- * @param offs[0] Destination tile to flood.
- * @param offs[1] First corner of edge between source and dest tile.
- * @param offs[2] Second corder of edge between source and dest tile.
- * @param offs[3] Third corner of dest tile.
- * @param offs[4] Fourth corner of dest tile.
- */
-static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs)
-{
-	TileIndex target = TILE_ADD(tile, ToTileIndexDiff(offs[0]));
-
-	/* type of this tile mustn't be water already. */
-	if (IsTileType(target, MP_WATER)) return;
-
-	/* Are both corners of the edge between source and dest on height 0 ? */
-	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 ||
-			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) {
-		return;
-	}
-
-	bool flooded = false; // Will be set to true, when something is flooded
-
-	/* Is any corner of the dest tile raised? (First two corners already checked above. */
-	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[3]))) != 0 ||
-			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[4]))) != 0) {
-		/* make coast.. */
-		switch (GetTileType(target)) {
-			case MP_RAILWAY: {
-				if (!IsPlainRailTile(target)) break;
-
-				flooded = FloodHalftile(target);
-
-				Vehicle *v = FindFloodableVehicleOnTile(target);
-				if (v != NULL) FloodVehicle(v);
-
-				break;
-			}
-
-			case MP_CLEAR:
-			case MP_TREES:
-				_current_player = OWNER_WATER;
-				if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
-					flooded = true;
-					MakeShore(target);
-					MarkTileDirtyByTile(target);
-				}
-				break;
-
-			default:
-				break;
-		}
-	} else {
-		/* Flood vehicles */
-		_current_player = OWNER_WATER;
-
-		Vehicle *v = FindFloodableVehicleOnTile(target);
-		if (v != NULL) FloodVehicle(v);
-
-		/* flood flat tile */
-		if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
-			flooded = true;
-			MakeWater(target);
-			MarkTileDirtyByTile(target);
-		}
-	}
-
-	if (flooded) {
-		/* Mark surrounding canal tiles dirty too to avoid glitches */
-		for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
-			MarkTileDirtyIfCanal(target + TileOffsByDir(dir));
-		}
-		/* update signals if needed */
-		UpdateSignalsInBuffer();
-	}
-}
 
 /**
  * Finds a vehicle to flood.
@@ -827,6 +792,122 @@
 }
 
 /**
+ * Returns the behaviour of a tile during flooding.
+ *
+ * @return Behaviour of the tile
+ */
+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_PASSIVE: oilrig, dock, water-industries
+	 * FLOOD_NONE:    canals, rivers, everything else
+	 */
+	switch (GetTileType(tile)) {
+		case MP_WATER:
+			if (IsCoast(tile)) {
+				Slope tileh = GetTileSlope(tile, NULL);
+				return (HasBit(_active_water_slopes, tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP);
+			} else {
+				return ((IsSea(tile) || (IsShipDepot(tile) && (GetShipDepotWaterOwner(tile) == OWNER_WATER))) ? FLOOD_ACTIVE : FLOOD_NONE);
+			}
+
+		case MP_RAILWAY:
+			return ((GetRailGroundType(tile) == RAIL_GROUND_WATER) ? FLOOD_ACTIVE : FLOOD_NONE);
+
+		case MP_STATION:
+			if (IsSeaBuoyTile(tile)) return FLOOD_ACTIVE;
+			if (IsOilRig(tile) || IsDock(tile)) return FLOOD_PASSIVE;
+			return FLOOD_NONE;
+
+		case MP_INDUSTRY:
+			return ((GetIndustrySpec(GetIndustryType(tile))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0 ? FLOOD_PASSIVE : FLOOD_NONE);
+
+		default:
+			return FLOOD_NONE;
+	}
+}
+
+/**
+ * Floods a tile.
+ */
+static void DoFloodTile(TileIndex target)
+{
+	if (IsTileType(target, MP_WATER)) return;
+
+	bool flooded = false; // Will be set to true if something is changed.
+
+	_current_player = OWNER_WATER;
+
+	if (GetTileSlope(target, NULL) != SLOPE_FLAT) {
+		/* make coast.. */
+		switch (GetTileType(target)) {
+			case MP_RAILWAY: {
+				if (!IsPlainRailTile(target)) break;
+
+				flooded = FloodHalftile(target);
+
+				Vehicle *v = FindFloodableVehicleOnTile(target);
+				if (v != NULL) FloodVehicle(v);
+
+				break;
+			}
+
+			case MP_CLEAR:
+			case MP_TREES:
+				if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
+					MakeShore(target);
+					MarkTileDirtyByTile(target);
+					flooded = true;
+				}
+				break;
+
+			default:
+				break;
+		}
+	} else {
+		/* Flood vehicles */
+		Vehicle *v = FindFloodableVehicleOnTile(target);
+		if (v != NULL) FloodVehicle(v);
+
+		/* flood flat tile */
+		if (CmdSucceeded(DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) {
+			MakeWater(target);
+			MarkTileDirtyByTile(target);
+			flooded = true;
+		}
+	}
+
+	if (flooded) {
+		/* Mark surrounding canal tiles dirty too to avoid glitches */
+		for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
+			MarkTileDirtyIfCanal(target + TileOffsByDir(dir));
+		}
+
+		/* update signals if needed */
+		UpdateSignalsInBuffer();
+	}
+
+	_current_player = OWNER_NONE;
+}
+
+/**
+ * Drys a tile up.
+ */
+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);
+	}
+
+	_current_player = OWNER_NONE;
+}
+
+/**
  * Let a water tile floods its diagonal adjoining tiles
  * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track()
  *
@@ -834,47 +915,79 @@
  */
 void TileLoop_Water(TileIndex tile)
 {
-	static const TileIndexDiffC _tile_loop_offs_array[][5] = {
-		// tile to mod              shore?    shore?
-		{{-1,  0}, {0, 0}, {0, 1}, {-1,  0}, {-1,  1}},
-		{{ 0,  1}, {0, 1}, {1, 1}, { 0,  2}, { 1,  2}},
-		{{ 1,  0}, {1, 0}, {1, 1}, { 2,  0}, { 2,  1}},
-		{{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}}
-	};
-
-	/* Ensure buoys on canal borders do not flood */
-	if (IsCanalBuoyTile(tile)) return;
-	/* Ensure only sea and coast floods, not canals or rivers */
-	if (IsTileType(tile, MP_WATER) && !(IsSea(tile) || IsCoast(tile))) return;
-
-	/* floods in all four diagonal directions with the exception of the edges */
-	if (IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1) &&
-			IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) {
-		uint i;
+	switch (GetFloodingBehaviour(tile)) {
+		case FLOOD_ACTIVE:
+			for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) {
+				TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir(dir));
+				if (dest == INVALID_TILE) continue;
 
-		for (i = 0; i != lengthof(_tile_loop_offs_array); i++) {
-			TileLoopWaterHelper(tile, _tile_loop_offs_array[i]);
-		}
-	}
-
-	/* _current_player can be changed by TileLoopWaterHelper.. reset it back here */
-	_current_player = OWNER_NONE;
+				uint z_dest;
+				Slope slope_dest = (Slope)(GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP);
+				if (z_dest > 0) continue;
 
-	/* edges */
-	if (TileX(tile) == 0 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //NE
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[2]);
-	}
+				if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue;
 
-	if (TileX(tile) == MapSizeX() - 2 && IsInsideMM(TileY(tile), 1, MapSizeY() - 3 + 1)) { //SW
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[0]);
-	}
+				DoFloodTile(dest);
+			}
+			break;
 
-	if (TileY(tile) == 0 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //NW
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[1]);
+		case FLOOD_DRYUP: {
+			Slope slope_here = (Slope)(GetFoundationSlope(tile, NULL) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP);
+			uint check_dirs = _flood_from_dirs[slope_here];
+			uint dir;
+			FOR_EACH_SET_BIT(dir, check_dirs) {
+				TileIndex dest = AddTileIndexDiffCWrap(tile, TileIndexDiffCByDir((Direction)dir));
+				if (dest == INVALID_TILE) continue;
+
+				FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest);
+				if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return;
+			}
+			DoDryUp(tile);
+			break;
+		}
+
+		default: return;
 	}
+}
 
-	if (TileY(tile) == MapSizeY() - 2 && IsInsideMM(TileX(tile), 1, MapSizeX() - 3 + 1)) { //SE
-		TileLoopWaterHelper(tile, _tile_loop_offs_array[3]);
+void ConvertGroundTilesIntoWaterTiles()
+{
+	TileIndex tile;
+	uint z;
+	Slope slope;
+
+	for (tile = 0; tile < MapSize(); ++tile) {
+		slope = GetTileSlope(tile, &z);
+		if (IsTileType(tile, MP_CLEAR) && z == 0) {
+			/* Make both water for tiles at level 0
+			 * and make shore, as that looks much better
+			 * during the generation. */
+			switch (slope) {
+				case SLOPE_FLAT:
+					MakeWater(tile);
+					break;
+
+				case SLOPE_N:
+				case SLOPE_E:
+				case SLOPE_S:
+				case SLOPE_W:
+					MakeShore(tile);
+					break;
+
+				default:
+					uint check_dirs = _flood_from_dirs[slope & ~SLOPE_STEEP];
+					uint dir;
+					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)) {
+							MakeShore(tile);
+							break;
+						}
+					}
+					break;
+			}
+		}
 	}
 }