Index: src/rail.h =================================================================== --- src/rail.h (revision 11056) +++ src/rail.h (working copy) @@ -778,6 +778,7 @@ return bits != TRACK_BIT_HORZ && bits != TRACK_BIT_VERT; } +void *UpdateTrainPowerProc(Vehicle *v, void *data); void DrawTrainDepotSprite(int x, int y, int image, RailType railtype); void DrawDefaultWaypointSprite(int x, int y, RailType railtype); Index: src/rail_cmd.cpp =================================================================== --- src/rail_cmd.cpp (revision 11056) +++ src/rail_cmd.cpp (working copy) @@ -34,6 +34,7 @@ #include "railtypes.h" // include table for railtypes #include "newgrf.h" #include "yapf/yapf.h" +#include "newgrf_engine.h" #include "newgrf_callbacks.h" #include "newgrf_station.h" #include "train.h" @@ -1024,6 +1025,18 @@ typedef CommandCost DoConvertRailProc(TileIndex tile, RailType totype, bool exec); +void *UpdateTrainPowerProc(Vehicle *v, void *data) +{ + /* Similiar checks as in TrainPowerChanged() */ + + if (v->type == VEH_TRAIN && v->tile == *(TileIndex*)data && !IsArticulatedPart(v)) { + const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); + if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First()); + } + + return NULL; +} + /** * Switches the rail type. * Railtypes are stored on a per-tile basis, not on a per-track basis, so @@ -1036,15 +1049,6 @@ */ static CommandCost DoConvertRail(TileIndex tile, RailType totype, bool exec) { - if (!CheckTileOwnership(tile)) return CMD_ERROR; - - if (GetRailType(tile) == totype) return CMD_ERROR; - - if (!EnsureNoVehicleOnGround(tile) && (!IsCompatibleRail(GetRailType(tile), totype) || IsPlainRailTile(tile))) return CMD_ERROR; - - /* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */ - if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; - /* change type. */ if (exec) { SetRailType(tile, totype); @@ -1057,18 +1061,12 @@ } if (IsTileDepotType(tile, TRANSPORT_RAIL)) { - Vehicle *v; - /* Update build vehicle window related to this depot */ InvalidateWindowData(WC_BUILD_VEHICLE, tile); + } - /* update power of trains in this depot */ - FOR_ALL_VEHICLES(v) { - if (v->type == VEH_TRAIN && IsFrontEngine(v) && v->tile == tile && v->u.rail.track == 0x80) { - TrainPowerChanged(v); - } - } - } + /* update power of train engines on this tile */ + VehicleFromPos(tile, &tile, UpdateTrainPowerProc); } return CommandCost(_price.build_rail / 2); @@ -1112,6 +1110,7 @@ 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; @@ -1121,7 +1120,22 @@ default: continue; } - ret = proc(tile, (RailType)p2, false); + /* 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) { @@ -1130,7 +1144,7 @@ _additional_cash_required = ret.GetCost(); return cost; } - proc(tile, (RailType)p2, true); + proc(tile, totype, true); } cost.AddCost(ret); } Index: src/station_cmd.cpp =================================================================== --- src/station_cmd.cpp (revision 11056) +++ src/station_cmd.cpp (working copy) @@ -1227,22 +1227,14 @@ */ CommandCost DoConvertStationRail(TileIndex tile, RailType totype, bool exec) { - const Station* st = GetStationByTile(tile); - - if (!CheckOwnership(st->owner) || !EnsureNoVehicle(tile)) return CMD_ERROR; - - // tile is not a railroad station? + /* Tile is not a railroad station? */ if (!IsRailwayStation(tile)) return CMD_ERROR; - if (GetRailType(tile) == totype) return CMD_ERROR; - - // 'hidden' elrails can't be downgraded to normal rail when elrails are disabled - if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; - if (exec) { SetRailType(tile, totype); MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, GetRailStationTrack(tile)); + VehicleFromPos(tile, &tile, UpdateTrainPowerProc); } return CommandCost(_price.build_rail / 2); Index: src/train_cmd.cpp =================================================================== --- src/train_cmd.cpp (revision 11056) +++ src/train_cmd.cpp (working copy) @@ -95,6 +95,9 @@ } if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) { + /* If it has no power (no catenary), stop the train */ + if (total_power == 0) v->vehstatus |= VS_STOPPED; + v->u.rail.cached_power = total_power; v->u.rail.cached_max_te = max_te; InvalidateWindow(WC_VEHICLE_DETAILS, v->index); Index: src/road_cmd.cpp =================================================================== --- src/road_cmd.cpp (revision 11056) +++ src/road_cmd.cpp (working copy) @@ -543,18 +543,11 @@ /* not a railroad crossing? */ if (!IsLevelCrossing(tile)) return CMD_ERROR; - /* not owned by me? */ - if (!CheckTileOwnership(tile) || !EnsureNoVehicleOnGround(tile)) return CMD_ERROR; - - if (GetRailType(tile) == totype) return CMD_ERROR; - - /* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */ - if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; - if (exec) { SetRailType(tile, totype); MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetCrossingRailBits(tile))); + VehicleFromPos(tile, &tile, UpdateTrainPowerProc); } return CommandCost(_price.build_rail / 2); Index: src/tunnelbridge_cmd.cpp =================================================================== --- src/tunnelbridge_cmd.cpp (revision 11056) +++ src/tunnelbridge_cmd.cpp (working copy) @@ -749,68 +749,67 @@ */ CommandCost DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec) { - TileIndex endtile; - if (IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_RAIL) { uint length; + TileIndex endtile; - if (!CheckTileOwnership(tile)) return CMD_ERROR; + /* If not coverting rail <-> el. rail, any vehicle cannot be in tunnel */ + if (!IsCompatibleRail(GetRailType(tile), totype)) { + endtile = CheckTunnelBusy(tile, &length); + if (endtile == INVALID_TILE) return CMD_ERROR; + } else { + endtile = GetOtherTunnelEnd(tile); + length = DistanceManhattan(tile, endtile); + } - if (GetRailType(tile) == totype) return CMD_ERROR; - - /* 'hidden' elrails can't be downgraded to normal rail when elrails are disabled */ - if (_patches.disable_elrails && totype == RAILTYPE_RAIL && GetRailType(tile) == RAILTYPE_ELECTRIC) return CMD_ERROR; - - endtile = CheckTunnelBusy(tile, &length); - if (endtile == INVALID_TILE) return CMD_ERROR; - if (exec) { - Track track; SetRailType(tile, totype); SetRailType(endtile, totype); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(endtile); - track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile))); + Track track = AxisToTrack(DiagDirToAxis(GetTunnelDirection(tile))); + YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); + + VehicleFromPos(tile, &tile, UpdateTrainPowerProc); + VehicleFromPos(endtile, &endtile, UpdateTrainPowerProc); } - return CommandCost((length + 1) * (_price.build_rail / 2)); - } else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) { - if (!CheckTileOwnership(tile)) return CMD_ERROR; - - endtile = GetOtherBridgeEnd(tile); + return CommandCost((length + 1) * (_price.build_rail >> 1)); + } else if (IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_RAIL) { + TileIndex endtile = GetOtherBridgeEnd(tile); byte bridge_height = GetBridgeHeight(tile); - if (FindVehicleOnTileZ(tile, bridge_height) != NULL || + if (!IsCompatibleRail(GetRailType(tile), totype) && + (FindVehicleOnTileZ(tile, bridge_height) != NULL || FindVehicleOnTileZ(endtile, bridge_height) != NULL || - IsVehicleOnBridge(tile, endtile, bridge_height)) { + IsVehicleOnBridge(tile, endtile, bridge_height))) { return CMD_ERROR; } - if (GetRailType(tile) == totype) return CMD_ERROR; - if (exec) { - TileIndexDiff delta; - Track track; - SetRailType(tile, totype); SetRailType(endtile, totype); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(endtile); - track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile))); + Track track = AxisToTrack(DiagDirToAxis(GetBridgeRampDirection(tile))); + TileIndexDiff delta = TileOffsByDiagDir(GetBridgeRampDirection(tile)); + YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); - delta = TileOffsByDiagDir(GetBridgeRampDirection(tile)); + VehicleFromPos(tile, &tile, UpdateTrainPowerProc); + VehicleFromPos(endtile, &endtile, UpdateTrainPowerProc); + for (tile += delta; tile != endtile; tile += delta) { MarkTileDirtyByTile(tile); // TODO encapsulate this into a function } } - return CommandCost((DistanceManhattan(tile, endtile) + 1) * (_price.build_rail / 2)); + return CommandCost((DistanceManhattan(tile, endtile) + 1) * (_price.build_rail >> 1)); } else { return CMD_ERROR; }