diff --git a/src/station.cpp b/src/station.cpp index 456262dea4..773e45e100 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -291,13 +291,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 eb90c29ab5..65b4ea9b07 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" @@ -1383,6 +1384,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); @@ -1495,6 +1497,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); @@ -1529,8 +1534,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); @@ -1674,6 +1677,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(); @@ -1863,6 +1869,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin MarkTileDirtyByTile(cur_tile); } + ZoningMarkDirtyStationCoverageArea(st); } if (st != NULL) { @@ -1933,6 +1940,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; @@ -2299,6 +2307,7 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint st->UpdateVirtCoord(); 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); @@ -2337,6 +2346,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) } 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 @@ -2539,6 +2549,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); @@ -2569,6 +2580,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); @@ -3903,11 +3915,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 bfea293342..995e762e54 100644 --- a/src/zoning.h +++ b/src/zoning.h @@ -45,4 +45,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 5f9240d76c..99a9640c4a 100644 --- a/src/zoning_cmd.cpp +++ b/src/zoning_cmd.cpp @@ -330,3 +330,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)); + } + } + } +}