(svn r21481) -Codechange: make rail conversion make use of TILE_AREA_LOOP as well

This commit is contained in:
rubidium 2010-12-12 17:21:49 +00:00
parent 90e247c84d
commit a1d923700f

View File

@ -1397,73 +1397,126 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (!ValParamRailtype(totype)) return CMD_ERROR; if (!ValParamRailtype(totype)) return CMD_ERROR;
if (p1 >= MapSize()) 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; TrainList affected_trains;
CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost cost(EXPENSES_CONSTRUCTION);
CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert. CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
for (uint x = sx; x <= ex; ++x) { TileArea ta(tile, p1);
for (uint y = sy; y <= ey; ++y) { TILE_AREA_LOOP(tile, ta) {
TileIndex tile = TileXY(x, y); TileType tt = GetTileType(tile);
TileType tt = GetTileType(tile);
/* Check if there is any track on tile */ /* Check if there is any track on tile */
switch (tt) { switch (tt) {
case MP_RAILWAY: case MP_RAILWAY:
break; break;
case MP_STATION: case MP_STATION:
if (!HasStationRail(tile)) continue; if (!HasStationRail(tile)) continue;
break; break;
case MP_ROAD: case MP_ROAD:
if (!IsLevelCrossing(tile)) continue; if (!IsLevelCrossing(tile)) continue;
if (RailNoLevelCrossings(totype)) { if (RailNoLevelCrossings(totype)) {
error.MakeError(STR_ERROR_CROSSING_DISALLOWED); error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
continue; 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; SetRailType(tile, totype);
break; MarkTileDirtyByTile(tile);
default: continue; /* update power of train on this tile */
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
} }
}
/* Original railtype we are converting from */ switch (tt) {
RailType type = GetRailType(tile); 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));
/* Converting to the same type or converting 'hidden' elrail -> rail */ /* Update build vehicle window related to this depot */
if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue; InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
InvalidateWindowData(WC_BUILD_VEHICLE, tile);
}
cost.AddCost(RailConvertCost(type, totype));
break;
/* Trying to convert other's rail */ default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
CommandCost ret = CheckTileOwnership(tile); if (flags & DC_EXEC) {
if (ret.Failed()) { /* notify YAPF about the track layout change */
error = ret; TrackBits tracks = GetTrackBits(tile);
continue; while (tracks != TRACK_BIT_NONE) {
} YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
}
}
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
break;
}
break;
SmallVector<Train *, 2> vehicles_affected; case MP_TUNNELBRIDGE: {
TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
/* Vehicle on the tile when not converting Rail <-> ElRail /* If both ends of tunnel/bridge are in the range, do not try to convert twice -
* Tunnels and bridges have special check later */ * it would cause assert because of different test and exec runs */
if (tt != MP_TUNNELBRIDGE) { if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
if (!IsCompatibleRail(type, totype)) { TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
CommandCost ret = EnsureNoVehicleOnGround(tile);
/* 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()) { if (ret.Failed()) {
error = ret; error = ret;
continue; continue;
} }
} }
if (flags & DC_EXEC) { // we can safely convert, too
TrackBits reserved = GetReservedTrackbits(tile); if (flags & DC_EXEC) {
Track track; Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) { if (HasTunnelBridgeReservation(tile)) {
Train *v = GetTrainForReservation(tile, track); Train *v = GetTrainForReservation(tile, track);
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) { if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
/* No power on new rail type, reroute. */ /* No power on new rail type, reroute. */
@ -1471,105 +1524,41 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
*vehicles_affected.Append() = v; *vehicles_affected.Append() = v;
} }
} }
SetRailType(tile, totype); SetRailType(tile, totype);
MarkTileDirtyByTile(tile); SetRailType(endtile, totype);
/* update power of train on this tile */
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
} FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
}
switch (tt) { YapfNotifyTrackLayoutChange(tile, track);
case MP_RAILWAY: YapfNotifyTrackLayoutChange(endtile, track);
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 */ MarkTileDirtyByTile(tile);
InvalidateWindowData(WC_VEHICLE_DEPOT, tile); MarkTileDirtyByTile(endtile);
InvalidateWindowData(WC_BUILD_VEHICLE, tile);
}
cost.AddCost(RailConvertCost(type, totype));
break;
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS if (IsBridge(tile)) {
if (flags & DC_EXEC) { TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
/* notify YAPF about the track layout change */ TileIndex t = tile + delta;
TrackBits tracks = GetTrackBits(tile); for (; t != endtile; t += delta) MarkTileDirtyByTile(t); // TODO encapsulate this into a function
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)) {
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 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
if (flags & DC_EXEC) { break;
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) { default: // MP_STATION, MP_ROAD
TryPathReserve(vehicles_affected[i], true); 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);
} }
} }