(svn r5369) -Backport: 5363, 5364, 5365 0.4
authortron
Mon, 26 Jun 2006 15:59:58 +0000
branch0.4
changeset 10050 53795ed4cdaf
parent 10049 f1b796f03d9f
child 10051 bbf6202843c1
(svn r5369) -Backport: 5363, 5364, 5365
-Fix: It was possible to dig into a tunnel if certain rail combinations were ontop of it
Makefile
clear_cmd.c
openttd.dsp
openttd.vcproj
rail_cmd.c
slope.h
tile.c
tile.h
tunnel_map.c
tunnel_map.h
--- a/Makefile	Mon Jun 26 15:00:23 2006 +0000
+++ b/Makefile	Mon Jun 26 15:59:58 2006 +0000
@@ -669,6 +669,7 @@
 SRCS += train_cmd.c
 SRCS += train_gui.c
 SRCS += tree_cmd.c
+SRCS += tunnel_map.c
 SRCS += tunnelbridge_cmd.c
 SRCS += unmovable_cmd.c
 SRCS += vehicle.c
--- a/clear_cmd.c	Mon Jun 26 15:00:23 2006 +0000
+++ b/clear_cmd.c	Mon Jun 26 15:59:58 2006 +0000
@@ -9,6 +9,7 @@
 #include "tile.h"
 #include "viewport.h"
 #include "command.h"
+#include "tunnel_map.h"
 #include "variables.h"
 #include "table/sprites.h"
 
