Changeset - r8371:32791d4d82d0
[Not reviewed]
master
0 1 0
frosch - 16 years ago 2008-01-21 15:48:00
frosch@openttd.org
(svn r11937) -Feature: Allow building bridge heads on more slopes.
These are SLOPE_NW, SLOPE_SW, SLOPE_SE, SLOPE_NE (with bridge perpendicular to the slope) and SLOPE_NS, SLOPE_EW.
1 file changed with 56 insertions and 72 deletions:
0 comments (0 inline, 0 general)
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -72,86 +72,88 @@ int CalcBridgeLenCostFactor(int x)
 
	int n;
 
	int r;
 

	
 
	if (x < 2) return x;
 
	x -= 2;
 
	for (n = 0, r = 2;; n++) {
 
		if (x <= n) return r + x * n;
 
		r += n * n;
 
		x -= n;
 
	}
 
}
 

	
 
#define M(x) (1 << (x))
 
enum BridgeFoundation {
 
	/* foundation, whole tile is leveled up --> 3 corners raised */
 
	BRIDGE_FULL_LEVELED_FOUNDATION = M(SLOPE_WSE) | M(SLOPE_NWS) | M(SLOPE_ENW) | M(SLOPE_SEN),
 
	/* foundation, tile is partly leveled up --> 1 corner raised */
 
	BRIDGE_PARTLY_LEVELED_FOUNDATION = M(SLOPE_W) | M(SLOPE_S) | M(SLOPE_E) | M(SLOPE_N),
 
	/* no foundations (X,Y direction) */
 
	BRIDGE_NO_FOUNDATION = M(SLOPE_FLAT) | M(SLOPE_SW) | M(SLOPE_SE) | M(SLOPE_NW) | M(SLOPE_NE),
 
	BRIDGE_HORZ_RAMP = (BRIDGE_PARTLY_LEVELED_FOUNDATION | BRIDGE_NO_FOUNDATION) & ~M(SLOPE_FLAT)
 
};
 
#undef M
 
Foundation GetBridgeFoundation(Slope tileh, Axis axis)
 
{
 
	if ((tileh == SLOPE_FLAT) ||
 
	    (((tileh == SLOPE_NE) || (tileh == SLOPE_SW)) && (axis == AXIS_X)) ||
 
	    (((tileh == SLOPE_NW) || (tileh == SLOPE_SE)) && (axis == AXIS_Y))) return FOUNDATION_NONE;
 

	
 
	return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh));
 
}
 

	
 
static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
 
{
 
	const Bridge *bridge = &_bridge[index];
 
	assert(table < 7);
 
	if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
 
		return _bridge_sprite_table[index][table];
 
	} else {
 
		return bridge->sprite_table[table];
 
	}
 
}
 

	
 
static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;}
 

	
 

	
 
/** Check the slope at the bridge ramps in three easy steps:
 
 * - valid slopes without foundation
 
 * - valid slopes with foundation
 
 * - rest is invalid
 
/**
 
 * Determines the foundation for the north bridge head, and tests if the resulting slope is valid.
 
 *
 
 * @param axis Axis of the bridge
 
 * @param tileh Slope of the tile under the north bridge head; returns slope on top of foundation
 
 * @param z TileZ corresponding to tileh, gets modified as well
 
 * @return Error or cost for bridge foundation
 
 */
 
#define M(x) (1 << (x))
 
static CommandCost CheckBridgeSlopeNorth(Axis axis, Slope tileh)
 
static CommandCost CheckBridgeSlopeNorth(Axis axis, Slope *tileh, uint *z)
 
{
 
	uint32 valid;
 
	Foundation f = GetBridgeFoundation(*tileh, axis);
 
	*z += ApplyFoundationToSlope(f, tileh);
 

	
 
	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW));
 
	if (HasBit(valid, tileh)) return CommandCost();
 
	Slope valid_inclined = (axis == AXIS_X ? SLOPE_NE : SLOPE_NW);
 
	if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR;
 

	
 
	valid =
 
		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) |
 
		(axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W));
 
	if (HasBit(valid, tileh)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
	if (f == FOUNDATION_NONE) return CommandCost();
 

	
 
	return CMD_ERROR;
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
}
 

	
 
static CommandCost CheckBridgeSlopeSouth(Axis axis, Slope tileh)
 
