(svn r11059) -Fix [FS#1182]: inconsistency between Rail<->ElRail conversions of different kinds of rail containing tiles (normal rail, stations, depots, etc). Patch by SmatZ.
authorrubidium
Sat, 08 Sep 2007 09:52:02 +0000
changeset 8035 a0200ced6d9f
parent 8034 0f6a176ce1e9
child 8036 6f35eaf30c16
(svn r11059) -Fix [FS#1182]: inconsistency between Rail<->ElRail conversions of different kinds of rail containing tiles (normal rail, stations, depots, etc). Patch by SmatZ.
src/rail.h
src/rail_cmd.cpp
src/road_cmd.cpp
src/station_cmd.cpp
src/train_cmd.cpp
src/tunnelbridge_cmd.cpp
--- a/src/rail.h	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/rail.h	Sat Sep 08 09:52:02 2007 +0000
@@ -778,6 +778,7 @@
 	return bits != TRACK_BIT_HORZ && bits != TRACK_BIT_VERT;
 }
 
+void *UpdateTrainPowerProc(Vehicle *v, void *data);
 void DrawTrainDepotSprite(int x, int y, int image, RailType railtype);
 void DrawDefaultWaypointSprite(int x, int y, RailType railtype);
 
--- a/src/rail_cmd.cpp	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/rail_cmd.cpp	Sat Sep 08 09:52:02 2007 +0000
@@ -34,6 +34,7 @@
 #include "railtypes.h" // include table for railtypes
 #include "newgrf.h"
 #include "yapf/yapf.h"
+#include "newgrf_engine.h"
 #include "newgrf_callbacks.h"
 #include "newgrf_station.h"
 #include "train.h"
@@ -1024,6 +1025,18 @@
 
 typedef CommandCost DoConvertRailProc(TileIndex tile, RailType totype, bool exec);
 
+void *UpdateTrainPowerProc(Vehicle *v, void *data)
+{
+	/* Similiar checks as in TrainPowerChanged() */
+
+	if (v->type == VEH_TRAIN && v->tile == *(TileIndex*)data && !IsArticulatedPart(v)) {
+		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
+		if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First());
+	}
+
+	return NULL;
+}
+
 /**
  * Switches the rail type.
  * Railtypes are stored on a per-tile basis, not on a per-track basis, so
@@ -1036,15 +1049,6 @@
  */
 static CommandCost DoConvertRail(TileIndex tile, RailType totype, bool exec)
 {
-	if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-	if (GetRailType(tile) == totype) return CMD_ERROR;
-
-	if (!EnsureNoVehicleOnGround(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) 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;
-
 	/* change type. */
 	if (exec) {
 		SetRailType(tile, totype);
@@ -1057,18 +1061,12 @@
 		}
 
 		if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
-			Vehicle *v;
-
 			/* Update build vehicle window related to this depot */
 			InvalidateWindowData(WC_BUILD_VEHICLE, tile);
+		}
 
-			/* update power of trains in this depot */
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_TRAIN && IsFrontEngine(v) && v->tile == tile && v->u.rail.track == 0x80) {
-					TrainPowerChanged(v);
-				}
-			}
-		}
+		/* update power of train engines on this tile */
+		VehicleFromPos(tile, &tile, UpdateTrainPowerProc);
 	}
 
 	return CommandCost(_price.build_rail / 2);
@@ -1111,7 +1109,8 @@
 	for (x = sx; x <= ex; ++x) {
 		for (y = sy; y <= ey; ++y) {
 			TileIndex tile = TileXY(x, y);
-			DoConvertRailProc* proc;
+			DoConvertRailProc *proc;
+			RailType totype = (RailType)p2;
 
 			switch (GetTileType(tile)) {
 				case MP_RAILWAY:      proc = DoConvertRail;             break;
@@ -1121,7 +1120,22 @@
 				default: continue;
 			}
 
-			ret = proc(tile, (RailType)p2, false);
+			/* It is possible that 'type' is invalid when there is no rail on the tile,
+			 * but this situation will be detected in proc()
+			 */
+			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;
+			}
+
+			ret = proc(tile, totype, false);
 			if (CmdFailed(ret)) continue;
 
 			if (flags & DC_EXEC) {
@@ -1130,7 +1144,7 @@
 					_additional_cash_required = ret.GetCost();
 					return cost;
 				}
-				proc(tile, (RailType)p2, true);
+				proc(tile, totype, true);
 			}
 			cost.AddCost(ret);
 		}
