src/road_cmd.cpp
branchNewGRF_ports
changeset 6877 889301acc299
parent 6872 1c4a4a609f85
child 6878 7d1ff2f621c7
--- a/src/road_cmd.cpp	Sun Feb 03 01:34:21 2008 +0000
+++ b/src/road_cmd.cpp	Sun Feb 03 20:34:26 2008 +0000
@@ -33,6 +33,7 @@
 #include "vehicle_base.h"
 #include "sound_func.h"
 #include "road_func.h"
+#include "tunnelbridge.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -42,6 +43,8 @@
 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
 
+Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
+
 bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
 {
 	RoadBits present;
@@ -93,19 +96,15 @@
 	return CheckAllowRemoveRoad(tile, remove, GetRoadOwner(tile, rt), edge_road, rt);
 }
 
+
 /** Delete a piece of road.
  * @param tile tile where to remove road from
  * @param flags operation to perform
- * @param p1 bit 0..3 road pieces to remove (RoadBits)
- *           bit 4..5 road type
- *           bit    6 ignore the fact that the tram track has not been removed
- *                    yet when removing the road bits when not actually doing
- *                    it. Makes it possible to test whether the road bits can
- *                    be removed from a level crossing without physically
- *                    removing the tram bits before the test.
- * @param p2 unused
+ * @param pieces roadbits to remove
+ * @param rt roadtype to remove
+ * @param crossing_check should we check if there is a tram track when we are removing road from crossing?
  */
-CommandCost CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, RoadType rt, bool crossing_check)
 {
 	/* cost for removing inner/edge -roads */
 	static const uint16 road_remove_cost[2] = {50, 18};
@@ -114,9 +113,6 @@
 	 * false if it was a center piece. Affects town ratings drop */
 	bool edge_road;
 
-	RoadType rt = (RoadType)GB(p1, 4, 2);
-	if (!IsValidRoadType(rt)) return CMD_ERROR;
-
 	Town *t = NULL;
 	switch (GetTileType(tile)) {
 		case MP_ROAD:
@@ -130,16 +126,14 @@
 			break;
 
 		case MP_TUNNELBRIDGE:
-			{
-				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
-				if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
-			} break;
+			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
+			if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
+			break;
 
 		default:
 			return CMD_ERROR;
 	}
 
-	RoadBits pieces = Extract<RoadBits, 0>(p1);
 	RoadTypes rts = GetRoadTypes(tile);
 	/* The tile doesn't have the given road type */
 	if (!HasBit(rts, rt)) return CMD_ERROR;
@@ -158,7 +152,7 @@
 		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 			TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
 			/* Pay for *every* tile of the bridge or tunnel */
-			cost.AddCost((DistanceManhattan(other_end, tile) + 1) * _price.remove_road);
+			cost.AddCost((GetTunnelBridgeLength(other_end, tile) + 2) * _price.remove_road);
 			if (flags & DC_EXEC) {
 				SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt));
 				SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
@@ -231,7 +225,7 @@
 
 			/* Don't allow road to be removed from the crossing when there is tram;
 			 * we can't draw the crossing without trambits ;) */
-			if (rt == ROADTYPE_ROAD && HasBit(GetRoadTypes(tile), ROADTYPE_TRAM) && ((flags & DC_EXEC) || !HasBit(p1, 6))) return CMD_ERROR;
+			if (rt == ROADTYPE_ROAD && HasBit(GetRoadTypes(tile), ROADTYPE_TRAM) && (flags & DC_EXEC || crossing_check)) return CMD_ERROR;
 
 			if (rt == ROADTYPE_ROAD) {
 				ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
@@ -257,6 +251,24 @@
 }
 
 
