(svn r11657) -Fix: show better error message when trying to convert rail
authorsmatz
Mon, 17 Dec 2007 22:29:27 +0000
changeset 8592 3b75a1a7ecd2
parent 8591 46eca2eb57ba
child 8593 ff04e6e4c7f3
(svn r11657) -Fix: show better error message when trying to convert rail
-Codechange: merge DoConvert functions into one, make test and exec runs the same for tunnels/bridges
src/command.cpp
src/rail_cmd.cpp
src/road_cmd.cpp
src/station_cmd.cpp
src/tunnelbridge_cmd.cpp
--- a/src/command.cpp	Mon Dec 17 22:04:07 2007 +0000
+++ b/src/command.cpp	Mon Dec 17 22:29:27 2007 +0000
@@ -549,7 +549,6 @@
 	 * estimate the cost of cloning a vehicle. */
 	notest =
 		(cmd & 0xFF) == CMD_CLEAR_AREA ||
-		(cmd & 0xFF) == CMD_CONVERT_RAIL ||
 		(cmd & 0xFF) == CMD_LEVEL_LAND ||
 		(cmd & 0xFF) == CMD_REMOVE_ROAD ||
 		(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD ||
--- a/src/rail_cmd.cpp	Mon Dec 17 22:04:07 2007 +0000
+++ b/src/rail_cmd.cpp	Mon Dec 17 22:29:27 2007 +0000
@@ -1143,8 +1143,7 @@
 	return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5)); // bit 5 is remove bit
 }
 
-typedef CommandCost DoConvertRailProc(TileIndex tile, RailType totype, bool exec);
-
+/** Update power of train under which is the railtype being converted */
 void *UpdateTrainPowerProc(Vehicle *v, void *data)
 {
 	/* Similiar checks as in TrainPowerChanged() */
@@ -1157,46 +1156,6 @@
 	return NULL;
 }
 
-/**
- * Switches the rail type.
- * Railtypes are stored on a per-tile basis, not on a per-track basis, so
- * all the tracks in the given tile will be converted.
- * @param tile        The tile on which the railtype is to be convert.
- * @param totype      The railtype we want to convert to
- * @param exec        Switches between test and execute mode
- * @return            The cost and state of the operation
- * @retval CMD_ERROR  An error occured during the operation.
- */
-static CommandCost DoConvertRail(TileIndex tile, RailType totype, bool exec)
-{
-	/* change type. */
-	if (exec) {
-		SetRailType(tile, totype);
-		MarkTileDirtyByTile(tile);
-
-		/* notify YAPF about the track layout change */
-		TrackBits tracks = GetTrackBits(tile);
-		while (tracks != TRACK_BIT_NONE) {
-			YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
-		}
-
-		if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
-			/* Update build vehicle window related to this depot */
-			InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
-			InvalidateWindowData(WC_BUILD_VEHICLE, tile);
-		}
-
-		/* update power of train engines on this tile */
-		VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
-	}
-
-	return CommandCost(RailConvertCost(GetRailType(tile), totype) * CountBits(GetTrackBits(tile)));
-}
-
-extern CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec);
-extern CommandCost DoConvertStreetRail(TileIndex tile, RailType totype, bool exec);
-extern CommandCost DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec);
-
 /** Convert one rail type to the other. You can convert normal rail to
  * monorail/maglev easily or vice-versa.
  * @param tile end tile of rail conversion drag
@@ -1206,72 +1165,137 @@
  */
 CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	CommandCost ret, cost;
-	Money money;
-	int ex;
-	int ey;
-	int sx, sy, x, y;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+	CommandCost cost;
 
 	if (!ValParamRailtype(p2)) return CMD_ERROR;
 	if (p1 >= MapSize()) return CMD_ERROR;
 
+	RailType totype = (RailType)p2;
+
+	uint ex = TileX(tile);
+	uint ey = TileY(tile);
+	uint sx = TileX(p1);
+	uint sy = TileY(p1);
+
 	/* make sure sx,sy are smaller than ex,ey */
-	ex = TileX(tile);
-	ey = TileY(tile);
-	sx = TileX(p1);
-	sy = TileY(p1);
 	if (ex < sx) Swap(ex, sx);
 	if (ey < sy) Swap(ey, sy);
 