@@ -86,23 +87,59 @@
 static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
 {
 	int r;
+	int32 ret;
 
 	assert(tile < MapSize());
 
-	if ((r=TerraformAllowTileProcess(ts, tile)) <= 0)
-		return r;
+	r = TerraformAllowTileProcess(ts, tile);
+	if (r <= 0) return r;
 
-	if (!IsTileType(tile, MP_RAILWAY)) {
-		int32 ret = DoCommandByTile(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
+	if (IsTileType(tile, MP_RAILWAY)) {
+		static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
+		static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
 
-		if (CmdFailed(ret)) {
+		Slope tileh;
+		uint z;
+
+		// Nothing could be built at the steep slope - this avoids a bug
+		// when you have a single diagonal track in one corner on a
+		// basement and then you raise/lower the other corner.
+		tileh = GetTileSlope(tile, &z);
+		if (tileh == unsafe_slope[mode] ||
+				tileh == ComplementSlope(unsafe_slope[mode])) {
 			_terraform_err_tile = tile;
+			_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
 			return -1;
 		}
 
-		ts->cost += ret;
+		// If we have a single diagonal track there, the other side of
+		// tile can be terraformed.
+		if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
+			/* If terraforming downwards prevent damaging a potential tunnel below.
+			 * This check is only necessary for flat tiles, because if the tile is
+			 * non-flat, then the corner opposing the rail is raised. Only this corner
+			 * can be lowered and this is a safe action
+			 */
+			if (tileh == SLOPE_FLAT &&
+					ts->direction == -1 &&
+					IsTunnelInWay(tile, z - TILE_HEIGHT)) {
+				_terraform_err_tile = tile;
+				_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
+				return -1;
+			}
+			return 0;
+		}
 	}
 
+	ret = DoCommandByTile(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
+
+	if (ret == CMD_ERROR) {
+		_terraform_err_tile = tile;
+		return -1;
+	}
+
+	ts->cost += ret;
+
 	if (ts->tile_table_count >= 625) return -1;
 	ts->tile_table[ts->tile_table_count++] = tile;
 
@@ -233,35 +270,26 @@
 					return CMD_ERROR;
 	}
 
-	{ /* Check if tunnel or track would take damage */
+	if (direction == -1) {
+		/* Check if tunnel would take damage */
 		int count;
 		TileIndex *ti = ts.tile_table;
 
 		for (count = ts.tile_table_count; count != 0; count--, ti++) {
-			uint a, b, c, d, r, min;
+			uint z, t;
 			TileIndex tile = *ti;
 
-			_terraform_err_tile = tile;
-
-			a = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
-			b = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
-			c = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
-			d = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
-
-			r = GetTileh(a, b, c, d, &min);
+			z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
+			t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
+			if (t <= z) z = t;
+			t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
+			if (t <= z) z = t;
+			t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
+			if (t <= z) z = t;
 
-			if (IsTileType(tile, MP_RAILWAY)) {
-				if (IsSteepTileh(r)) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
-
-				if (IsPlainRailTile(tile)) {
-					extern const TrackBits _valid_tileh_slopes[2][15];
-					if (GetTrackBits(tile) & ~_valid_tileh_slopes[0][r]) return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
-				} else return_cmd_error(STR_5800_OBJECT_IN_THE_WAY);
+			if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
+				return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
 			}
-
-			if (direction == -1 && !CheckTunnelInWay(tile, min)) return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
-
-			_terraform_err_tile = 0;
 		}
 	}
 
--- a/openttd.dsp	Mon Jun 26 15:00:23 2006 +0000
+++ b/openttd.dsp	Mon Jun 26 15:59:58 2006 +0000
@@ -922,6 +922,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\tunnel_map.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\tunnelbridge_cmd.c
 # End Source File
 # Begin Source File
--- a/openttd.vcproj	Mon Jun 26 15:00:23 2006 +0000
+++ b/openttd.vcproj	Mon Jun 26 15:59:58 2006 +0000
@@ -725,6 +725,9 @@
 				RelativePath=".\tree_cmd.c">
 			</File>
 			<File
+				RelativePath=".\tunnel_map.c">
+			</File>
+			<File
 				RelativePath=".\tunnelbridge_cmd.c">
 			</File>
 			<File
--- a/rail_cmd.c	Mon Jun 26 15:00:23 2006 +0000
+++ b/rail_cmd.c	Mon Jun 26 15:59:58 2006 +0000
@@ -130,7 +130,7 @@
 }
 
 
-const TrackBits _valid_tileh_slopes[4][15] = {
+static const TrackBits _valid_tileh_slopes[][15] = {
 
 // set of normal ones
 {
--- a/slope.h	Mon Jun 26 15:00:23 2006 +0000
+++ b/slope.h	Mon Jun 26 15:59:58 2006 +0000
@@ -27,4 +27,15 @@
 	SLOPE_STEEP_N = SLOPE_STEEP | SLOPE_ENW
 } Slope;
 
+static inline bool IsSteepSlope(Slope s)
+{
+	return (s & SLOPE_STEEP) != 0;
+}
+
+static inline Slope ComplementSlope(Slope s)
+{
+	assert(!IsSteepSlope(s));
+	return (Slope)(0xF ^ s);
+}
+
 #endif
--- a/tile.c	Mon Jun 26 15:00:23 2006 +0000
+++ b/tile.c	Mon Jun 26 15:59:58 2006 +0000
@@ -15,37 +15,14 @@
 	return GB(_m[tile].extra, 0, 2);
 }
 
-/** Converts the heights of 4 corners into a tileh, and returns the minimum height of the tile
-  * @param n,w,e,s the four corners
-  * @param h uint pointer to write the height to
-  * @return the tileh
-*/
-uint GetTileh(uint n, uint w, uint e, uint s, uint *h)
-{
-	uint min = n;
-	uint r;
-
-	if (min >= w) min = w;
-	if (min >= e) min = e;
-	if (min >= s) min = s;
-
-	r = 0;
-	if ((n -= min) != 0) r += (--n << 4) + 8;
-	if ((e -= min) != 0) r += (--e << 4) + 4;
-	if ((s -= min) != 0) r += (--s << 4) + 2;
-	if ((w -= min) != 0) r += (--w << 4) + 1;
-
-	if (h != NULL) *h = min * 8;
-
-	return r;
-}
-
 uint GetTileSlope(TileIndex tile, uint *h)
 {
 	uint a;
 	uint b;
 	uint c;
 	uint d;
+	uint min;
+	uint r;
 
 	assert(tile < MapSize());
 
@@ -54,12 +31,23 @@
 		return 0;
 	}
 
-	a = TileHeight(tile);
+	min = a = TileHeight(tile);
 	b = TileHeight(tile + TileDiffXY(1, 0));
+	if (min >= b) min = b;
 	c = TileHeight(tile + TileDiffXY(0, 1));
+	if (min >= c) min = c;
 	d = TileHeight(tile + TileDiffXY(1, 1));
+	if (min >= d) min = d;
 
-	return GetTileh(a, b, c, d, h);
+	r = SLOPE_FLAT;
+	if ((a -= min) != 0) r += (--a << 4) + SLOPE_N;
+	if ((c -= min) != 0) r += (--c << 4) + SLOPE_E;
+	if ((d -= min) != 0) r += (--d << 4) + SLOPE_S;
+	if ((b -= min) != 0) r += (--b << 4) + SLOPE_W;
+
+	if (h != NULL) *h = min * TILE_HEIGHT;
+
+	return r;
 }
 
 uint GetTileZ(TileIndex tile)
--- a/tile.h	Mon Jun 26 15:00:23 2006 +0000
+++ b/tile.h	Mon Jun 26 15:59:58 2006 +0000
@@ -48,7 +48,6 @@
 void SetMapExtraBits(TileIndex tile, byte flags);
 uint GetMapExtraBits(TileIndex tile);
 
-uint GetTileh(uint n, uint w, uint e, uint s, uint *h);
 uint GetTileSlope(TileIndex tile, uint *h);
 uint GetTileZ(TileIndex tile);
 uint GetTileMaxZ(TileIndex tile);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tunnel_map.c	Mon Jun 26 15:59:58 2006 +0000
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "tile.h"
+#include "tunnel_map.h"
+
+static bool IsTunnelInWayDir(TileIndex tile, uint z, DiagDirection dir)
+{
+	TileIndexDiff delta = TileOffsByDir(dir);
+	uint height;
+
+	do {
+		tile -= delta;
+		height = GetTileZ(tile);
+	} while (z < height);
+
+	return
+		z == height &&
+		IsTunnelTile(tile) &&
+		GetTunnelDirection(tile) == dir;
+}
+
+bool IsTunnelInWay(TileIndex tile, uint z)
+{
+	return
+		IsTunnelInWayDir(tile, z, DIAGDIR_NE) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_SE) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_SW) ||
+		IsTunnelInWayDir(tile, z, DIAGDIR_NW);
+}
--- a/tunnel_map.h	Mon Jun 26 15:00:23 2006 +0000
+++ b/tunnel_map.h	Mon Jun 26 15:59:58 2006 +0000
@@ -20,4 +20,7 @@
 	return (uint)GB(_m[t].m5, 0, 2);
 }
 
+
+bool IsTunnelInWay(TileIndex, uint z);
+
 #endif