src/road_cmd.cpp
branchNewGRF_ports
changeset 6870 ca3fd1fbe311
parent 6868 7eb395287b3d
child 6871 5a9dc001e1ad
--- a/src/road_cmd.cpp	Thu Sep 06 19:42:48 2007 +0000
+++ b/src/road_cmd.cpp	Sat Oct 06 21:16:00 2007 +0000
@@ -32,6 +32,12 @@
 #include "station_map.h"
 #include "tunnel_map.h"
 #include "misc/autoptr.hpp"
+#include "autoslope.h"
+
+#define M(x) (1 << (x))
+/* Level crossings may only be built on these slopes */
+static const uint32 VALID_LEVEL_CROSSING_SLOPES = (M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT));
+#undef M
 
 bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
 {
@@ -198,10 +204,12 @@
 				if (present == ROAD_NONE) {
 					RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
 					if (rts == ROADTYPES_NONE) {
+						/* Includes MarkTileDirtyByTile() */
 						DoClearSquare(tile);
 					} else {
 						SetRoadBits(tile, ROAD_NONE, rt);
 						SetRoadTypes(tile, rts);
+						MarkTileDirtyByTile(tile);
 					}
 				} else {
 					/* When bits are removed, you *always* end up with something that
@@ -251,70 +259,121 @@
 static const RoadBits _valid_tileh_slopes_road[][15] = {
 	/* set of normal ones */
 	{
-		ROAD_ALL, ROAD_NONE, ROAD_NONE,
-		ROAD_X,   ROAD_NONE, ROAD_NONE,  // 3, 4, 5
-		ROAD_Y,   ROAD_NONE, ROAD_NONE,
-		ROAD_Y,   ROAD_NONE, ROAD_NONE,  // 9, 10, 11
-		ROAD_X,   ROAD_NONE, ROAD_NONE
+		ROAD_ALL,  // SLOPE_FLAT
+		ROAD_NONE, // SLOPE_W
+		ROAD_NONE, // SLOPE_S
+
+		ROAD_X,    // SLOPE_SW
+		ROAD_NONE, // SLOPE_E
+		ROAD_NONE, // SLOPE_EW
+
+		ROAD_Y,    // SLOPE_SE
+		ROAD_NONE, // SLOPE_WSE
+		ROAD_NONE, // SLOPE_N
+
+		ROAD_Y,    // SLOPE_NW
+		ROAD_NONE, // SLOPE_NS
+		ROAD_NONE, // SLOPE_NE
+
+		ROAD_X,    // SLOPE_ENW
+		ROAD_NONE, // SLOPE_SEN
+		ROAD_NONE  // SLOPE_ELEVATED
 	},
 	/* allowed road for an evenly raised platform */
 	{
-		ROAD_NONE,
-		ROAD_SW | ROAD_NW,
-		ROAD_SW | ROAD_SE,
-		ROAD_Y  | ROAD_SW,
+		ROAD_NONE,         // SLOPE_FLAT
+		ROAD_SW | ROAD_NW, // SLOPE_W
+		ROAD_SW | ROAD_SE, // SLOPE_S
 
-		ROAD_SE | ROAD_NE, // 4
-		ROAD_ALL,
-		ROAD_X  | ROAD_SE,
-		ROAD_ALL,
+		ROAD_Y  | ROAD_SW, // SLOPE_SW
+		ROAD_SE | ROAD_NE, // SLOPE_E
+		ROAD_ALL,          // SLOPE_EW
 
-		ROAD_NW | ROAD_NE, // 8
-		ROAD_X  | ROAD_NW,
-		ROAD_ALL,
-		ROAD_ALL,
+		ROAD_X  | ROAD_SE, // SLOPE_SE
+		ROAD_ALL,          // SLOPE_WSE
+		ROAD_NW | ROAD_NE, // SLOPE_N
 
-		ROAD_Y  | ROAD_NE, // 12
-		ROAD_ALL,
-		ROAD_ALL
+		ROAD_X  | ROAD_NW, // SLOPE_NW
+		ROAD_ALL,          // SLOPE_NS
+		ROAD_ALL,          // SLOPE_NE
+
+		ROAD_Y  | ROAD_NE, // SLOPE_ENW
+		ROAD_ALL,          // SLOPE_SEN
+		ROAD_ALL           // SLOPE_ELEVATED
+	},
+	/* Singe bits on slopes */
+	{
+		ROAD_ALL,          // SLOPE_FLAT
+		ROAD_NE | ROAD_SE, // SLOPE_W
+		ROAD_NE | ROAD_NW, // SLOPE_S
+
+		ROAD_NE,           // SLOPE_SW
+		ROAD_NW | ROAD_SW, // SLOPE_E
+		ROAD_ALL,          // SLOPE_EW
+
+		ROAD_NW,           // SLOPE_SE
+		ROAD_ALL,          // SLOPE_WSE
+		ROAD_SE | ROAD_SW, // SLOPE_N
+
+		ROAD_SE,           // SLOPE_NW
+		ROAD_ALL,          // SLOPE_NS
+		ROAD_ALL,          // SLOPE_NE
+
+		ROAD_SW,           // SLOPE_ENW
+		ROAD_ALL,          // SLOPE_SEN
+		ROAD_ALL,          // SLOPE_ELEVATED
 	},
 };
 
-
+/**
+ * Calculate the costs for roads on slopes
+ *  Aside modify the RoadBits to fit on the slopes
+ *
+ * @note The RoadBits are modified too!
+ * @param tileh The current slope
+ * @param pieces The RoadBits we want to add
+ * @param existing The existent RoadBits
+ * @return The costs for these RoadBits on this slope
+ */
 static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existing)
 {
-	RoadBits road_bits;
-
 	if (IsSteepSlope(tileh)) {
-		/* force full pieces. */
-		*pieces |= (RoadBits)((*pieces & 0xC) >> 2);
-		*pieces |= (RoadBits)((*pieces & 0x3) << 2);
+		/* Force straight roads. */
+		*pieces |= MirrorRoadBits(*pieces);
 
-		if (existing == 0 || existing == *pieces) {
+		if (existing == ROAD_NONE || existing == *pieces) {
 			if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
 		}
 		return CMD_ERROR;
 	}
-	road_bits = *pieces | existing;
+
+	RoadBits road_bits = *pieces | existing;
+
+	/* Single bits on slopes.
+	 * We check for the roads that need at least 2 bits */
+	if (_patches.build_on_slopes && !_is_old_ai_player &&
+			existing == ROAD_NONE && COUNTBITS(*pieces) == 1 &&
+			(_valid_tileh_slopes_road[2][tileh] & *pieces) == ROAD_NONE) {
+		return CommandCost(_price.terraform);
+	}
 
 	/* no special foundation */
-	if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == 0) {
+	if ((~_valid_tileh_slopes_road[0][tileh] & road_bits) == ROAD_NONE) {
 		/* force that all bits are set when we have slopes */
 		if (tileh != SLOPE_FLAT) *pieces |= _valid_tileh_slopes_road[0][tileh];
 		return CommandCost(); // no extra cost
 	}
 
 	/* foundation is used. Whole tile is leveled up */
-	if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == 0) {
-		return CommandCost(existing != 0 ? 0 : _price.terraform);
+	if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == ROAD_NONE) {
+		return CommandCost(existing != ROAD_NONE ? 0 : _price.terraform);
 	}
 
-	*pieces |= (RoadBits)((*pieces & 0xC) >> 2);
-	*pieces |= (RoadBits)((*pieces & 0x3) << 2);
+	/* Force straight roads. */
+	*pieces |= MirrorRoadBits(*pieces);
 
 	/* partly leveled up tile, only if there's no road on that tile */
-	if ((existing == 0 || existing == *pieces) && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
-		/* force full pieces. */
+	if ((existing == ROAD_NONE || existing == *pieces) && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
 		if (*pieces == ROAD_X || *pieces == ROAD_Y) return _price.terraform;
 	}
 	return CMD_ERROR;
@@ -403,12 +462,10 @@
 				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 			}
 
-#define M(x) (1 << (x))
 			/* Level crossings may only be built on these slopes */
-			if (!HASBIT(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
+			if (!HASBIT(VALID_LEVEL_CROSSING_SLOPES, tileh)) {
 				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 			}
-#undef M
 
 			if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
 			switch (GetTrackBits(tile)) {
@@ -541,18 +598,11 @@
 	/* not a railroad crossing? */
 	if (!IsLevelCrossing(tile)) return CMD_ERROR;
 
-	/* not owned by me? */
-	if (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
-
-	if (GetRailType(tile) == totype) return CMD_ERROR;
-
-	/* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */
-	if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR;
-
 	if (exec) {
 		SetRailType(tile, totype);
 		MarkTileDirtyByTile(tile);
 		YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetCrossingRailBits(tile)));
+		VehicleFromPos(tile, &tile, UpdateTrainPowerProc);
 	}
 
 	return CommandCost(_price.build_rail / 2);
@@ -603,7 +653,7 @@
 	/* On the X-axis, we have to swap the initial bits, so they
 	 * will be interpreted correctly in the GTTS. Futhermore
 	 * when you just 'click' on one tile to build them. */
-	if (HASBIT(p2, 2) == (start_tile == end_tile)) drd ^= DRD_BOTH;
+	if (HASBIT(p2, 2) == (start_tile == end_tile && HASBIT(p2, 0) == HASBIT(p2, 1))) drd ^= DRD_BOTH;
 	/* No disallowed direction bits have to be toggled */
 	if (!HASBIT(p2, 5)) drd = DRD_NONE;
 
@@ -786,10 +836,9 @@
 		case ROAD_TILE_NORMAL: {
 			RoadBits b = GetAllRoadBits(tile);
 
-#define M(x) (1 << (x))
 			/* Clear the road if only one piece is on the tile OR the AI tries
 			 * to clear town road OR we are not using the DC_AUTO flag */
-			if ((M(b) & (M(ROAD_NW) | M(ROAD_SW) | M(ROAD_SE) | M(ROAD_NE))) ||
+			if ((COUNTBITS(b) == 1 && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) ||
 			    ((flags & DC_AI_BUILDING) && IsTileOwner(tile, OWNER_TOWN)) ||
 			    !(flags & DC_AUTO)
 				) {
@@ -806,7 +855,6 @@
 			}
 			return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
 		}
-#undef M
 
 		case ROAD_TILE_CROSSING: {
 			RoadTypes rts = GetRoadTypes(tile);
@@ -915,8 +963,8 @@
 		front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[tram];
 	}
 
-	AddSortableSpriteToDraw(back,  PAL_NONE, ti->x, ti->y, 16, 16, 0x1F, ti->z, HASBIT(_transparent_opt, TO_BUILDINGS));
-	AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, 0x1F, ti->z, HASBIT(_transparent_opt, TO_BUILDINGS));
+	AddSortableSpriteToDraw(back,  PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, HASBIT(_transparent_opt, TO_BUILDINGS));
+	AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, HASBIT(_transparent_opt, TO_BUILDINGS));
 }
 
 /**
@@ -1183,8 +1231,8 @@
 
 	if (GetRoadTileType(tile) == ROAD_TILE_DEPOT) return;
 
+	const Town* t = ClosestTownFromTile(tile, (uint)-1);
 	if (!HasRoadWorks(tile)) {
-		const Town* t = ClosestTownFromTile(tile, (uint)-1);
 		int grp = 0;
 
 		if (t != NULL) {
@@ -1193,8 +1241,8 @@
 			/* Show an animation to indicate road work */
 			if (t->road_build_months != 0 &&
 					(DistanceManhattan(t->xy, tile) < 8 || grp != 0) &&
-					GetRoadTileType(tile) == ROAD_TILE_NORMAL && (GetAllRoadBits(tile) == ROAD_X || GetAllRoadBits(tile) == ROAD_Y)) {
-				if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile) && CHANCE16(1, 20)) {
+					GetRoadTileType(tile) == ROAD_TILE_NORMAL && COUNTBITS(GetAllRoadBits(tile)) > 1 ) {
+				if (GetTileSlope(tile, NULL) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile) && CHANCE16(1, 40)) {
 					StartRoadWorks(tile);
 
 					SndPlayTileFx(SND_21_JACKHAMMER, tile);
@@ -1232,6 +1280,17 @@
 		}
 	} else if (IncreaseRoadWorksCounter(tile)) {
 		TerminateRoadWorks(tile);
+
+		if (_patches.mod_road_rebuild) {
+			/* Generate a nicer town surface */
+			const RoadBits old_rb = GetAnyRoadBits(tile, ROADTYPE_ROAD);
+			const RoadBits new_rb = CleanUpRoadBits(tile, old_rb);
+
+			if (old_rb != new_rb) {
+				DoCommand(tile, (old_rb ^ new_rb), t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_REMOVE_ROAD);
+			}
+		}
+
 		MarkTileDirtyByTile(tile);
 	}
 }