+/** Delete a piece of road.
+ * @param tile tile where to remove road from
+ * @param flags operation to perform
+ * @param p1 bit 0..3 road pieces to remove (RoadBits)
+ *           bit 4..5 road type
+ * @param p2 unused
+ */
+CommandCost CmdRemoveRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	RoadType rt = (RoadType)GB(p1, 4, 2);
+	if (!IsValidRoadType(rt)) return CMD_ERROR;
+
+	RoadBits pieces = Extract<RoadBits, 0>(p1);
+
+	return RemoveRoad(tile, flags, pieces, rt, true);
+}
+
+
 static const RoadBits _valid_tileh_slopes_road[][15] = {
 	/* set of normal ones */
 	{
@@ -374,7 +386,7 @@
 	*pieces |= MirrorRoadBits(*pieces);
 
 	/* partly leveled up tile, only if there's no road on that tile */
-	if ((existing == ROAD_NONE || existing == *pieces) && (tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)) {
+	if ((existing == ROAD_NONE || existing == *pieces) && IsSlopeWithOneCornerRaised(tileh)) {
 		if (*pieces == ROAD_X || *pieces == ROAD_Y) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 	}
 	return CMD_ERROR;
@@ -496,18 +508,16 @@
 		case MP_STATION:
 			if (!IsDriveThroughStopTile(tile)) return CMD_ERROR;
 			if (HasBit(GetRoadTypes(tile), rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
-			/* Don't allow "upgrading" the roadstop when vehicles are already driving on it */
+			/* Don't allow adding roadtype to the roadstop when vehicles are already driving on it */
 			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 			break;
 
 		case MP_TUNNELBRIDGE:
-			{
-				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
-				if (HasBit(GetRoadTypes(tile), rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
-
-				/* Don't allow "upgrading" the bridge/tunnel when vehicles are already driving on it */
-				if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
-			} break;
+			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
+			if (HasBit(GetRoadTypes(tile), rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
+			/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
+			if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
+			break;
 
 		default:
 do_clear:;
@@ -530,12 +540,29 @@
 	if (IsTileType(tile, MP_ROAD)) {
 		/* Don't put the pieces that already exist */
 		pieces &= ComplementRoadBits(existing);
+
+		/* Check if new road bits will have the same foundation as other existing road types */
+		if (GetRoadTileType(tile) == ROAD_TILE_NORMAL) {
+			Slope slope = GetTileSlope(tile, NULL);
+			Foundation found_new = GetRoadFoundation(slope, pieces | existing);
+
+			/* Test if all other roadtypes can be built at that foundation */
+			for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) {
+				if (rtest != rt) { // check only other road types
+					RoadBits bits = GetRoadBits(tile, rtest);
+					/* do not check if there are not road bits of given type */
+					if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) {
+						return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+					}
+				}
+			}
+		}
 	}
 
 	cost.AddCost(CountBits(pieces) * _price.build_road);
 	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 		/* Pay for *every* tile of the bridge or tunnel */
-		cost.MultiplyCost(DistanceManhattan(GetOtherTunnelBridgeEnd(tile), tile) + 1);
+		cost.MultiplyCost(GetTunnelBridgeLength(GetOtherTunnelBridgeEnd(tile), tile) + 2);
 	}
 
 	if (flags & DC_EXEC) {
@@ -653,7 +680,7 @@
 						cost.AddCost(ret);
 					}
 					had_bridge = true;
-				} else {
+				} else { // IsTunnel(tile)
 					if ((!had_tunnel || GetTunnelBridgeDirection(tile) == DIAGDIR_SE || GetTunnelBridgeDirection(tile) == DIAGDIR_SW)) {
 						cost.AddCost(ret);
 					}
@@ -717,7 +744,7 @@
 
 		/* try to remove the halves. */
 		if (bits != 0) {
-			ret = DoCommand(tile, rt << 4 | bits, 0, flags & ~DC_EXEC, CMD_REMOVE_ROAD);
+			ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true);
 			if (CmdSucceeded(ret)) {
 				if (flags & DC_EXEC) {
 					money -= ret.GetCost();
@@ -725,7 +752,7 @@
 						_additional_cash_required = DoCommand(end_tile, start_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost();
 						return cost;
 					}
-					DoCommand(tile, rt << 4 | bits, 0, flags, CMD_REMOVE_ROAD);
+					RemoveRoad(tile, flags, bits, rt, true);
 				}
 				cost.AddCost(ret);
 			}
@@ -818,7 +845,7 @@
 				CommandCost ret(EXPENSES_CONSTRUCTION);
 				for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 					if (HasBit(rts, rt)) {
-						CommandCost tmp_ret = DoCommand(tile, rt << 4 | GetRoadBits(tile, rt), 0, flags, CMD_REMOVE_ROAD);
+						CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true);
 						if (CmdFailed(tmp_ret)) return tmp_ret;
 						ret.AddCost(tmp_ret);
 					}
@@ -838,7 +865,7 @@
 			 * tram tracks must be removed before the road bits. */
 			for (RoadType rt = ROADTYPE_HWAY; rt >= ROADTYPE_ROAD; rt--) {
 				if (HasBit(rts, rt)) {
-					CommandCost tmp_ret = DoCommand(tile, 1 << 6 | rt << 4 | GetCrossingRoadBits(tile), 0, flags, CMD_REMOVE_ROAD);
+					CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false);
 					if (CmdFailed(tmp_ret)) return tmp_ret;
 					ret.AddCost(tmp_ret);
 				}
@@ -1259,7 +1286,7 @@
 			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);
+				RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), ROADTYPE_ROAD, true);
 			}
 		}