/**
 
 * Determines the foundation for the south bridge head, and tests if the resulting slope is valid.
 
 *
 
 * @param axis Axis of the bridge
 
 * @param tileh Slope of the tile under the south bridge head; returns slope on top of foundation
 
 * @param z TileZ corresponding to tileh, gets modified as well
 
 * @return Error or cost for bridge foundation
 
 */
 
static CommandCost CheckBridgeSlopeSouth(Axis axis, Slope *tileh, uint *z)
 
{
 
	uint32 valid;
 

	
 
	valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_SW) : M(SLOPE_SE));
 
	if (HasBit(valid, tileh)) return CommandCost();
 
	Foundation f = GetBridgeFoundation(*tileh, axis);
 
	*z += ApplyFoundationToSlope(f, tileh);
 

	
 
	valid =
 
		BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_S) | M(SLOPE_STEEP_S) |
 
		(axis == AXIS_X ? M(SLOPE_W) | M(SLOPE_STEEP_W) : M(SLOPE_E) | M(SLOPE_STEEP_E));
 
	if (HasBit(valid, tileh)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
	Slope valid_inclined = (axis == AXIS_X ? SLOPE_SW : SLOPE_SE);
 
	if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR;
 

	
 
	return CMD_ERROR;
 
	if (f == FOUNDATION_NONE) return CommandCost();
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
}
 
#undef M
 

	
 

	
 
uint32 GetBridgeLength(TileIndex begin, TileIndex end)
 
{
 
	int x1 = TileX(begin);
 
	int y1 = TileY(begin);
 
	int x2 = TileX(end);
 
	int y2 = TileY(end);
 

	
 
	return abs(x2 + y2 - x1 - y1) - 1;
 
}
 

	
 
