--- 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