Changeset - r8096:e424ba98e353
[Not reviewed]
master
0 5 0
smatz - 16 years ago 2007-12-17 22:29:27
smatz@openttd.org
(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
5 files changed with 112 insertions and 184 deletions:
0 comments (0 inline, 0 general)
src/command.cpp
Show inline comments
 
@@ -549,7 +549,6 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	 * 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 ||
src/rail_cmd.cpp
Show inline comments
 
@@ -1143,8 +1143,7 @@ CommandCost CmdRemoveSignalTrack(TileInd
 
	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 @@ void *UpdateTrainPowerProc(Vehicle *v, v
 
	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 @@ extern CommandCost DoConvertTunnelBridge
 
 */
 
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)
src/road_cmd.cpp
Show inline comments
 
@@ -593,30 +593,6 @@ do_clear:;
 
	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
src/station_cmd.cpp
Show inline comments
 
@@ -1290,29 +1290,6 @@ static CommandCost RemoveRailroadStation
 
}
 

	
 
/**
 
 * 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*
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -691,54 +691,6 @@ static CommandCost ClearTile_TunnelBridg
 
}
 

	
 
/**
 
 * 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.
0 comments (0 inline, 0 general)