--- a/src/road_cmd.cpp	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/road_cmd.cpp	Sat Sep 08 09:52:02 2007 +0000
@@ -543,18 +543,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);
--- a/src/station_cmd.cpp	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/station_cmd.cpp	Sat Sep 08 09:52:02 2007 +0000
@@ -1227,22 +1227,14 @@
  */
 CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec)
 {
-	const Station* st = GetStationByTile(tile);
-
-	if (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile)) return CMD_ERROR;
-
-	// tile is not a railroad station?
+	/* Tile is not a railroad station? */
 	if (!IsRailwayStation(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, GetRailStationTrack(tile));
+		VehicleFromPos(tile, &tile, UpdateTrainPowerProc);
 	}
 
 	return CommandCost(_price.build_rail / 2);
--- a/src/train_cmd.cpp	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/train_cmd.cpp	Sat Sep 08 09:52:02 2007 +0000
@@ -95,6 +95,9 @@
 	}
 
 	if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
+		/* If it has no power (no catenary), stop the train */
+		if (total_power == 0) v->vehstatus |= VS_STOPPED;
+
 		v->u.rail.cached_power = total_power;
 		v->u.rail.cached_max_te = max_te;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
--- a/src/tunnelbridge_cmd.cpp	Sat Sep 08 00:37:37 2007 +0000
+++ b/src/tunnelbridge_cmd.cpp	Sat Sep 08 09:52:02 2007 +0000
@@ -749,68 +749,67 @@
  */
 CommandCost DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec)
 {
-	TileIndex endtile;
-
 	if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) {
 		uint length;
-
-		if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-		if (GetRailType(tile) == totype) return CMD_ERROR;
+		TileIndex endtile;
 
-		/* '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;
-
-		endtile = CheckTunnelBusy(tile, &length);
-		if (endtile == INVALID_TILE) return CMD_ERROR;
+		/* If not coverting rail <-> el. rail, any vehicle cannot be in tunnel */
+		if (!IsCompatibleRail(GetRailType(tile), totype)) {
+			endtile = CheckTunnelBusy(tile, &length);
+			if (endtile == INVALID_TILE) return CMD_ERROR;
+		} else {
+			endtile = GetOtherTunnelEnd(tile);
+			length = DistanceManhattan(tile, endtile);
+		}
 
 		if (exec) {
-			Track track;
 			SetRailType(tile, totype);
 			SetRailType(endtile, totype);
 			MarkTileDirtyByTile(tile);
 			MarkTileDirtyByTile(endtile);
 
-			track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile)));
+			Track track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile)));
+
 			YapfNotifyTrackLayoutChange(tile, track);
 			YapfNotifyTrackLayoutChange(endtile, track);
+
+			VehicleFromPos(tile, &tile, UpdateTrainPowerProc);
+			VehicleFromPos(endtile, &endtile, UpdateTrainPowerProc);
 		}
-		return CommandCost((length + 1) * (_price.build_rail / 2));
+
+		return CommandCost((length + 1) * (_price.build_rail >> 1));
 	} else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) {
-
-		if (!CheckTileOwnership(tile)) return CMD_ERROR;
-
-		endtile = GetOtherBridgeEnd(tile);
+		TileIndex endtile = GetOtherBridgeEnd(tile);
 		byte bridge_height = GetBridgeHeight(tile);
 
-		if (FindVehicleOnTileZ(tile, bridge_height) != NULL ||
+		if (!IsCompatibleRail(GetRailType(tile), totype) &&
+				(FindVehicleOnTileZ(tile, bridge_height) != NULL ||
 				FindVehicleOnTileZ(endtile, bridge_height) != NULL ||
-				IsVehicleOnBridge(tile, endtile, bridge_height)) {
+				IsVehicleOnBridge(tile, endtile, bridge_height))) {
 			return CMD_ERROR;
 		}
 
-		if (GetRailType(tile) == totype) return CMD_ERROR;
-
 		if (exec) {
-			TileIndexDiff delta;
-			Track track;
-
 			SetRailType(tile, totype);
 			SetRailType(endtile, totype);
 			MarkTileDirtyByTile(tile);
 			MarkTileDirtyByTile(endtile);
 
-			track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile)));
+			Track track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile)));
+			TileIndexDiff delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
+
 			YapfNotifyTrackLayoutChange(tile, track);
 			YapfNotifyTrackLayoutChange(endtile, track);
 
-			delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
+			VehicleFromPos(tile, &tile, UpdateTrainPowerProc);
+			VehicleFromPos(endtile, &endtile, UpdateTrainPowerProc);
+
 			for (tile += delta; tile != endtile; tile += delta) {
 				MarkTileDirtyByTile(tile); // TODO encapsulate this into a function
 			}
 		}
 
-		return CommandCost((DistanceManhattan(tile, endtile) + 1) * (_price.build_rail / 2));
+		return CommandCost((DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1));
 	} else {
 		return CMD_ERROR;
 	}