mirror of https://github.com/OpenTTD/OpenTTD
(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/bridgesrelease/0.6
parent
bda9d4a236
commit
0b08f7370d
|
@ -549,7 +549,6 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
|
||||||
* estimate the cost of cloning a vehicle. */
|
* estimate the cost of cloning a vehicle. */
|
||||||
notest =
|
notest =
|
||||||
(cmd & 0xFF) == CMD_CLEAR_AREA ||
|
(cmd & 0xFF) == CMD_CLEAR_AREA ||
|
||||||
(cmd & 0xFF) == CMD_CONVERT_RAIL ||
|
|
||||||
(cmd & 0xFF) == CMD_LEVEL_LAND ||
|
(cmd & 0xFF) == CMD_LEVEL_LAND ||
|
||||||
(cmd & 0xFF) == CMD_REMOVE_ROAD ||
|
(cmd & 0xFF) == CMD_REMOVE_ROAD ||
|
||||||
(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD ||
|
(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD ||
|
||||||
|
|
206
src/rail_cmd.cpp
206
src/rail_cmd.cpp
|
@ -1143,8 +1143,7 @@ CommandCost CmdRemoveSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32
|
||||||
return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5)); // bit 5 is remove bit
|
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)
|
void *UpdateTrainPowerProc(Vehicle *v, void *data)
|
||||||
{
|
{
|
||||||
/* Similiar checks as in TrainPowerChanged() */
|
/* Similiar checks as in TrainPowerChanged() */
|
||||||
|
@ -1157,23 +1156,80 @@ void *UpdateTrainPowerProc(Vehicle *v, void *data)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Convert one rail type to the other. You can convert normal rail to
|
||||||
* Switches the rail type.
|
* monorail/maglev easily or vice-versa.
|
||||||
* Railtypes are stored on a per-tile basis, not on a per-track basis, so
|
* @param tile end tile of rail conversion drag
|
||||||
* all the tracks in the given tile will be converted.
|
* @param flags operation to perform
|
||||||
* @param tile The tile on which the railtype is to be convert.
|
* @param p1 start tile of drag
|
||||||
* @param totype The railtype we want to convert to
|
* @param p2 new railtype 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)
|
CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||||
{
|
{
|
||||||
/* change type. */
|
CommandCost cost;
|
||||||
if (exec) {
|
|
||||||
|
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 */
|
||||||
|
if (ex < sx) Swap(ex, sx);
|
||||||
|
if (ey < sy) Swap(ey, sy);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Original railtype we are converting from */
|
||||||
|
RailType type = GetRailType(tile);
|
||||||
|
|
||||||
|
/* 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);
|
SetRailType(tile, totype);
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
|
/* update power of train engines on this tile */
|
||||||
|
VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tt) {
|
||||||
|
case MP_RAILWAY:
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
/* notify YAPF about the track layout change */
|
/* notify YAPF about the track layout change */
|
||||||
TrackBits tracks = GetTrackBits(tile);
|
TrackBits tracks = GetTrackBits(tile);
|
||||||
while (tracks != TRACK_BIT_NONE) {
|
while (tracks != TRACK_BIT_NONE) {
|
||||||
|
@ -1185,93 +1241,61 @@ static CommandCost DoConvertRail(TileIndex tile, RailType totype, bool exec)
|
||||||
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
|
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
|
||||||
InvalidateWindowData(WC_BUILD_VEHICLE, 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)));
|
cost.AddCost(CommandCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile))));
|
||||||
}
|
break;
|
||||||
|
|
||||||
extern CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec);
|
case MP_TUNNELBRIDGE: {
|
||||||
extern CommandCost DoConvertStreetRail(TileIndex tile, RailType totype, bool exec);
|
TileIndex endtile = IsTunnel(tile) ? GetOtherTunnelEnd(tile) : GetOtherBridgeEnd(tile);
|
||||||
extern CommandCost DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec);
|
|
||||||
|
|
||||||
/** Convert one rail type to the other. You can convert normal rail to
|
/* If both ends of tunnel/bridge are in the range, do not try to convert twice -
|
||||||
* monorail/maglev easily or vice-versa.
|
* it would cause assert because of different test and exec runs */
|
||||||
* @param tile end tile of rail conversion drag
|
if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
|
||||||
* @param flags operation to perform
|
TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
|
||||||
* @param p1 start tile of drag
|
|
||||||
* @param p2 new railtype to convert to
|
|
||||||
*/
|
|
||||||
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);
|
/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
|
||||||
|
if (!IsCompatibleRail(GetRailType(tile), totype) &&
|
||||||
if (!ValParamRailtype(p2)) return CMD_ERROR;
|
GetVehicleTunnelBridge(tile, endtile) != NULL) continue;
|
||||||
if (p1 >= MapSize()) return CMD_ERROR;
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
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;
|
|
||||||
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()
|
|
||||||
*/
|
|
||||||
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) {
|
if (flags & DC_EXEC) {
|
||||||
money -= ret.GetCost();
|
SetRailType(tile, totype);
|
||||||
if (money < 0) {
|
SetRailType(endtile, totype);
|
||||||
_additional_cash_required = ret.GetCost();
|
|
||||||
return cost;
|
VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
|
||||||
}
|
VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
|
||||||
proc(tile, totype, true);
|
|
||||||
}
|
Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
||||||
cost.AddCost(ret);
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (cost.GetCost() == 0) ? ret : cost;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cost.GetCost() == 0) ? CMD_ERROR : cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CommandCost RemoveTrainDepot(TileIndex tile, uint32 flags)
|
static CommandCost RemoveTrainDepot(TileIndex tile, uint32 flags)
|
||||||
|
|
|
@ -593,30 +593,6 @@ do_clear:;
|
||||||
return cost;
|
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.
|
/** Build a long piece of road.
|
||||||
* @param end_tile end tile of drag
|
* @param end_tile end tile of drag
|
||||||
* @param flags operation to perform
|
* @param flags operation to perform
|
||||||
|
|
|
@ -1289,29 +1289,6 @@ static CommandCost RemoveRailroadStation(Station *st, TileIndex tile, uint32 fla
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 truck_station Determines whether a stop is RoadStop::BUS or RoadStop::TRUCK
|
||||||
* @param st The Station to do the whole procedure for
|
* @param st The Station to do the whole procedure for
|
||||||
|
|
|
@ -690,54 +690,6 @@ static CommandCost ClearTile_TunnelBridge(TileIndex tile, byte flags)
|
||||||
return CMD_ERROR;
|
return CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Draws the pillars under high bridges.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue