src/rail_cmd.cpp
branchnoai
changeset 9723 eee46cb39750
parent 9722 ebf0ece7d8f6
child 9724 b39bc69bb2f2
--- a/src/rail_cmd.cpp	Fri Nov 23 16:59:30 2007 +0000
+++ b/src/rail_cmd.cpp	Wed Jan 09 18:11:12 2008 +0000
@@ -8,30 +8,25 @@
 #include "bridge.h"
 #include "cmd_helper.h"
 #include "debug.h"
-#include "functions.h"
+#include "tile_cmd.h"
 #include "rail_map.h"
 #include "road_map.h"
 #include "table/sprites.h"
 #include "table/strings.h"
-#include "map.h"
 #include "landscape.h"
-#include "tile.h"
 #include "town_map.h"
 #include "tunnel_map.h"
-#include "vehicle.h"
-#include "viewport.h"
-#include "command.h"
+#include "viewport_func.h"
+#include "command_func.h"
 #include "pathfind.h"
 #include "engine.h"
 #include "town.h"
-#include "sound.h"
 #include "station.h"
 #include "sprite.h"
 #include "depot.h"
 #include "waypoint.h"
-#include "window.h"
 #include "rail.h"
-#include "railtypes.h" // include table for railtypes
+#include "table/railtypes.h" // include table for railtypes
 #include "newgrf.h"
 #include "yapf/yapf.h"
 #include "newgrf_engine.h"
@@ -39,8 +34,15 @@
 #include "newgrf_station.h"
 #include "train.h"
 #include "misc/autoptr.hpp"
+#include "variables.h"
 #include "autoslope.h"
 #include "transparency.h"
+#include "water.h"
+#include "tunnelbridge_map.h"
+#include "window_func.h"
+#include "vehicle_func.h"
+#include "sound_func.h"
+
 
 const byte _track_sloped_sprites[14] = {
 	14, 15, 22, 13,
@@ -81,21 +83,14 @@
  *               11uuuudd => rail depot
  */
 
-/** Struct used in EnsureNoTrainOnTrack() */
-struct TrainOnTrackData {
-	TileIndex tile;       ///< tile to check
-	uint z;               ///< tile max Z
-	TrackBits rail_bits;  ///< trackbits of interest
-};
 
 static void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
 {
-	const TrainOnTrackData *info = (const TrainOnTrackData *)data;
-
-	if (v->tile != info->tile || v->type != VEH_TRAIN) return NULL;
-	if (v->z_pos > info->z) return NULL;
-
-	if ((v->u.rail.track != info->rail_bits) && !TracksOverlap(v->u.rail.track | info->rail_bits)) return NULL;
+	TrackBits rail_bits = *(TrackBits *)data;
+
+	if (v->type != VEH_TRAIN) return NULL;
+
+	if ((v->u.rail.track != rail_bits) && !TracksOverlap(v->u.rail.track | rail_bits)) return NULL;
 
 	_error_message = VehicleInTheWayErrMsg(v);
 	return v;
@@ -110,13 +105,9 @@
  */
 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
 {
-	TrainOnTrackData info;
-
-	info.tile = tile;
-	info.z = GetTileMaxZ(tile);
-	info.rail_bits = TrackToTrackBits(track);
-
-	return VehicleFromPos(tile, &info, EnsureNoTrainOnTrackProc) == NULL;
+	TrackBits rail_bits = TrackToTrackBits(track);
+
+	return VehicleFromPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc) == NULL;
 }
 
 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
@@ -297,7 +288,7 @@
 	   ) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
 	Foundation f_old = GetRailFoundation(tileh, existing);
-	return CommandCost(f_new != f_old ? _price.terraform : (Money)0);
+	return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price.terraform : (Money)0);
 }
 
 /* Validate functions for rail building */
@@ -315,7 +306,7 @@
 	RailType railtype;
 	Track track;
 	TrackBits trackbit;
