Changeset - r16738:d08e218e816c
[Not reviewed]
master
0 1 0
rubidium - 14 years ago 2010-12-12 17:21:49
rubidium@openttd.org
(svn r21481) -Codechange: make rail conversion make use of TILE_AREA_LOOP as well
1 file changed with 137 insertions and 148 deletions:
0 comments (0 inline, 0 general)
src/rail_cmd.cpp
Show inline comments
 
@@ -1394,185 +1394,174 @@ CommandCost CmdConvertRail(TileIndex til
 
{
 
	RailType totype = Extract<RailType, 0, 4>(p2);
 

	
 
	if (!ValParamRailtype(totype)) return CMD_ERROR;
 
	if (p1 >= MapSize()) return CMD_ERROR;
 

	
 
	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 */
 
	if (ex < sx) Swap(ex, sx);
 
	if (ey < sy) Swap(ey, sy);
 

	
 
	TrainList affected_trains;
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost error = CommandCost(STR_ERROR_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);
 
			TileType tt = GetTileType(tile);
 

	
 
			/* Check if there is any track on tile */
 
			switch (tt) {
 
				case MP_RAILWAY:
 
					break;
 
				case MP_STATION:
 
					if (!HasStationRail(tile)) continue;
 
					break;
 
				case MP_ROAD:
 
					if (!IsLevelCrossing(tile)) continue;
 
					if (RailNoLevelCrossings(totype)) {
 
						error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
 
						continue;
 
	TileArea ta(tile, p1);
 
	TILE_AREA_LOOP(tile, ta) {
 
		TileType tt = GetTileType(tile);
 

	
 
		/* Check if there is any track on tile */
 
		switch (tt) {
 
			case MP_RAILWAY:
 
				break;
 
			case MP_STATION:
 
				if (!HasStationRail(tile)) continue;
 
				break;
 
			case MP_ROAD:
 
				if (!IsLevelCrossing(tile)) continue;
 
				if (RailNoLevelCrossings(totype)) {
 
					error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
 
					continue;
 
				}
 
				break;
 
			case MP_TUNNELBRIDGE:
 
				if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
 
				break;
 
			default: continue;
 
		}
 

	
 
		/* Original railtype we are converting from */
 
		RailType type = GetRailType(tile);
 

	
 
		/* Converting to the same type or converting 'hidden' elrail -> rail */
 
		if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
 

	
 
		/* Trying to convert other's rail */
 
		CommandCost ret = CheckTileOwnership(tile);
 
		if (ret.Failed()) {
 
			error = ret;
 
			continue;
 
		}
 

	
 
		SmallVector<Train *, 2> vehicles_affected;
 

	
 
		/* Vehicle on the tile when not converting Rail <-> ElRail
 
		 * Tunnels and bridges have special check later */
 
		if (tt != MP_TUNNELBRIDGE) {
 
			if (!IsCompatibleRail(type, totype)) {
 
				CommandCost ret = EnsureNoVehicleOnGround(tile);
 
				if (ret.Failed()) {
 
					error = ret;
 
					continue;
 
				}
 
			}
 
			if (flags & DC_EXEC) { // we can safely convert, too
 
				TrackBits reserved = GetReservedTrackbits(tile);
 
				Track     track;
 
				while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
 
					Train *v = GetTrainForReservation(tile, track);
 
					if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
 
						/* No power on new rail type, reroute. */
 
						FreeTrainTrackReservation(v);
 
						*vehicles_affected.Append() = v;
 
					}
 
					break;
 
				case MP_TUNNELBRIDGE:
 
					if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
 
					break;
 
				default: continue;
 
				}
 

	
 
				SetRailType(tile, totype);
 
				MarkTileDirtyByTile(tile);
 
				/* update power of train on this tile */
 
				FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
 
			}
 

	
 
			/* Original railtype we are converting from */
 
			RailType type = GetRailType(tile);
 

	
 
			/* Converting to the same type or converting 'hidden' elrail -> rail */
 
			if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
 

	
 
			/* Trying to convert other's rail */
 
			CommandCost ret = CheckTileOwnership(tile);
 
			if (ret.Failed()) {
 
				error = ret;
 
				continue;
 
			}
 

	
 
			SmallVector<Train *, 2> vehicles_affected;
 

	
 
			/* Vehicle on the tile when not converting Rail <-> ElRail
 
			 * Tunnels and bridges have special check later */
 
			if (tt != MP_TUNNELBRIDGE) {
 
				if (!IsCompatibleRail(type, totype)) {
 
					CommandCost ret = EnsureNoVehicleOnGround(tile);
 
		}
 

	
 
		switch (tt) {
 
			case MP_RAILWAY:
 
				switch (GetRailTileType(tile)) {
 
					case RAIL_TILE_DEPOT:
 
						if (flags & DC_EXEC) {
 
							/* notify YAPF about the track layout change */
 
							YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(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) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
 
						TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
 

	
 
				/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
 
				if (!IsCompatibleRail(GetRailType(tile), totype)) {
 
					CommandCost ret = TunnelBridgeIsFree(tile, endtile);
 
					if (ret.Failed()) {
 
						error = ret;
 
						continue;
 
					}
 
				}
 
				if (flags & DC_EXEC) { // we can safely convert, too
 
					TrackBits reserved = GetReservedTrackbits(tile);
 
					Track     track;
 
					while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
 

	
 
				if (flags & DC_EXEC) {
 
					Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
 
					if (HasTunnelBridgeReservation(tile)) {
 
						Train *v = GetTrainForReservation(tile, track);
 
						if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
 
							/* No power on new rail type, reroute. */
 
							FreeTrainTrackReservation(v);
 
							*vehicles_affected.Append() = v;
 
						}
 
					}
 

	
 
					SetRailType(tile, totype);
 
					MarkTileDirtyByTile(tile);
 
					/* update power of train on this tile */
 
					SetRailType(endtile, totype);
 

	
 
					FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
 
				}
 
			}
 

	
 
			switch (tt) {
 
				case MP_RAILWAY:
 
					switch (GetRailTileType(tile)) {
 
						case RAIL_TILE_DEPOT:
 
							if (flags & DC_EXEC) {
 
								/* notify YAPF about the track layout change */
 
								YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(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;
 
					FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
 

	
 
					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
 
					}
 
					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)) {
 
						CommandCost ret = TunnelBridgeIsFree(tile, endtile);
 
						if (ret.Failed()) {
 
							error = ret;
 
							continue;
 
						}
 
					}
 

	
 
					if (flags & DC_EXEC) {
 
						Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
 
						if (HasTunnelBridgeReservation(tile)) {
 
							Train *v = GetTrainForReservation(tile, track);
 
							if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
 
								/* No power on new rail type, reroute. */
 
								FreeTrainTrackReservation(v);
 
								*vehicles_affected.Append() = v;
 
							}
 
						}
 
						SetRailType(tile, totype);
 
						SetRailType(endtile, totype);
 

	
 
						FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
 
						FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
 

	
 
						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((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
 
					break;
 
				}
 

	
 
				default: // MP_STATION, MP_ROAD
 
					if (flags & DC_EXEC) {
 
						Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
 
						YapfNotifyTrackLayoutChange(tile, track);
 
					}
 

	
 
					cost.AddCost(RailConvertCost(type, totype));
 
					break;
 
				cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
 
				break;
 
			}
 

	
 
			for (uint i = 0; i < vehicles_affected.Length(); ++i) {
 
				TryPathReserve(vehicles_affected[i], true);
 
			}
 
			default: // MP_STATION, MP_ROAD
 
				if (flags & DC_EXEC) {
 
					Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
 
					YapfNotifyTrackLayoutChange(tile, track);
 
				}
 

	
 
				cost.AddCost(RailConvertCost(type, totype));
 
				break;
 
		}
 

	
 
		for (uint i = 0; i < vehicles_affected.Length(); ++i) {
 
			TryPathReserve(vehicles_affected[i], true);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* Railtype changed, update trains as when entering different track */
 
		for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
0 comments (0 inline, 0 general)