-	money = GetAvailableMoneyForCommand();
-
-	for (x = sx; x <= ex; ++x) {
-		for (y = sy; y <= ey; ++y) {
+	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+
+	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK; // by default, there is no track to convert
+
+	for (uint x = sx; x <= ex; ++x) {
+		for (uint y = sy; y <= ey; ++y) {
 			TileIndex tile = TileXY(x, y);
-			DoConvertRailProc *proc;
-			RailType totype = (RailType)p2;
-
-			switch (GetTileType(tile)) {
-				case MP_RAILWAY:      proc = DoConvertRail;             break;
-				case MP_STATION:      proc = DoConvertStationRail;      break;
-				case MP_ROAD:         proc = DoConvertStreetRail;       break;
-				case MP_TUNNELBRIDGE: proc = DoConvertTunnelBridgeRail; break;
+			TileType tt = GetTileType(tile);
+
+			/* Check if there is any track on tile */
+			switch (tt) {
+				case MP_RAILWAY:
+					break;
+				case MP_STATION:
+					if (!IsRailwayStation(tile)) continue;
+					break;
+				case MP_ROAD:
+					if (!IsLevelCrossing(tile)) continue;
+					break;
+				case MP_TUNNELBRIDGE:
+					if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
+					break;
 				default: continue;
 			}
 
-			/* It is possible that 'type' is invalid when there is no rail on the tile,
-			 * but this situation will be detected in proc()
-			 */
+			/* Original railtype we are converting from */
 			RailType type = GetRailType(tile);
 
-			/* Not own tile or track is already converted */
-			if ((!CheckTileOwnership(tile) || type == totype) ||
-				/* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */
-				(_patches.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC) ||
-				/* Vehicle on a tile while not converting Rail <-> ElRail */
-				(!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile))) {
-					ret = CMD_ERROR;
-					continue;
+			/* Converting to the same type or converting 'hidden' elrail -> rail */
+			if (type == totype || (_patches.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
+
+			/* Trying to convert other's rail */
+			if (!CheckTileOwnership(tile)) continue;
+
+			/* Vehicle on the tile when not converting Rail <-> ElRail
+			 * Tunnels and bridges have special check later */
+			if (tt != MP_TUNNELBRIDGE) {
+				if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
+				if (flags & DC_EXEC) { // we can safely convert, too
+					SetRailType(tile, totype);
+					MarkTileDirtyByTile(tile);
+					/* update power of train engines on this tile */
+					VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
+				}
 			}
 
-			ret = proc(tile, totype, false);
-			if (CmdFailed(ret)) continue;
-
-			if (flags & DC_EXEC) {
-				money -= ret.GetCost();
-				if (money < 0) {
-					_additional_cash_required = ret.GetCost();
-					return cost;
-				}
-				proc(tile, totype, true);
+			switch (tt) {
+				case MP_RAILWAY:
+					if (flags & DC_EXEC) {
+						/* notify YAPF about the track layout change */
+						TrackBits tracks = GetTrackBits(tile);
+						while (tracks != TRACK_BIT_NONE) {
+							YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
+						}
+
+						if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
+							/* Update build vehicle window related to this depot */
+							InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
+							InvalidateWindowData(WC_BUILD_VEHICLE, tile);
+						}
+					}
+
+					cost.AddCost(CommandCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile))));
+					break;
+
+				case MP_TUNNELBRIDGE: {
+					TileIndex endtile = IsTunnel(tile) ? GetOtherTunnelEnd(tile) : GetOtherBridgeEnd(tile);
+
+					/* If both ends of tunnel/bridge are in the range, do not try to convert twice -
+					 * it would cause assert because of different test and exec runs */
+					if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
+							TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
+
+					/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
+					if (!IsCompatibleRail(GetRailType(tile), totype) &&
+							GetVehicleTunnelBridge(tile, endtile) != NULL) continue;
+
+					if (flags & DC_EXEC) {
+						SetRailType(tile, totype);
+						SetRailType(endtile, totype);
+
+						VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
+						VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
+
+						Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
+
+						YapfNotifyTrackLayoutChange(tile, track);
+						YapfNotifyTrackLayoutChange(endtile, track);
+
+						MarkTileDirtyByTile(tile);
+						MarkTileDirtyByTile(endtile);
+
+						if (IsBridge(tile)) {
+							TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
+							TileIndex t = tile + delta;
+							for (; t != endtile; t += delta) MarkTileDirtyByTile(t); // TODO encapsulate this into a function
+						}
+					}
+
+					cost.AddCost((DistanceManhattan(tile, endtile) + 1) * RailConvertCost(type, totype));
+				} break;
+
+				default: // MP_STATION, MP_ROAD
+					if (flags & DC_EXEC) {
+						Track track = (tt == MP_STATION) ? GetRailStationTrack(tile) : AxisToTrack(OtherAxis(GetCrossingRoadAxis(tile)));
+						YapfNotifyTrackLayoutChange(tile, track);
+					}
+
+					cost.AddCost(RailConvertCost(type, totype));
+					break;
 			}
-			cost.AddCost(ret);
 		}
 	}
 
-	return (cost.GetCost() == 0) ? ret : cost;
+	return (cost.GetCost() == 0) ? CMD_ERROR : cost;
 }
 
 static CommandCost RemoveTrainDepot(TileIndex tile, uint32 flags)
--- a/src/road_cmd.cpp	Mon Dec 17 22:04:07 2007 +0000
+++ b/src/road_cmd.cpp	Mon Dec 17 22:29:27 2007 +0000
@@ -593,30 +593,6 @@
 	return cost;
 }
 