@@ -1377,6 +1436,41 @@
 
 static CommandCost TerraformTile_Road(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
 {
+	if (_patches.build_on_slopes && AutoslopeEnabled()) {
+		switch (GetRoadTileType(tile)) {
+			case ROAD_TILE_CROSSING:
+				if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HASBIT(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return _price.terraform;
+				break;
+
+			case ROAD_TILE_DEPOT:
+				if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return _price.terraform;
+				break;
+
+			case ROAD_TILE_NORMAL: {
+				RoadBits bits = GetAllRoadBits(tile);
+				RoadBits bits_copy = bits;
+				/* Check if the slope-road_bits combination is valid at all, i.e. it is save to call GetRoadFoundation(). */
+				if (!CmdFailed(CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE))) {
+					/* CheckRoadSlope() sometimes changes the road_bits, if it does not agree with them. */
+					if (bits == bits_copy) {
+						uint z_old;
+						Slope tileh_old = GetTileSlope(tile, &z_old);
+
+						/* Get the slope on top of the foundation */
+						z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old);
+						z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new);
+
+						/* The surface slope must not be changed */
+						if ((z_old == z_new) && (tileh_old == tileh_new)) return _price.terraform;
+					}
+				}
+				break;
+			}
+
+			default: NOT_REACHED();
+		}
+	}
+
 	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 }