# HG changeset patch # User rubidium # Date 1266069756 0 # Node ID 6a22379530fe4929fb24f6c72431fbec22146c89 # Parent 92d5f8fd3be28416f4e9d57064ed80339da76c63 (svn r19119) -Fix [FS#3616]: removing towns (in the scenario editor) that had stations/depots refer to them or vehicles were on the town's road could cause a crash diff --git a/src/lang/english.txt b/src/lang/english.txt --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3373,6 +3373,7 @@ STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... there is no more space on the map STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}The town will not build roads. You can enable building of roads via Advanced Settings->Economy->Towns. STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress +STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed # Industry related errors STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries... diff --git a/src/town_gui.cpp b/src/town_gui.cpp --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -34,6 +34,8 @@ #include "townname_func.h" #include "townname_type.h" #include "core/geometry_func.hpp" +#include "station_base.h" +#include "depot_base.h" #include "table/sprites.h" #include "table/strings.h" @@ -457,11 +459,65 @@ break; case TVW_DELETE: // delete town - only available on Scenario editor - delete this->town; + if (this->CanDeleteTown()) { + delete this->town; + } else { + ShowErrorMessage(STR_ERROR_TOWN_CAN_T_DELETE, INVALID_STRING_ID, 0, 0); + } break; } } + /** + * Can we delete the town? + * Or in other words, does anything refer to this town? + * @return true if it's possible + */ + bool CanDeleteTown() const + { + /* Stations refer to towns. */ + const Station *st; + FOR_ALL_STATIONS(st) { + if (st->town == this->town) { + /* Non-oil rig stations are always a problem. */ + if (!(st->facilities & FACIL_AIRPORT) || st->airport_type != AT_OILRIG) return false; + /* We can only automatically delete oil rigs *if* there's no vehicle on them. */ + if (DoCommand(st->airport_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false; + } + } + + /* Depots refer to towns. */ + const Depot *d; + FOR_ALL_DEPOTS(d) { + if (d->town_index == this->town->index) return false; + } + + /* Check all tiles for town ownership. */ + for (TileIndex tile = 0; tile < MapSize(); ++tile) { + switch (GetTileType(tile)) { + case MP_ROAD: + if (HasTownOwnedRoad(tile) && GetTownIndex(tile) == this->town->index) { + /* Can we clear this tile? */ + if (DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false; + } + break; + + case MP_TUNNELBRIDGE: + if (IsTileOwner(tile, OWNER_TOWN) && + ClosestTownFromTile(tile, UINT_MAX) == this->town) { + /* Can we clear this bridge? */ + if (DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false; + } + break; + + default: + break; + } + } + + return true; + } + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) {