@@ -189,26 +191,25 @@ CommandCost CmdBuildBridge(TileIndex end
 
	uint sy;
 
	TileIndex tile_start;
 
	TileIndex tile_end;
 
	Slope tileh_start;
 
	Slope tileh_end;
 
	uint z_start;
 
	uint z_end;
 
	TileIndex tile;
 
	TileIndexDiff delta;
 
	uint bridge_len;
 
	Axis direction;
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost terraformcost, ret;
 
	bool allow_on_slopes;
 
	CommandCost ret;
 
	bool replace_bridge = false;
 
	uint replaced_bridge_type;
 

	
 
	/* unpack parameters */
 
	bridge_type = GB(p2, 0, 8);
 

	
 
	if (p1 >= MapSize()) return CMD_ERROR;
 

	
 
	/* type of bridge */
 
	if (HasBit(p2, 15)) {
 
		railtype = INVALID_RAILTYPE; // road bridge
 
		roadtypes = (RoadTypes)GB(p2, 8, 3);
 
@@ -241,35 +242,29 @@ CommandCost CmdBuildBridge(TileIndex end
 
	if (!CheckBridge_Stuff(bridge_type, bridge_len)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
 

	
 
	/* retrieve landscape height and ensure it's on land */
 
	tile_start = TileXY(x, y);
 
	tile_end = TileXY(sx, sy);
 
	if (IsWaterTile(tile_start) || IsWaterTile(tile_end)) {
 
		return_cmd_error(STR_02A0_ENDS_OF_BRIDGE_MUST_BOTH);
 
	}
 

	
 
	tileh_start = GetTileSlope(tile_start, &z_start);
 
	tileh_end = GetTileSlope(tile_end, &z_end);
 

	
 
	if (IsSteepSlope(tileh_start)) z_start += TILE_HEIGHT;
 
	if (HasBit(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_start)) z_start += TILE_HEIGHT;
 

	
 
	if (IsSteepSlope(tileh_end)) z_end += TILE_HEIGHT;
 
	if (HasBit(BRIDGE_FULL_LEVELED_FOUNDATION, tileh_end)) z_end += TILE_HEIGHT;
 
	CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start);
 
	CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end, &z_end);
 

	
 
	if (z_start != z_end) return_cmd_error(STR_BRIDGEHEADS_NOT_SAME_HEIGHT);
 

	
 
	allow_on_slopes = (!_is_old_ai_player
 
	                   && _patches.build_on_slopes);
 

	
 
	TransportType transport_type = railtype == INVALID_RAILTYPE ? TRANSPORT_ROAD : TRANSPORT_RAIL;
 

	
 
	if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
 
			GetOtherBridgeEnd(tile_start) == tile_end &&
 
			GetTunnelBridgeTransportType(tile_start) == transport_type) {
 
		/* Replace a current bridge. */
 

	
 
		/* If this is a railway bridge, make sure the railtypes match. */
 
		if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) {
 
			return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
 
		}
 

	
 
@@ -296,44 +291,44 @@ CommandCost CmdBuildBridge(TileIndex end
 
			return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
 
		}
 

	
 
		cost.AddCost((bridge_len + 1) * _price.clear_bridge); // The cost of clearing the current bridge.
 
		replace_bridge = true;
 
		replaced_bridge_type = GetBridgeType(tile_start);
 

	
 
		/* Do not remove road types when upgrading a bridge */
 
		roadtypes |= GetRoadTypes(tile_start);
 
	} else {
 
		/* Build a new bridge. */
 

	
 
		bool allow_on_slopes = (!_is_old_ai_player && _patches.build_on_slopes);
 

	
 
		/* Try and clear the start landscape */
 
		ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
		if (CmdFailed(ret)) return ret;
 
		cost = ret;
 

	
 
		terraformcost = CheckBridgeSlopeNorth(direction, tileh_start);
 
		if (CmdFailed(terraformcost) || (terraformcost.GetCost() != 0 && !allow_on_slopes))
 
		if (CmdFailed(terraform_cost_north) || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes))
 
			return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
		cost.AddCost(terraformcost);
 
		cost.AddCost(terraform_cost_north);
 

	
 
		/* Try and clear the end landscape */
 
		ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
		if (CmdFailed(ret)) return ret;
 
		cost.AddCost(ret);
 

	
 
		/* false - end tile slope check */
 
		terraformcost = CheckBridgeSlopeSouth(direction, tileh_end);
 
		if (CmdFailed(terraformcost) || (terraformcost.GetCost() != 0 && !allow_on_slopes))
 
		if (CmdFailed(terraform_cost_south) || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes))
 
			return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
		cost.AddCost(terraformcost);
 
		cost.AddCost(terraform_cost_south);
 
	}
 

	
 
	if (!replace_bridge) {
 
		TileIndex Heads[] = {tile_start, tile_end};
 
		int i;
 

	
 
		for (i = 0; i < 2; i++) {
 
			if (MayHaveBridgeAbove(Heads[i])) {
 
				if (IsBridgeAbove(Heads[i])) {
 
					TileIndex north_head = GetNorthernBridgeEnd(Heads[i]);
 

	
 
					if (direction == GetBridgeAxis(Heads[i])) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
 
@@ -388,25 +383,24 @@ CommandCost CmdBuildBridge(TileIndex end
 
			case MP_TUNNELBRIDGE:
 
				if (IsTunnel(tile)) break;
 
				if (replace_bridge) break;
 
				if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below;
 
				if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
 
				break;
 

	
 
			case MP_UNMOVABLE:
 
				if (!IsOwnedLand(tile)) goto not_valid_below;
 
				break;
 

	
 
			case MP_CLEAR:
 
				if (!replace_bridge && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
 
				break;
 

	
 
			default:
 
not_valid_below:;
 
				/* try and clear the middle landscape */
 
				ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
				if (CmdFailed(ret)) return ret;
 
				cost.AddCost(ret);
 
				break;
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
@@ -746,31 +740,24 @@ static void DrawBridgePillars(const PalS
 
			if (cur_z >= front_height) {
 
				AddSortableSpriteToDraw(image, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - 5, cur_z, IsTransparencySet(TO_BRIDGES), 0, 0, -5);
 
			}
 

	
 
			/* Draw back facing pillar, but not the highest part directly under the bridge-floor */
 
			if (drawfarpillar && cur_z >= back_height && cur_z < z_bridge - TILE_HEIGHT) {
 
				AddSortableSpriteToDraw(image, psid->pal, x_back, y_back, w, h, BB_HEIGHT_UNDER_BRIDGE - 5, cur_z, IsTransparencySet(TO_BRIDGES), 0, 0, -5);
 
			}
 
		}
 
	}
 
}
 

	
 
Foundation GetBridgeFoundation(Slope tileh, Axis axis)
 
{
 
	if (HasBit(BRIDGE_NO_FOUNDATION, tileh)) return FOUNDATION_NONE;
 
	if (HasBit(BRIDGE_FULL_LEVELED_FOUNDATION, tileh)) return FlatteningFoundation(tileh);
 
	return InclinedFoundation(axis);
 
}
 

	
 
/**
 
 * Draws the trambits over an already drawn (lower end) of a bridge.
 
 * @param x       the x of the bridge
 
 * @param y       the y of the bridge
 
 * @param z       the z of the bridge
 
 * @param offset  number representing whether to level or sloped and the direction
 
 * @param overlay do we want to still see the road?
 
 */
 
static void DrawBridgeTramBits(int x, int y, byte z, int offset, bool overlay)
 
{
 
	static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } };
 
	static const SpriteID back_offsets[6]    =   {  95,  96,  99, 102, 100, 101 };
 
@@ -1088,24 +1075,25 @@ void DrawBridgeMiddle(const TileInfo* ti
 

	
 
			DrawGroundSpriteAt(image, pal, x, y, z);
 
		}
 
	} else if (_patches.bridge_pillars) {
 
		/* draw pillars below for high bridges */
 
		DrawBridgePillars(psid, ti, axis, type, x, y, z);
 
	}
 
}
 

	
 

	
 
static uint GetSlopeZ_TunnelBridge(TileIndex tile, uint x, uint y)
 
{
 
	static const uint32 BRIDGE_HORZ_RAMP = (1 << SLOPE_SW) | (1 << SLOPE_SE) | (1 << SLOPE_NW) | (1 << SLOPE_NE);
 
	uint z;
 
	Slope tileh = GetTileSlope(tile, &z);
 

	
 
	x &= 0xF;
 
	y &= 0xF;
 

	
 
	if (IsTunnel(tile)) {
 
		uint pos = (DiagDirToAxis(GetTunnelBridgeDirection(tile)) == AXIS_X ? y : x);
 

	
 
		/* In the tunnel entrance? */
 
		if (5 <= pos && pos <= 10) return z;
 
	} else {
 
@@ -1381,42 +1369,38 @@ static VehicleEnterTileStatus VehicleEnt
 
			return VETSB_CONTINUE;
 
		}
 
	}
 
	return VETSB_CONTINUE;
 
}
 

	
 
