Changeset - r3063:8b842b479943
[Not reviewed]
master
0 1 0
tron - 18 years ago 2006-02-22 21:09:55
tron@openttd.org
(svn r3652) Rewrite CmdBuildTunnel in the hope to make it a bit more comprehensible
This implementation is also significantly shorter because it removes many redundant checks
1 file changed with 65 insertions and 134 deletions:
0 comments (0 inline, 0 general)
tunnelbridge_cmd.c
Show inline comments
 
@@ -454,104 +454,6 @@ bool CheckTunnelInWay(TileIndex tile, in
 
		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)
 
{
 
	TileIndex end_tile;
 
	int direction;
 
	int32 cost, ret;
 
	TileInfo ti;
 
	uint z;
 

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

	
 
	cost = 0;
 

	
 
	FindLandscapeHeight(&ti, x2, y2);
 
	end_tile = ti.tile;
 
	z = ti.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;
 
	}
 
	cost += _price.build_tunnel;
 

	
 
	for (;;) {
 
		if (direction) y2-=16; else x2-=16;
 

	
 
		if (x2 == x && y2 == y) break;
 

	
 
		FindLandscapeHeight(&ti, x2, y2);
 
		if (ti.z <= z) return CMD_ERROR;
 

	
 
		if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(ti.tile, z))
 
			return CMD_ERROR;
 

	
 
		cost += _price.build_tunnel;
 
		cost += (cost >> 3);
 

	
 
		if (cost >= 400000000) cost = 400000000;
 
	}
 

	
 
	FindLandscapeHeight(&ti, x2, y2);
 
	if (ti.z != z) return CMD_ERROR;
 

	
 
	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;
 
		cost += ret;
 
	}
 

	
 
	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
 
@@ -560,53 +462,82 @@ static int32 DoBuildTunnel(int x, int y,
 
 */
 
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;
 
	TileIndexDiff delta;
 
	TileIndex start_tile;
 
	TileIndex end_tile;
 
	DiagDirection direction;
 
	uint start_tileh;
 
	uint end_tileh;
 
	uint start_z;
 
	uint end_z;
 
	int32 cost;
 
	int32 ret;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
	_build_tunnel_endtile = 0;
 

	
 
	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);
 
	start_tile = TileVirtXY(x, y);
 
	start_tileh = GetTileSlope(start_tile, &start_z);
 

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

	
 
	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;
 
	ret = DoCommandByTile(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(ret)) return ret;
 
	cost = _price.build_tunnel + ret;
 

	
 
	delta = TileOffsByDir(direction);
 
	end_tile = start_tile;
 
	for (;;) {
 
		end_tile += delta;
 
		end_tileh = GetTileSlope(end_tile, &end_z);
 

	
 

	
 
	if (!EnsureNoVehicle(ti.tile)) return CMD_ERROR;
 
		if (start_z == end_z) break;
 

	
 
	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;
 
		if (!_cheats.crossing_tunnels.value && !CheckTunnelInWay(end_tile, start_z)) {
 
			return CMD_ERROR;
 
		}
 

	
 
		cost += _price.build_tunnel;
 
		cost += cost >> 3;
 
		if (cost >= 400000000) cost = 400000000;
 
	}
 

	
 
	return DoBuildTunnel(x, y, tiorg.x, tiorg.y, flags, excavated_tile);
 
	// if the command fails from here on we want the end tile to be highlighted
 
	_build_tunnel_endtile = end_tile;
 

	
 
	// 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) {
 
		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
 

	
 
		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 (GB(p1, 9, 1) == 0) UpdateSignalsOnSegment(start_tile, direction << 1);
 
	}
 

	
 
	return cost;
 
}
 

	
 
TileIndex CheckTunnelBusy(TileIndex tile, uint *length)
0 comments (0 inline, 0 general)