changeset 18566:9b9dc36d3eb2 draft

(svn r23411) -Add: Company infrastructure counts for rail.
author michi_cc <michi_cc@openttd.org>
date Sat, 03 Dec 2011 23:40:13 +0000
parents 021a10db1a99
children 1c2e5babf594
files src/economy_type.h src/openttd.cpp src/rail_cmd.cpp src/road_cmd.cpp src/saveload/afterload.cpp src/saveload/company_sl.cpp src/saveload/saveload_internal.h src/station_cmd.cpp src/tunnelbridge_cmd.cpp
diffstat 9 files changed, 255 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/economy_type.h
+++ b/src/economy_type.h
@@ -201,6 +201,11 @@
 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;
 
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -1115,6 +1115,22 @@
  */
 static void CheckCaches()
 {
+	/* Check company infrastructure cache. */
+	SmallVector<CompanyInfrastructure, 4> 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;
--- 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 @@
 
 			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 @@
 					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 @@
 			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 @@
 					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 @@
 					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 @@
 		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 @@
 			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 @@
 			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 @@
 				}
 			}
 		}
+		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 @@
 					}
 				}
 
+				/* 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 @@
 							*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 @@
 			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 @@
 	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);
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -1671,6 +1671,10 @@
 			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);
 			}
 		}
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -2716,6 +2716,7 @@
 	/* Road stops is 'only' updating some caches */
 	AfterLoadRoadStops();
 	AfterLoadLabelMaps();
+	AfterLoadCompanyStats();
 
 	GamelogPrintDebug(1);
 
@@ -2746,6 +2747,8 @@
 	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 */
--- 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 @@
 	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 */
--- a/src/saveload/saveload_internal.h
+++ b/src/saveload/saveload_internal.h
@@ -31,6 +31,7 @@
 void AfterLoadStations();
 void AfterLoadRoadStops();
 void AfterLoadLabelMaps();
+void AfterLoadCompanyStats();
 void UpdateHousesAndTowns();
 
 void UpdateOldAircraft();
--- 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 @@
 
 		numtracks_orig = numtracks;
 
+		Company *c = Company::Get(st->owner);
 		do {
 			TileIndex tile = tile_org;
 			int w = plat_len;
@@ -1235,6 +1237,9 @@
 					}
 				}
 
+				/* 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 @@
 				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 @@
 		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 @@
 			}
 
 			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 @@
 				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 @@
 		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 @@
 	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);
--- 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 @@
 	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 @@
 		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 @@
 	}
 
 	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 @@
 			MakeRoadTunnel(start_tile, _current_company, direction,                 rts);
 			MakeRoadTunnel(end_tile,   _current_company, ReverseDiagDir(direction), rts);
 		}
+		DirtyCompanyInfrastructureWindows(_current_company);
 	}
 
 	return cost;
@@ -720,6 +729,8 @@
 		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 @@
 				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 @@
 			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 @@
 	}
 
 	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 @@
 			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 @@
 		}
 	}
 
-	return CommandCost(EXPENSES_CONSTRUCTION, (GetTunnelBridgeLength(tile, endtile) + 2) * base_cost);
+	return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
 }
 
 /**
@@ -1489,6 +1512,11 @@
 
 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 @@
 
 	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);