|
|
|
@ -454,159 +454,90 @@ bool CheckTunnelInWay(TileIndex tile, int z)
|
|
|
|
|
DoCheckTunnelInWay(tile,z,3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static byte _build_tunnel_bh;
|
|
|
|
|
static byte _build_tunnel_railtype;
|
|
|
|
|
|
|
|
|
|
static int32 DoBuildTunnel(int x, int y, int x2, int y2, uint32 flags, uint exc_tile)
|
|
|
|
|
/** Build Tunnel.
|
|
|
|
|
* @param x,y start tile coord of tunnel
|
|
|
|
|
* @param p1 railtype, 0x200 for road tunnel
|
|
|
|
|
* @param p2 unused
|
|
|
|
|
*/
|
|
|
|
|
int32 CmdBuildTunnel(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|
|
|
|
{
|
|
|
|
|
TileIndexDiff delta;
|
|
|
|
|
TileIndex start_tile;
|
|
|
|
|
TileIndex end_tile;
|
|
|
|
|
int direction;
|
|
|
|
|
int32 cost, ret;
|
|
|
|
|
TileInfo ti;
|
|
|
|
|
uint z;
|
|
|
|
|
DiagDirection direction;
|
|
|
|
|
uint start_tileh;
|
|
|
|
|
uint end_tileh;
|
|
|
|
|
uint start_z;
|
|
|
|
|
uint end_z;
|
|
|
|
|
int32 cost;
|
|
|
|
|
int32 ret;
|
|
|
|
|
|
|
|
|
|
if ((uint)x > MapMaxX() * 16 - 1 || (uint)y > MapMaxY() * 16 - 1)
|
|
|
|
|
return CMD_ERROR;
|
|
|
|
|
|
|
|
|
|
/* check if valid, and make sure that (x,y) is smaller than (x2,y2) */
|
|
|
|
|
direction = 0;
|
|
|
|
|
if (x == x2) {
|
|
|
|
|
if (y == y2) return_cmd_error(STR_5008_CANNOT_START_AND_END_ON);
|
|
|
|
|
direction++;
|
|
|
|
|
if (y > y2) {
|
|
|
|
|
intswap(y,y2);
|
|
|
|
|
intswap(x,x2);
|
|
|
|
|
exc_tile |= 2;
|
|
|
|
|
}
|
|
|
|
|
} else if (y == y2) {
|
|
|
|
|
if (x > x2) {
|
|
|
|
|
intswap(y,y2);
|
|
|
|
|
intswap(x,x2);
|
|
|
|
|
exc_tile |= 2;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
|
|
|
|
|
}
|
|
|
|
|
_build_tunnel_endtile = 0;
|
|
|
|
|
|
|
|
|
|
cost = 0;
|
|
|
|
|
if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR;
|
|
|
|
|
|
|
|
|
|
FindLandscapeHeight(&ti, x2, y2);
|
|
|
|
|
end_tile = ti.tile;
|
|
|
|
|
z = ti.z;
|
|
|
|
|
start_tile = TileVirtXY(x, y);
|
|
|
|
|
start_tileh = GetTileSlope(start_tile, &start_z);
|
|
|
|
|
|
|
|
|
|
if (exc_tile != 3) {
|
|
|
|
|
if ((direction ? 9U : 12U) != ti.tileh)
|
|
|
|
|
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
|
|
|
|
|
ret = DoCommandByTile(ti.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
|
|
if (CmdFailed(ret)) return CMD_ERROR;
|
|
|
|
|
cost += ret;
|
|
|
|
|
switch (start_tileh) {
|
|
|
|
|
case 3: direction = DIAGDIR_SW; break;
|
|
|
|
|
case 6: direction = DIAGDIR_SE; break;
|
|
|
|
|
case 9: direction = DIAGDIR_NW; break;
|
|
|
|
|
case 12: direction = DIAGDIR_NE; break;
|
|
|
|
|
default: return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
|
|
|
|
|
}
|
|
|
|
|
cost += _price.build_tunnel;
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (direction) y2-=16; else x2-=16;
|
|
|
|
|
ret = DoCommandByTile(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
|
|
if (CmdFailed(ret)) return ret;
|
|
|
|
|
cost = _price.build_tunnel + ret;
|
|
|
|
|
|
|
|
|
|
if (x2 == x && y2 == y) break;
|
|
|
|
|
delta = TileOffsByDir(direction);
|
|
|
|
|
end_tile = start_tile;
|
|
|
|
|
for (;;) {
|
|
|
|
|
end_tile += delta;
|
|
|
|
|
end_tileh = GetTileSlope(end_tile, &end_z);
|
|
|
|
|
|
|
|
|
|
FindLandscapeHeight(&ti, x2, y2);
|
|
|
|
|
if (ti.z <= z) return CMD_ERROR;
|
|
|
|
|
if (start_z == end_z) break;
|
|
|
|
|
|
|
|
|
|
if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(ti.tile, z))
|
|
|
|
|
if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(end_tile, start_z)) {
|
|
|
|
|
return CMD_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cost += _price.build_tunnel;
|
|
|
|
|
cost += (cost >> 3);
|
|
|
|
|
|
|
|
|
|
cost += cost >> 3;
|
|
|
|
|
if (cost >= 400000000) cost = 400000000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FindLandscapeHeight(&ti, x2, y2);
|
|
|
|
|
if (ti.z != z) return CMD_ERROR;
|
|
|
|
|
// if the command fails from here on we want the end tile to be highlighted
|
|
|
|
|
_build_tunnel_endtile = end_tile;
|
|
|
|
|
|
|
|
|
|
if (exc_tile != 1) {
|
|
|
|
|
if ((direction ? 6U : 3U) != ti.tileh)
|
|
|
|
|
return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
|
|
|
|
|
|
|
|
|
|
ret = DoCommandByTile(ti.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
|
|
if (CmdFailed(ret)) return CMD_ERROR;
|
|
|
|
|
// slope of end tile must be complementary to the slope of the start tile
|
|
|
|
|
if (end_tileh != (15 ^ start_tileh)) {
|
|
|
|
|
ret = DoCommandByTile(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND);
|
|
|
|
|
if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
|
|
|
|
|
} else {
|
|
|
|
|
ret = DoCommandByTile(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
|
|
if (CmdFailed(ret)) return ret;
|
|
|
|
|
cost += ret;
|
|
|
|
|
}
|
|
|
|
|
cost += _price.build_tunnel;
|
|
|
|
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
|
|
ModifyTile(ti.tile,
|
|
|
|
|
MP_SETTYPE(MP_TUNNELBRIDGE) |
|
|
|
|
|
MP_MAP3LO | MP_MAPOWNER_CURRENT | MP_MAP5,
|
|
|
|
|
_build_tunnel_railtype, /* map3lo */
|
|
|
|
|
((_build_tunnel_bh << 1) | 2) - direction /* map5 */
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
ModifyTile(end_tile,
|
|
|
|
|
MP_SETTYPE(MP_TUNNELBRIDGE) |
|
|
|
|
|
MP_MAP3LO | MP_MAPOWNER_CURRENT | MP_MAP5,
|
|
|
|
|
_build_tunnel_railtype, /* map3lo */
|
|
|
|
|
(_build_tunnel_bh << 1) | (direction ? 3:0)/* map5 */
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
UpdateSignalsOnSegment(end_tile, direction?7:1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cost + _price.build_tunnel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Build Tunnel.
|
|
|
|
|
* @param x,y start tile coord of tunnel
|
|
|
|
|
* @param p1 railtype, 0x200 for road tunnel
|
|
|
|
|
* @param p2 unused
|
|
|
|
|
*/
|
|
|
|
|
int32 CmdBuildTunnel(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
|
|
|
|
{
|
|
|
|
|
TileInfo ti, tiorg;
|
|
|
|
|
int direction;
|
|
|
|
|
uint z;
|
|
|
|
|
static const int8 _build_tunnel_coord_mod[4+1] = { -16, 0, 16, 0, -16 };
|
|
|
|
|
static const byte _build_tunnel_tileh[4] = {3, 9, 12, 6};
|
|
|
|
|
TileIndex excavated_tile;
|
|
|
|
|
SetTileType(start_tile, MP_TUNNELBRIDGE);
|
|
|
|
|
SetTileOwner(start_tile, _current_player);
|
|
|
|
|
_m[start_tile].m3 = GB(p1, 0, 4); // rail type (if any)
|
|
|
|
|
_m[start_tile].m5 = (GB(p1, 9, 1) << 2) | direction; // transport type and entrance direction
|
|
|
|
|
|
|
|
|
|
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
|
|
|
|
|
SetTileType(end_tile, MP_TUNNELBRIDGE);
|
|
|
|
|
SetTileOwner(end_tile, _current_player);
|
|
|
|
|
_m[end_tile].m3 = GB(p1, 0, 4); // rail type (if any)
|
|
|
|
|
_m[end_tile].m5 = (GB(p1, 9, 1) << 2) | (direction ^ 2); // transport type and entrance direction
|
|
|
|
|
|
|
|
|
|
if (p1 != 0x200 && !ValParamRailtype(p1)) return CMD_ERROR;
|
|
|
|
|
|
|
|
|
|
_build_tunnel_railtype = GB(p1, 0, 8);
|
|
|
|
|
_build_tunnel_bh = GB(p1, 8, 8);
|
|
|
|
|
|
|
|
|
|
_build_tunnel_endtile = 0;
|
|
|
|
|
excavated_tile = 0;
|
|
|
|
|
|
|
|
|
|
FindLandscapeHeight(&tiorg, x, y);
|
|
|
|
|
|
|
|
|
|
if (!EnsureNoVehicle(tiorg.tile))
|
|
|
|
|
return CMD_ERROR;
|
|
|
|
|
|
|
|
|
|
if (!(direction=0, tiorg.tileh == 12) &&
|
|
|
|
|
!(direction++, tiorg.tileh == 6) &&
|
|
|
|
|
!(direction++, tiorg.tileh == 3) &&
|
|
|
|
|
!(direction++, tiorg.tileh == 9)) {
|
|
|
|
|
return_cmd_error(STR_500B_SITE_UNSUITABLE_FOR_TUNNEL);
|
|
|
|
|
if (GB(p1, 9, 1) == 0) UpdateSignalsOnSegment(start_tile, direction << 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
z = tiorg.z;
|
|
|
|
|
do {
|
|
|
|
|
x += _build_tunnel_coord_mod[direction];
|
|
|
|
|
y += _build_tunnel_coord_mod[direction+1];
|
|
|
|
|
FindLandscapeHeight(&ti, x, y);
|
|
|
|
|
} while (z != ti.z);
|
|
|
|
|
_build_tunnel_endtile = ti.tile;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!EnsureNoVehicle(ti.tile)) return CMD_ERROR;
|
|
|
|
|
|
|
|
|
|
if (ti.tileh != _build_tunnel_tileh[direction]) {
|
|
|
|
|
if (CmdFailed(DoCommandByTile(ti.tile, ti.tileh & ~_build_tunnel_tileh[direction], 0, flags, CMD_TERRAFORM_LAND)))
|
|
|
|
|
return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
|
|
|
|
|
excavated_tile = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DoBuildTunnel(x, y, tiorg.x, tiorg.y, flags, excavated_tile);
|
|
|
|
|
return cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
|
|
|
|
|