1
0
Fork 0

(svn r5369) -Backport: 5363, 5364, 5365

-Fix: It was possible to dig into a tunnel if certain rail combinations were ontop of it
release/0.4
tron 2006-06-26 15:59:58 +00:00
parent a2fc417d86
commit 22df8a8d6b
10 changed files with 124 additions and 56 deletions

View File

@ -669,6 +669,7 @@ SRCS += town_gui.c
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

View File

@ -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 void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
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 @@ int32 CmdTerraformLand(int x, int y, uint32 flags, uint32 p1, uint32 p2)
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;
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;
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);
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;
}
}

View File

@ -922,6 +922,10 @@ SOURCE=.\tree_cmd.c
# 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

View File

@ -724,6 +724,9 @@
<File
RelativePath=".\tree_cmd.c">
</File>
<File
RelativePath=".\tunnel_map.c">
</File>
<File
RelativePath=".\tunnelbridge_cmd.c">
</File>

View File

@ -130,7 +130,7 @@ static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags
}
const TrackBits _valid_tileh_slopes[4][15] = {
static const TrackBits _valid_tileh_slopes[][15] = {
// set of normal ones
{

11
slope.h
View File

@ -27,4 +27,15 @@ typedef enum Slope {
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

42
tile.c
View File

@ -15,37 +15,14 @@ uint GetMapExtraBits(TileIndex tile)
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 @@ uint GetTileSlope(TileIndex tile, uint *h)
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)

1
tile.h
View File

@ -48,7 +48,6 @@ typedef enum DiagonalDirections {
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);

31
tunnel_map.c 100644
View File

@ -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);
}

View File

@ -20,4 +20,7 @@ static inline uint GetTunnelDirection(TileIndex t)
return (uint)GB(_m[t].m5, 0, 2);
}
bool IsTunnelInWay(TileIndex, uint z);
#endif