diff --git a/src/station.cpp b/src/station.cpp index 7e1f639459..302589b205 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -294,13 +294,11 @@ uint Station::GetCatchmentRadius() const * Determines catchment rectangle of this station * @return clamped catchment rectangle */ -Rect Station::GetCatchmentRect() const +Rect Station::GetCatchmentRectUsingRadius(uint catchment_radius) const { assert(!this->rect.IsEmpty()); /* Compute acceptance rectangle */ - int catchment_radius = this->GetCatchmentRadius(); - Rect ret = { max(this->rect.left - catchment_radius, 0), max(this->rect.top - catchment_radius, 0), diff --git a/src/station_base.h b/src/station_base.h index af4d206ba0..c4743bf88f 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -489,7 +489,11 @@ public: static void RecomputeIndustriesNearForAll(); uint GetCatchmentRadius() const; - Rect GetCatchmentRect() const; + Rect GetCatchmentRectUsingRadius(uint radius) const; + inline Rect GetCatchmentRect() const + { + return GetCatchmentRectUsingRadius(this->GetCatchmentRadius()); + } /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const { diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 70e535e20a..affccab84d 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -53,6 +53,7 @@ #include "linkgraph/linkgraph_base.h" #include "linkgraph/refresh.h" #include "widgets/station_widget.h" +#include "zoning.h" #include "table/strings.h" @@ -1425,6 +1426,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); + ZoningMarkDirtyStationCoverageArea(st); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); @@ -1537,6 +1539,9 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected } if (flags & DC_EXEC) { + bool already_affected = affected_stations.Include(st); + if (!already_affected) ZoningMarkDirtyStationCoverageArea(st); + /* read variables before the station tile is removed */ uint specindex = GetCustomStationSpecIndex(tile); Track track = GetRailStationTrack(tile); @@ -1571,8 +1576,6 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected DeallocateSpecFromStation(st, specindex); - affected_stations.Include(st); - if (v != NULL) { /* Restore station reservation. */ if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true); @@ -1716,6 +1719,9 @@ static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags) } Station *st = Station::GetByTile(tile); + + if (flags & DC_EXEC) ZoningMarkDirtyStationCoverageArea(st); + CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]); if (flags & DC_EXEC) st->RecomputeIndustriesNear(); @@ -1905,6 +1911,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin MarkTileDirtyByTile(cur_tile); } + ZoningMarkDirtyStationCoverageArea(st); } if (st != NULL) { @@ -1975,6 +1982,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) } if (flags & DC_EXEC) { + ZoningMarkDirtyStationCoverageArea(st); if (*primary_stop == cur_stop) { /* removed the first stop in the list */ *primary_stop = cur_stop->next; @@ -2432,6 +2440,7 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); + ZoningMarkDirtyStationCoverageArea(st); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); InvalidateWindowData(WC_STATION_VIEW, st->index, -1); @@ -2463,6 +2472,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) if (cost.Failed()) return cost; if (flags & DC_EXEC) { + ZoningMarkDirtyStationCoverageArea(st); const AirportSpec *as = st->airport.GetSpec(); /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. * And as for construction, always remove it, even if the setting is not set, in order to avoid the @@ -2654,6 +2664,7 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); + ZoningMarkDirtyStationCoverageArea(st); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_SHIPS); @@ -2684,6 +2695,7 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) if (ret.Failed()) return ret; if (flags & DC_EXEC) { + ZoningMarkDirtyStationCoverageArea(st); DoClearSquare(tile1); MarkTileDirtyByTile(tile1); MakeWaterKeepingClass(tile2, st->owner); @@ -4023,11 +4035,13 @@ void BuildOilRig(TileIndex tile) st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); + ZoningMarkDirtyStationCoverageArea(st); } void DeleteOilRig(TileIndex tile) { Station *st = Station::GetByTile(tile); + ZoningMarkDirtyStationCoverageArea(st); MakeWaterKeepingClass(tile, OWNER_NONE); diff --git a/src/zoning.h b/src/zoning.h index 9fd33ef76b..af50e856b1 100644 --- a/src/zoning.h +++ b/src/zoning.h @@ -46,4 +46,7 @@ void DrawTileZoning(const TileInfo *ti); void ShowZoningToolbar(); +void ZoningMarkDirtyStationCoverageArea(const Station *st); +inline void ZoningMarkDirtyStationCoverageArea(const Waypoint *st) { } // no-op + #endif /* ZONING_H */ diff --git a/src/zoning_cmd.cpp b/src/zoning_cmd.cpp index d7d308a4c0..b7031ee36d 100644 --- a/src/zoning_cmd.cpp +++ b/src/zoning_cmd.cpp @@ -348,3 +348,35 @@ void DrawTileZoning(const TileInfo *ti) DrawZoningSprites(SPR_ZONING_INNER_HIGHLIGHT_BASE, TileZoningSpriteEvaluation(ti->tile, _local_company, _zoning.inner), ti); } } + +static uint GetZoningModeDependantStationCoverageRadius(const Station *st, ZoningEvaluationMode ev_mode) +{ + switch (ev_mode) { + case ZEM_STA_CATCH: return st->GetCatchmentRadius(); + case ZEM_BUL_UNSER: return st->GetCatchmentRadius(); + case ZEM_IND_UNSER: return st->GetCatchmentRadius() + 10; // this is to wholly update industries partially within the region + default: return 0; + } +} + +/** + * Mark dirty the coverage area around a station if the current zoning mode depends on station coverage + * + * @param const Station *st + * The station to use + */ +void ZoningMarkDirtyStationCoverageArea(const Station *st) +{ + if (st->rect.IsEmpty()) return; + + uint radius = max(GetZoningModeDependantStationCoverageRadius(st, _zoning.outer), GetZoningModeDependantStationCoverageRadius(st, _zoning.inner)); + + if (radius > 0) { + Rect rect = st->GetCatchmentRectUsingRadius(radius); + for (int x = rect.left; x <= rect.right; x++) { + for (int y = rect.top; y <= rect.bottom; y++) { + MarkTileDirtyByTile(TileXY(x, y)); + } + } + } +}