-	CommandCost cost;
+	CommandCost cost(EXPENSES_CONSTRUCTION);
 	CommandCost ret;
 
 	if (!ValParamRailtype(p1) || !ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
@@ -325,8 +316,6 @@
 	tileh = GetTileSlope(tile, NULL);
 	trackbit = TrackToTrackBits(track);
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	switch (GetTileType(tile)) {
 		case MP_RAILWAY:
 			if (!CheckTrackCombination(tile, trackbit, flags) ||
@@ -418,7 +407,7 @@
 
 			if (water_ground) {
 				cost.AddCost(-_price.clear_water);
-				cost.AddCost(_price.purchase_land);
+				cost.AddCost(_price.clear_roughland);
 			}
 
 			if (flags & DC_EXEC) {
@@ -447,14 +436,12 @@
 {
 	Track track = (Track)p2;
 	TrackBits trackbit;
-	CommandCost cost(_price.remove_rail);
+	CommandCost cost(EXPENSES_CONSTRUCTION, _price.remove_rail );
 	bool crossing = false;
 
 	if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
 	trackbit = TrackToTrackBits(track);
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	switch (GetTileType(tile)) {
 		case MP_ROAD: {
 			if (!IsLevelCrossing(tile) ||
@@ -633,7 +620,7 @@
  */
 static CommandCost CmdRailTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	CommandCost ret, total_cost;
+	CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
 	Track track = (Track)GB(p2, 4, 3);
 	Trackdir trackdir;
 	byte mode = HasBit(p2, 7);
@@ -645,8 +632,6 @@
 	end_tile = p1;
 	trackdir = TrackToTrackdir(track);
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
 
 	if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
@@ -715,11 +700,8 @@
  */
 CommandCost CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	CommandCost cost;
 	Slope tileh;
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	/* check railtype and valid direction for depot (0 through 3), 4 in total */
 	if (!ValParamRailtype(p1)) return CMD_ERROR;
 
@@ -743,7 +725,7 @@
 		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 	}
 
-	cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
+	CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 	if (CmdFailed(cost)) return CMD_ERROR;
 
 	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
@@ -774,16 +756,20 @@
  * @param flags operation to perform
  * @param p1 various bitstuffed elements
  * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum)
- * - p1 = (bit 3)   - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle)
+ * - p1 = (bit 3)   - 1 = override signal/semaphore, or pre/exit/combo signal or (for bit 7) toggle variant (CTRL-toggle)
  * - p1 = (bit 4)   - 0 = signals, 1 = semaphores
+ * - p1 = (bit 5-6) - type of the signal, for valid values see enum SignalType in rail_map.h
+ * - p1 = (bit 7)   - convert the present signal type and variant
  * @param p2 used for CmdBuildManySignals() to copy direction of first signal
  * TODO: p2 should be replaced by two bits for "along" and "against" the track.
  */
 CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
 	Track track = (Track)GB(p1, 0, 3);
-	bool pre_signal = HasBit(p1, 3);
-	SignalVariant sigvar = (pre_signal ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
+	bool ctrl_pressed = HasBit(p1, 3); // was the CTRL button pressed
+	SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; // the signal variant of the new signal
+	SignalType sigtype = (SignalType)GB(p1, 5, 2); // the signal type of the new signal
+	bool convert_signal = HasBit(p1, 7); // convert button pressed
 	CommandCost cost;
 
 	if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoTrainOnTrack(tile, track))
@@ -797,27 +783,37 @@
 
 	if (!CheckTileOwnership(tile)) return CMD_ERROR;
 
-	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
-
 	{
 		/* See if this is a valid track combination for signals, (ie, no overlap) */
 		TrackBits trackbits = GetTrackBits(tile);
 		if (KillFirstBit(trackbits) != TRACK_BIT_NONE && /* More than one track present */
 				trackbits != TRACK_BIT_HORZ &&
 				trackbits != TRACK_BIT_VERT) {
-			return CMD_ERROR;
+			return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
 		}
 	}
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
+	/* you can not convert a signal if no signal is on track */
+	if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
 
 	if (!HasSignalOnTrack(tile, track)) {
 		/* build new signals */
-		cost = CommandCost(_price.build_signals);
+		cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals);
 	} else {
 		if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
 			/* convert signals <-> semaphores */
-			cost = CommandCost(_price.build_signals + _price.remove_signals);
+			cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
+
+		} else if (convert_signal) {
+			/* convert button pressed */
+			if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
+				/* convert electric <-> semaphore */
+				cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
+			} else {
+				/* it is free to change signal type: normal-pre-exit-combo */
+				cost = CommandCost();
+			}
+
 		} else {
 			/* it is free to change orientation/pre-exit-combo signals */
 			cost = CommandCost();
@@ -830,7 +826,7 @@
 			SetHasSignals(tile, true);
 			SetSignalStates(tile, 0xF); // all signals are on
 			SetPresentSignals(tile, 0); // no signals built by default
-			SetSignalType(tile, track, SIGTYPE_NORMAL);
+			SetSignalType(tile, track, sigtype);
 			SetSignalVariant(tile, track, sigvar);
 		}
 
@@ -838,15 +834,28 @@
 			if (!HasSignalOnTrack(tile, track)) {
 				/* build new signals */
 				SetPresentSignals(tile, GetPresentSignals(tile) | SignalOnTrack(track));
-				SetSignalType(tile, track, SIGTYPE_NORMAL);
+				SetSignalType(tile, track, sigtype);
 				SetSignalVariant(tile, track, sigvar);
 			} else {
-				if (pre_signal) {
+				if (convert_signal) {
+					/* convert signal button pressed */
+					if (ctrl_pressed) {
+						/* toggle the pressent signal variant: SIG_ELECTRIC <-> SIG_SEMAPHORE */
+						SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
+
+					} else {
+						/* convert the present signal to the chosen type and variant */
+						SetSignalType(tile, track, sigtype);
+						SetSignalVariant(tile, track, sigvar);
+					}
+
+				} else if (ctrl_pressed) {
 					/* cycle between normal -> pre -> exit -> combo -> ... */
-					SignalType type = GetSignalType(tile, track);
-
-					SetSignalType(tile, track, type == SIGTYPE_COMBO ? SIGTYPE_NORMAL : (SignalType)(type + 1));
+					sigtype = GetSignalType(tile, track);
+
+					SetSignalType(tile, track, sigtype == SIGTYPE_COMBO ? SIGTYPE_NORMAL : (SignalType)(sigtype + 1));
 				} else {
+					/* cycle the signal side: both -> left -> right -> both -> ... */
 					CycleSignalSide(tile, track);
 				}
 			}
@@ -904,17 +913,15 @@
 			return true;
 
 		case MP_TUNNELBRIDGE: {
-			TileIndex orig_tile = tile;
-			/* Skip to end of tunnel or bridge */
-			if (IsBridge(tile)) {
-				if (GetBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
-				if (GetBridgeRampDirection(tile) != TrackdirToExitdir(trackdir)) return false;
-				tile = GetOtherBridgeEnd(tile);
-			} else {
-				if (GetTunnelTransportType(tile) != TRANSPORT_RAIL) return false;
-				if (GetTunnelDirection(tile) != TrackdirToExitdir(trackdir)) return false;
-				tile = GetOtherTunnelEnd(tile);
-			}
+			TileIndex orig_tile = tile; // backup old value
+
+			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
+			if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
+
+			/* Skip to end of tunnel or bridge
+			 * note that tile is a parameter by reference, so it must be updated */
+			tile = GetOtherTunnelBridgeEnd(tile);
+
 			signal_ctr += 2 + DistanceMax(orig_tile, tile) * 2;
 			return true;
 		}
@@ -937,7 +944,7 @@
  */
 static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 {
-	CommandCost ret, total_cost;
+	CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
 	int signal_ctr;
 	byte signals;
 	bool error = true;
@@ -958,8 +965,6 @@
 
 	if (!IsTileType(tile, MP_RAILWAY)) return CMD_ERROR;
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	/* for vertical/horizontal tracks, double the given signals density
 	 * since the original amount will be too dense (shorter tracks) */
 	signal_density *= 2;
@@ -1082,8 +1087,6 @@
 	/* Only water can remove signals from anyone */
 	if (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
 
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
 	/* Do it? */
 	if (flags & DC_EXEC) {
 		SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
@@ -1101,7 +1104,7 @@
 		MarkTileDirtyByTile(tile);
 	}
 
-	return CommandCost(_price.remove_signals);
+	return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_signals);
 }
 
 /** Remove signals on a stretch of track.
@@ -1123,13 +1126,12 @@
 	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() */
 
-	if (v->type == VEH_TRAIN && v->tile == *(TileIndex*)data && !IsArticulatedPart(v)) {
+	if (v->type == VEH_TRAIN && !IsArticulatedPart(v)) {
 		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 		if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First());
 	}
@@ -1137,46 +1139,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, &tile, UpdateTrainPowerProc);
-	}
-
-	return CommandCost(RailBuildCost(totype) / 2);
-}
-
-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
@@ -1186,72 +1148,152 @@
  */
 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(EXPENSES_CONSTRUCTION);
 
 	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) {
+	_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:
+					switch (GetRailTileType(tile)) {
+						case RAIL_TILE_WAYPOINT:
+							if (flags & DC_EXEC) {
+								/* notify YAPF about the track layout change */
+								YapfNotifyTrackLayoutChange(tile, AxisToTrack(GetWaypointAxis(tile)));
+							}
+							cost.AddCost(RailConvertCost(type, totype));
+							break;
+
+						case RAIL_TILE_DEPOT:
+							if (flags & DC_EXEC) {
+								/* notify YAPF about the track layout change */
+								YapfNotifyTrackLayoutChange(tile, AxisToTrack(DiagDirToAxis(GetRailDepotDirection(tile))));
+
+								/* Update build vehicle window related to this depot */
+								InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
+								InvalidateWindowData(WC_BUILD_VEHICLE, tile);
+							}
+							cost.AddCost(RailConvertCost(type, totype));
+							break;
+
+						default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
+							if (flags & DC_EXEC) {
+								/* notify YAPF about the track layout change */
+								TrackBits tracks = GetTrackBits(tile);
+								while (tracks != TRACK_BIT_NONE) {
+									YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
+								}
+							}
+							cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
+							break;
+					}
+					break;
+
+				case MP_TUNNELBRIDGE: {
+					TileIndex endtile = GetOtherTunnelBridgeEnd(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)
@@ -1271,12 +1313,12 @@
 		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
 	}
 
-	return CommandCost(_price.remove_train_depot);
+	return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
 }
 
 static CommandCost ClearTile_Track(TileIndex tile, byte flags)
 {
-	CommandCost cost;
+	CommandCost cost(EXPENSES_CONSTRUCTION);
 	CommandCost ret;
 
 	if (flags & DC_AUTO) {
@@ -1752,7 +1794,7 @@
 				image += relocation;
 			}
 
-			if (!IsTransparencySet(TO_BUILDINGS) && HasBit(image, PALETTE_MODIFIER_COLOR)) {
+			if (!(!HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)) && HasBit(image, PALETTE_MODIFIER_COLOR)) {
 				pal = _drawtile_track_palette;
 			} else {
 				pal = dtss->pal;
@@ -1764,7 +1806,7 @@
 					ti->x + dtss->delta_x, ti->y + dtss->delta_y,
 					dtss->size_x, dtss->size_y,
 					dtss->size_z, ti->z + dtss->delta_z,
-					IsTransparencySet(TO_BUILDINGS)
+					!HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
 				);
 			} else {
 				AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y);
@@ -1862,23 +1904,14 @@
 	return false;
 }
 