static CommandCost TerraformTile_TunnelBridge(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
 
{
 
	if (_patches.build_on_slopes && AutoslopeEnabled() && IsBridge(tile)) {
 
		DiagDirection direction = GetTunnelBridgeDirection(tile);
 
		Axis axis = DiagDirToAxis(direction);
 
		CommandCost res;
 
		uint z_old;
 
		Slope tileh_old = GetTileSlope(tile, &z_old);
 

	
 
		/* Check if new slope is valid for bridges in general (so we can savely call GetBridgeFoundation()) */
 
		if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
 
			res = CheckBridgeSlopeSouth(axis, tileh_new);
 
			CheckBridgeSlopeSouth(axis, &tileh_old, &z_old);
 
			res = CheckBridgeSlopeSouth(axis, &tileh_new, &z_new);
 
		} else {
 
			res = CheckBridgeSlopeNorth(axis, tileh_new);
 
			CheckBridgeSlopeNorth(axis, &tileh_old, &z_old);
 
			res = CheckBridgeSlopeNorth(axis, &tileh_new, &z_new);
 
		}
 

	
 
		if (!CmdFailed(res)) {
 
			uint z_old;
 
			Slope tileh_old = GetTileSlope(tile, &z_old);
 

	
 
			z_old += ApplyFoundationToSlope(GetBridgeFoundation(tileh_old, axis), &tileh_old);
 
			z_new += ApplyFoundationToSlope(GetBridgeFoundation(tileh_new, axis), &tileh_new);
 

	
 
			/* Surface slope remains unchanged? */
 
			if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
		}
 
		/* Surface slope is valid and remains unchanged? */
 
		if (!CmdFailed(res) && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
	}
 

	
 
	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
}
 

	
 
extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
 
	DrawTile_TunnelBridge,           /* draw_tile_proc */
 
	GetSlopeZ_TunnelBridge,          /* get_slope_z_proc */
 
	ClearTile_TunnelBridge,          /* clear_tile_proc */
 
	GetAcceptedCargo_TunnelBridge,   /* get_accepted_cargo_proc */
 
	GetTileDesc_TunnelBridge,        /* get_tile_desc_proc */
 
	GetTileTrackStatus_TunnelBridge, /* get_tile_track_status_proc */
0 comments (0 inline, 0 general)