-/**
- * Switches the rail type on a level crossing.
- * @param tile        The tile on which the railtype is to be convert.
- * @param totype      The railtype we want to convert to
- * @param exec        Switches between test and execute mode
- * @return            The cost and state of the operation
- * @retval CMD_ERROR  An error occured during the operation.
- */
-CommandCost DoConvertStreetRail(TileIndex tile, RailType totype, bool exec)
-{
-	/* not a railroad crossing? */
-	if (!IsLevelCrossing(tile)) return CMD_ERROR;
-
-	if (exec) {
-		SetRailType(tile, totype);
-		MarkTileDirtyByTile(tile);
-		YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetCrossingRailBits(tile)));
-		VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
-	}
-
-	return CommandCost(RailConvertCost(GetRailType(tile), totype));
-}
-
-
 /** Build a long piece of road.
  * @param end_tile end tile of drag
  * @param flags operation to perform
--- a/src/station_cmd.cpp	Mon Dec 17 22:04:07 2007 +0000
+++ b/src/station_cmd.cpp	Mon Dec 17 22:29:27 2007 +0000
@@ -1290,29 +1290,6 @@
 }
 
 /**
- * Switches the rail type at a railway station tile.
- * @param tile        The tile on which the railtype is to be convert.
- * @param totype      The railtype we want to convert to
- * @param exec        Switches between test and execute mode
- * @return            The cost and state of the operation
- * @retval CMD_ERROR  An error occured during the operation.
- */
-CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
-{
-	/* Tile is not a railroad station? */
-	if (!IsRailwayStation(tile)) return CMD_ERROR;
-
-	if (exec) {
-		SetRailType(tile, totype);
-		MarkTileDirtyByTile(tile);
-		YapfNotifyTrackLayoutChange(tile, GetRailStationTrack(tile));
-		VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
-	}
-
-	return CommandCost(RailConvertCost(GetRailType(tile), totype));
-}
-
-/**
  * @param truck_station Determines whether a stop is RoadStop::BUS or RoadStop::TRUCK
  * @param st The Station to do the whole procedure for
  * @return a pointer to where to link a new RoadStop*
--- a/src/tunnelbridge_cmd.cpp	Mon Dec 17 22:04:07 2007 +0000
+++ b/src/tunnelbridge_cmd.cpp	Mon Dec 17 22:29:27 2007 +0000
@@ -691,54 +691,6 @@
 }
 
 /**
- * Switches the rail type for a tunnel or a bridgehead. As the railtype
- * on the bridge are determined by the one of the bridgehead, this
- * functions converts the railtype on the entire bridge.
- * @param tile        The tile on which the railtype is to be convert.
- * @param totype      The railtype we want to convert to
- * @param exec        Switches between test and execute mode
- * @return            The cost and state of the operation
- * @retval CMD_ERROR  An error occured during the operation.
- */
-CommandCost DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
-{
-	if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return CMD_ERROR;
-
-	TileIndex endtile = IsTunnel(tile) ? GetOtherTunnelEnd(tile) : GetOtherBridgeEnd(tile);
-
-	/* If not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
-	if (!IsCompatibleRail(GetRailType(tile), totype) &&
-			GetVehicleTunnelBridge(tile, endtile) != NULL) {
-		return CMD_ERROR;
-	}
-
-	if (exec) {
-		SetRailType(tile, totype);
-		SetRailType(endtile, totype);
-
-		Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
-
-		YapfNotifyTrackLayoutChange(tile, track);
-		YapfNotifyTrackLayoutChange(endtile, track);
-
-		VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
-		VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
-
-		MarkTileDirtyByTile(tile);
-		MarkTileDirtyByTile(endtile);
-
-		if (IsBridge(tile)) {
-			TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
-			TileIndex t = tile + delta;
-			for (; t != endtile; t += delta) MarkTileDirtyByTile(t); // TODO encapsulate this into a function
-		}
-	}
-
-	return CommandCost((DistanceManhattan(tile, endtile) + 1) * RailConvertCost(GetRailType(tile), totype));
-}
-
-
-/**
  * Draws the pillars under high bridges.
  *
  * @param psid Image and palette of a bridge pillar.