changeset 14548:6a22379530fe draft

(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
author rubidium <rubidium@openttd.org>
date Sat, 13 Feb 2010 14:02:36 +0000
parents 92d5f8fd3be2
children 67592123d961
files src/lang/english.txt src/town_gui.cpp
diffstat 2 files changed, 58 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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...
--- 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) {