-/* Struct to parse data from VehicleFromPos to SignalVehicleCheckProc */
-struct SignalVehicleCheckStruct {
-	TileIndex tile;
-	uint track;
-};
-
 static void *SignalVehicleCheckProc(Vehicle *v, void *data)
 {
-	const SignalVehicleCheckStruct* dest = (SignalVehicleCheckStruct*)data;
+	uint track = *(uint*)data;
 
 	if (v->type != VEH_TRAIN) return NULL;
 
-	/* Wrong tile, or no train? Not a match */
-	if (v->tile != dest->tile) return NULL;
-
 	/* Are we on the same piece of track? */
-	if (dest->track & v->u.rail.track * 0x101) return v;
+	if (track & v->u.rail.track * 0x101) return v;
 
 	return NULL;
 }
@@ -1886,42 +1919,12 @@
 /* Special check for SetSignalsAfterProc, to see if there is a vehicle on this tile */
 static bool SignalVehicleCheck(TileIndex tile, uint track)
 {
-	SignalVehicleCheckStruct dest;
-
-	dest.tile = tile;
-	dest.track = track;
-
-	/* Locate vehicles in tunnels or on bridges */
-	if (IsTunnelTile(tile) || IsBridgeTile(tile)) {
-		TileIndex end;
-		DiagDirection direction;
-
-		if (IsTunnelTile(tile)) {
-			end = GetOtherTunnelEnd(tile);
-			direction = GetTunnelDirection(tile);
-		} else {
-			end = GetOtherBridgeEnd(tile);
-			direction = GetBridgeRampDirection(tile);
-		}
-
-		dest.track = 1 << (direction & 1); // get the trackbit the vehicle would have if it has not entered the tunnel yet (ie is still visible)
-
-		/* check for a vehicle with that trackdir on the start tile of the tunnel */
-		if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true;
-
-		/* check for a vehicle with that trackdir on the end tile of the tunnel */
-		if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
-
-		/* now check all tiles from start to end for a warping vehicle */
-		dest.track = 0x40;   //Vehicle inside a tunnel or on a bridge
-		if (VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL) return true;
-		if (VehicleFromPos(end, &dest, SignalVehicleCheckProc) != NULL) return true;
-
-		/* no vehicle found */
-		return false;
+	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
+		/* Locate vehicles in tunnels or on bridges */
+		return GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL;
+	} else {
+		return VehicleFromPos(tile, &track, &SignalVehicleCheckProc) != NULL;
 	}
-
-	return VehicleFromPos(tile, &dest, SignalVehicleCheckProc) != NULL;
 }
 
 static void SetSignalsAfterProc(TrackPathFinder *tpf)
