diff --git a/src/economy_type.h b/src/economy_type.h index d648c9b09d..a7169245fe 100644 --- a/src/economy_type.h +++ b/src/economy_type.h @@ -201,6 +201,11 @@ static const int MIN_PRICE_MODIFIER = -8; static const int MAX_PRICE_MODIFIER = 16; static const int INVALID_PRICE_MODIFIER = MIN_PRICE_MODIFIER - 1; +/** Multiplier for how many regular track bits a tunnel/bridge counts. */ +static const uint TUNNELBRIDGE_TRACKBIT_FACTOR = 4; +/** Multiplier for how many regular track bits a level crossing counts. */ +static const uint LEVELCROSSING_TRACKBIT_FACTOR = 2; + struct CargoPayment; typedef uint32 CargoPaymentID; diff --git a/src/openttd.cpp b/src/openttd.cpp index d20a2c33a8..520589b8ec 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1115,6 +1115,22 @@ void SwitchToMode(SwitchMode new_mode) */ static void CheckCaches() { + /* Check company infrastructure cache. */ + SmallVector old_infrastructure; + Company *c; + FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); + + extern void AfterLoadCompanyStats(); + AfterLoadCompanyStats(); + + uint i = 0; + FOR_ALL_COMPANIES(c) { + if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { + DEBUG(desync, 2, "infrastructure cache mismatch: company %i", c->index); + } + i++; + } + /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index f749ad94a8..5e00bfcb2f 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -32,6 +32,7 @@ #include "core/backup_type.hpp" #include "date_func.h" #include "strings_func.h" +#include "company_gui.h" #include "table/strings.h" #include "table/railtypes.h" @@ -417,7 +418,17 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { SetRailGroundType(tile, RAIL_GROUND_BARREN); - SetTrackBits(tile, GetTrackBits(tile) | trackbit); + TrackBits bits = GetTrackBits(tile); + SetTrackBits(tile, bits | trackbit); + /* Subtract old infrastructure count. */ + uint pieces = CountBits(bits); + if (TracksOverlap(bits)) pieces *= pieces; + Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces; + /* Add new infrastructure count. */ + pieces = CountBits(bits | trackbit); + if (TracksOverlap(bits | trackbit)) pieces *= pieces; + Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces; + DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); } break; } @@ -459,6 +470,8 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile)); UpdateLevelCrossing(tile, false); + Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR; + DirtyCompanyInfrastructureWindows(_current_company); } break; } @@ -490,6 +503,8 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { MakeRailNormal(tile, _current_company, trackbit, railtype); if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER); + Company::Get(_current_company)->infrastructure.rail[railtype]++; + DirtyCompanyInfrastructureWindows(_current_company); } break; } @@ -553,6 +568,8 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, if (v != NULL) FreeTrainTrackReservation(v); } owner = GetTileOwner(tile); + Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; + DirtyCompanyInfrastructureWindows(owner); MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM)); DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile); } @@ -588,8 +605,20 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } + owner = GetTileOwner(tile); + + /* Subtract old infrastructure count. */ + uint pieces = CountBits(present); + if (TracksOverlap(present)) pieces *= pieces; + Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces; + /* Add new infrastructure count. */ present ^= trackbit; + pieces = CountBits(present); + if (TracksOverlap(present)) pieces *= pieces; + Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces; + DirtyCompanyInfrastructureWindows(owner); + if (present == 0) { Slope tileh = GetTileSlope(tile); /* If there is flat water on the lower halftile, convert the tile to shore so the water remains */ @@ -895,6 +924,9 @@ CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, u MarkTileDirtyByTile(tile); MakeDefaultName(d); + Company::Get(_current_company)->infrastructure.rail[railtype]++; + DirtyCompanyInfrastructureWindows(_current_company); + AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company); YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir)); } @@ -1013,6 +1045,9 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, SetSignalVariant(tile, track, sigvar); } + /* Subtract old signal infrastructure count. */ + Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile)); + if (p2 == 0) { if (!HasSignalOnTrack(tile, track)) { /* build new signals */ @@ -1062,6 +1097,10 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, SetSignalType(tile, track, sigtype); } + /* Add new signal infrastructure count. */ + Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile)); + DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); + if (IsPbsSignal(sigtype)) { /* PBS signals should show red unless they are on a reservation. */ uint mask = GetPresentSignals(tile) & SignalOnTrack(track); @@ -1343,7 +1382,10 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 } } } + Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile)); SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track)); + Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile)); + DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); /* removed last signal from tile? */ if (GetPresentSignals(tile) == 0) { @@ -1481,6 +1523,20 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } } + /* Update the company infrastructure counters. */ + if (IsRailStationTile(tile) && !IsStationTileBlocked(tile)) { + Company *c = Company::Get(GetTileOwner(tile)); + uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1; + if (IsPlainRailTile(tile)) { + TrackBits bits = GetTrackBits(tile); + num_pieces = CountBits(bits); + if (TracksOverlap(bits)) num_pieces *= num_pieces; + } + c->infrastructure.rail[type] -= num_pieces; + c->infrastructure.rail[totype] += num_pieces; + DirtyCompanyInfrastructureWindows(c->index); + } + SetRailType(tile, totype); MarkTileDirtyByTile(tile); /* update power of train on this tile */ @@ -1543,6 +1599,14 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 *vehicles_affected.Append() = v; } } + + /* Update the company infrastructure counters. */ + uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; + Company *c = Company::Get(GetTileOwner(tile)); + c->infrastructure.rail[GetRailType(tile)] -= num_pieces; + c->infrastructure.rail[totype] += num_pieces; + DirtyCompanyInfrastructureWindows(c->index); + SetRailType(tile, totype); SetRailType(endtile, totype); @@ -1613,6 +1677,9 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags) if (v != NULL) FreeTrainTrackReservation(v); } + Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--; + DirtyCompanyInfrastructureWindows(owner); + delete Depot::GetByTile(tile); DoClearSquare(tile); AddSideToSignalBuffer(tile, dir, owner); @@ -2692,6 +2759,23 @@ static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_own if (!IsTileOwner(tile, old_owner)) return; if (new_owner != INVALID_OWNER) { + /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */ + uint num_pieces = 1; + if (IsPlainRail(tile)) { + TrackBits bits = GetTrackBits(tile); + num_pieces = CountBits(bits); + if (TracksOverlap(bits)) num_pieces *= num_pieces; + } + RailType rt = GetRailType(tile); + Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces; + Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces; + + if (HasSignals(tile)) { + uint num_sigs = CountBits(GetPresentSignals(tile)); + Company::Get(old_owner)->infrastructure.signal -= num_sigs; + Company::Get(new_owner)->infrastructure.signal += num_sigs; + } + SetTileOwner(tile, new_owner); } else { DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 5fc871bfb7..0f560165e0 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1671,6 +1671,10 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne if (new_owner == INVALID_OWNER) { DoCommand(tile, 0, GetCrossingRailTrack(tile), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL); } else { + /* Update infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */ + Company::Get(old_owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; + Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; + SetTileOwner(tile, new_owner); } } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 9cdd527151..3873b5d6ed 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2716,6 +2716,7 @@ bool AfterLoadGame() /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); + AfterLoadCompanyStats(); GamelogPrintDebug(1); @@ -2746,6 +2747,8 @@ void ReloadNewGRFData() GroupStatistics::UpdateAfterLoad(); /* update station graphics */ AfterLoadStations(); + /* Update company statistics. */ + AfterLoadCompanyStats(); /* Check and update house and town values */ UpdateHousesAndTowns(); /* Delete news referring to no longer existing entities */ diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index 894611d6e4..358600948a 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -13,6 +13,11 @@ #include "../company_func.h" #include "../company_manager_face.h" #include "../fios.h" +#include "../rail_map.h" +#include "../road_map.h" +#include "../station_map.h" +#include "../tunnelbridge_map.h" +#include "../tunnelbridge.h" #include "saveload.h" @@ -86,6 +91,78 @@ CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face) return cmf; } +/** Rebuilding of company statistics after loading a savegame. */ +void AfterLoadCompanyStats() +{ + /* Reset infrastructure statistics to zero. */ + Company *c; + FOR_ALL_COMPANIES(c) MemSetT(&c->infrastructure, 0); + + for (TileIndex tile = 0; tile < MapSize(); tile++) { + switch (GetTileType(tile)) { + case MP_RAILWAY: + c = Company::GetIfValid(GetTileOwner(tile)); + if (c != NULL) { + uint pieces = 1; + if (IsPlainRail(tile)) { + TrackBits bits = GetTrackBits(tile); + pieces = CountBits(bits); + if (TracksOverlap(bits)) pieces *= pieces; + } + c->infrastructure.rail[GetRailType(tile)] += pieces; + + if (HasSignals(tile)) c->infrastructure.signal += CountBits(GetPresentSignals(tile)); + } + break; + + case MP_ROAD: + if (IsLevelCrossing(tile)) { + c = Company::GetIfValid(GetTileOwner(tile)); + if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; + } + break; + + case MP_STATION: + c = Company::GetIfValid(GetTileOwner(tile)); + + switch (GetStationType(tile)) { + case STATION_RAIL: + case STATION_WAYPOINT: + if (c != NULL && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]++; + break; + + default: + break; + } + break; + + case MP_TUNNELBRIDGE: { + /* Only count the tunnel/bridge if we're on the northern end tile. */ + TileIndex other_end = GetOtherTunnelBridgeEnd(tile); + if (tile < other_end) { + /* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate + * the higher structural maintenance needs, and don't forget the end tiles. */ + uint len = (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; + + switch (GetTunnelBridgeTransportType(tile)) { + case TRANSPORT_RAIL: + c = Company::GetIfValid(GetTileOwner(tile)); + if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += len; + break; + + default: + break; + } + } + break; + } + + default: + break; + } + } +} + /* Save/load of companies */ diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index 613ff262a6..5217db1364 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -31,6 +31,7 @@ void FixupTrainLengths(); void AfterLoadStations(); void AfterLoadRoadStops(); void AfterLoadLabelMaps(); +void AfterLoadCompanyStats(); void UpdateHousesAndTowns(); void UpdateOldAircraft(); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index bb45953817..8f040338c0 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -50,6 +50,7 @@ #include "newgrf_airporttiles.h" #include "order_backup.h" #include "newgrf_house.h" +#include "company_gui.h" #include "table/strings.h" @@ -1218,6 +1219,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 numtracks_orig = numtracks; + Company *c = Company::Get(st->owner); do { TileIndex tile = tile_org; int w = plat_len; @@ -1235,6 +1237,9 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 } } + /* Railtype can change when overbuilding. */ + if (IsRailStationTile(tile) && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--; + /* Remove animation if overbuilding */ DeleteAnimatedTile(tile); byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0; @@ -1246,6 +1251,8 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 SetStationTileRandomBits(tile, GB(Random(), 0, 4)); SetAnimationFrame(tile, 0); + if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++; + if (statspec != NULL) { /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */ uint32 platinfo = GetPlatformInfo(AXIS_X, 0, plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false); @@ -1287,6 +1294,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS); + DirtyCompanyInfrastructureWindows(st->owner); } return cost; @@ -1409,10 +1417,12 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected } bool build_rail = keep_rail && !IsStationTileBlocked(tile); + if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--; DoClearSquare(tile); DeleteNewGRFInspectWindow(GSF_STATIONS, tile); if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt); + DirtyCompanyInfrastructureWindows(owner); st->rect.AfterRemoveTile(st, tile); AddTrackToSignalBuffer(tile, track, owner); @@ -1554,6 +1564,7 @@ CommandCost RemoveRailStation(T *st, DoCommandFlag flags) v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } + if (!IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--; DoClearSquare(tile); DeleteNewGRFInspectWindow(GSF_STATIONS, tile); AddTrackToSignalBuffer(tile, track, owner); @@ -1574,6 +1585,7 @@ CommandCost RemoveRailStation(T *st, DoCommandFlag flags) st->speclist = NULL; st->cached_anim_triggers = 0; + DirtyCompanyInfrastructureWindows(st->owner); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS); st->UpdateVirtCoord(); DeleteStationIfEmpty(st); @@ -3500,6 +3512,18 @@ static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_o if (!IsTileOwner(tile, old_owner)) return; if (new_owner != INVALID_OWNER) { + /* Update company infrastructure counts. Only do it here + * if the new owner is valid as otherwise the clear + * command will do it for us. No need to dirty windows + * here, we'll redraw the whole screen anyway.*/ + Company *old_company = Company::Get(old_owner); + Company *new_company = Company::Get(new_owner); + + if ((IsRailWaypoint(tile) || IsRailStation(tile)) && !IsStationTileBlocked(tile)) { + old_company->infrastructure.rail[GetRailType(tile)]--; + new_company->infrastructure.rail[GetRailType(tile)]++; + } + /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */ SetTileOwner(tile, new_owner); InvalidateWindowClassesData(WC_STATION_LIST, 0); diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index ce5470317f..dbc24fa581 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -40,6 +40,7 @@ #include "newgrf_railtype.h" #include "object_base.h" #include "water.h" +#include "company_gui.h" #include "table/sprites.h" #include "table/strings.h" @@ -430,8 +431,11 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { DiagDirection dir = AxisToDiagDir(direction); + Company *c = Company::GetIfValid(owner); switch (transport_type) { case TRANSPORT_RAIL: + /* Add to company infrastructure count if building a new bridge. */ + if (!IsBridgeTile(tile_start) && c != NULL) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype); MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype); SetTunnelBridgeReservation(tile_start, pbs_reservation); @@ -457,6 +461,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u for (TileIndex tile = tile_start; tile <= tile_end; tile += delta) { MarkTileDirtyByTile(tile); } + DirtyCompanyInfrastructureWindows(owner); } if ((flags & DC_EXEC) && transport_type == TRANSPORT_RAIL) { @@ -626,7 +631,10 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, } if (flags & DC_EXEC) { + Company *c = Company::GetIfValid(_current_company); + uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; if (transport_type == TRANSPORT_RAIL) { + if (!IsTunnelTile(start_tile) && c != NULL) c->infrastructure.rail[railtype] += num_pieces; MakeRailTunnel(start_tile, _current_company, direction, railtype); MakeRailTunnel(end_tile, _current_company, ReverseDiagDir(direction), railtype); AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_company); @@ -635,6 +643,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, MakeRoadTunnel(start_tile, _current_company, direction, rts); MakeRoadTunnel(end_tile, _current_company, ReverseDiagDir(direction), rts); } + DirtyCompanyInfrastructureWindows(_current_company); } return cost; @@ -720,6 +729,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags); } + uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles. + if (flags & DC_EXEC) { if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { /* We first need to request values before calling DoClearSquare */ @@ -733,6 +744,11 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) if (v != NULL) FreeTrainTrackReservation(v); } + if (Company::IsValidID(owner)) { + Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; + DirtyCompanyInfrastructureWindows(owner); + } + DoClearSquare(tile); DoClearSquare(endtile); @@ -749,7 +765,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) DoClearSquare(endtile); } } - return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * (GetTunnelBridgeLength(tile, endtile) + 2)); + return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len); } @@ -789,6 +805,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) } Money base_cost = (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) ? _price[PR_CLEAR_BRIDGE] : _price[PR_CLEAR_AQUEDUCT]; + uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles. if (flags & DC_EXEC) { /* read this value before actual removal of bridge */ @@ -802,6 +819,12 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) if (v != NULL) FreeTrainTrackReservation(v); } + /* Update company infrastructure counts. */ + if (rail) { + if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; + } + DirtyCompanyInfrastructureWindows(owner); + DoClearSquare(tile); DoClearSquare(endtile); for (TileIndex c = tile + delta; c != endtile; c += delta) { @@ -827,7 +850,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) } } - return CommandCost(EXPENSES_CONSTRUCTION, (GetTunnelBridgeLength(tile, endtile) + 2) * base_cost); + return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost); } /** @@ -1489,6 +1512,11 @@ static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner) { + TileIndex other_end = GetOtherTunnelBridgeEnd(tile); + /* Set number of pieces to zero if it's the southern tile as we + * don't want to update the infrastructure counts twice. */ + uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0; + for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { /* Update all roadtypes, no matter if they are present */ if (GetRoadOwner(tile, rt) == old_owner) { @@ -1498,10 +1526,19 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner if (!IsTileOwner(tile, old_owner)) return; + /* Update company infrastructure counts for rail and water as well. + * No need to dirty windows here, we'll redraw the whole screen anyway. */ + TransportType tt = GetTunnelBridgeTransportType(tile); + Company *old = Company::Get(old_owner); + if (tt == TRANSPORT_RAIL) { + old->infrastructure.rail[GetRailType(tile)] -= num_pieces; + if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces; + } + if (new_owner != INVALID_OWNER) { SetTileOwner(tile, new_owner); } else { - if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { + if (tt == TRANSPORT_RAIL) { /* Since all of our vehicles have been removed, it is safe to remove the rail * bridge / tunnel. */ CommandCost ret = DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);