@@ -2329,7 +2332,7 @@
 	 0,  1,  0, -1  /* y */
 };
 
-static uint32 VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
+static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
 {
 	byte fract_coord;
 	byte fract_coord_leave;
@@ -2412,7 +2415,7 @@
 		case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
 
 		/* Surface slope must not be changed */
-		default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : _price.terraform);
+		default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price.terraform));
 	}
 
 	/* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
@@ -2420,7 +2423,7 @@
 	z_new += GetSlopeZInCorner((Slope)(tileh_new & ~SLOPE_HALFTILE_MASK), track_corner);
 	if (z_old != z_new) return CMD_ERROR;
 
-	CommandCost cost = CommandCost(_price.terraform);
+	CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 	/* Make the ground dirty, if surface slope has changed */
 	if (tileh_old != tileh_new) {
 		if (GetRailGroundType(tile) == RAIL_GROUND_WATER) cost.AddCost(_price.clear_water);
@@ -2467,7 +2470,7 @@
 		if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
 
 		/* allow terraforming */
-		return (was_water ? CommandCost(_price.clear_water) : CommandCost());
+		return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0);
 	} else {
 		if (_patches.build_on_slopes && AutoslopeEnabled()) {
 			switch (GetRailTileType(tile)) {
@@ -2478,7 +2481,7 @@
 				}
 
 				case RAIL_TILE_DEPOT:
-					if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) return _price.terraform;
+					if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 					break;
 
 				default: NOT_REACHED();