changeset 6394:d1cf5ac55918 draft

(svn r9524) -Fix(FS#640,r8755): Implemented a "dummy" State Machine for stations who got their airport removed while there were still aircraft within the State Machine (and thus caused asserts)
author celestar <celestar@openttd.org>
date Thu, 29 Mar 2007 13:52:34 +0000
parents ffd35446c110
children f32f6fe9cbac
files src/aircraft_cmd.cpp src/airport.cpp src/airport.h src/airport_movement.h src/station.h src/station_cmd.cpp
diffstat 6 files changed, 100 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -944,6 +944,42 @@
 }
 
 /**
+ * Find the entry point to an airport depending on direction which
+ * the airport is being approached from. Each airport can have up to
+ * four entry points for its approach system so that approaching
+ * aircraft do not fly through each other or are forced to do 180
+ * degree turns during the approach. The arrivals are grouped into
+ * four sectors dependent on the DiagDirection from which the airport
+ * is approached.
+ *
+ * @param v   The vehicle that is approaching the airport
+ * @param apc The Airport Class being approached.
+ * @returns   The index of the entry point
+ */
+static byte AircraftGetEntryPoint(const Vehicle *v, const AirportFTAClass *apc)
+{
+	assert(v != NULL);
+	assert(apc != NULL);
+
+	const Station *st = GetStation(v->u.air.targetairport);
+	/* Make sure we don't go to 0,0 if the airport has been removed. */
+	TileIndex tile = (st->airport_tile != 0) ? st->airport_tile : st->xy;
+
+	int delta_x = v->x_pos - TileX(tile) * TILE_SIZE;
+	int delta_y = v->y_pos - TileY(tile) * TILE_SIZE;
+
+	DiagDirection dir;
+	if (abs(delta_y) < abs(delta_x)) {
+		/* We are northeast or southwest of the airport */
+		dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW;
+	} else {
+		/* We are northwest or southeast of the airport */
+		dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE;
+	}
+	return apc->entry_points[dir];
+}
+
+/**
  * Controls the movement of an aircraft. This function actually moves the vehicle
  * on the map and takes care of minor things like sound playback.
  * @todo    De-mystify the cur_speed values for helicopter rotors.
@@ -954,17 +990,24 @@
 {
 	int count;
 	const Station *st = GetStation(v->u.air.targetairport);
+	const AirportFTAClass *afc = st->Airport();
+	const AirportMovingData *amd;
 
 	/* prevent going to 0,0 if airport is deleted. */
 	TileIndex tile = st->airport_tile;
-	if (tile == 0) tile = st->xy;
+	if (tile == 0) {
+		tile = st->xy;
+
+		/* Jump into our "holding pattern" state machine if possible */
+	if (v->u.air.pos >= afc->nofelements) v->u.air.pos = v->u.air.previous_pos = AircraftGetEntryPoint(v, afc);
+	}
+
+	/*  get airport moving data */
+	amd = afc->MovingData(v->u.air.pos);
+
 	int x = TileX(tile) * TILE_SIZE;
 	int y = TileY(tile) * TILE_SIZE;
 
-	/*  get airport moving data */
-	const AirportFTAClass *afc = st->Airport();
-	const AirportMovingData *amd = afc->MovingData(v->u.air.pos);
-
 	/* Helicopter raise */
 	if (amd->flag & AMED_HELI_RAISE) {
 		Vehicle *u = v->next->next;
@@ -1470,42 +1513,6 @@
 	MaybeCrashAirplane(v);
 }
 
-/**
- * Find the entry point to an airport depending on direction which
- * the airport is being approached from. Each airport can have up to
- * four entry points for its approach system so that approaching
- * aircraft do not fly through each other or are forced to do 180
- * degree turns during the approach. The arrivals are grouped into
- * four sectors dependent on the DiagDirection from which the airport
- * is approached.
- *
- * @param v   The vehicle that is approaching the airport
- * @param apc The Airport Class being approached.
- * @returns   The index of the entry point
- */
-static byte AircraftGetEntryPoint(const Vehicle *v, const AirportFTAClass *apc)
-{
-	assert(v != NULL);
-	assert(apc != NULL);
-
-	const Station *st = GetStation(v->u.air.targetairport);
-	/* Make sure we don't go to 0,0 if the airport has been removed. */
-	TileIndex tile = (st->airport_tile != 0) ? st->airport_tile : st->xy;
-
-	int delta_x = v->x_pos - TileX(tile) * TILE_SIZE;
-	int delta_y = v->y_pos - TileY(tile) * TILE_SIZE;
-
-	DiagDirection dir;
-	if (abs(delta_y) < abs(delta_x)) {
-		/* We are northeast or southwest of the airport */
-		dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW;
-	} else {
-		/* We are northwest or southeast of the airport */
-		dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE;
-	}
-	return apc->entry_points[dir];
-}
-
 
 /** set the right pos when heading to other airports after takeoff */
 static void AircraftNextAirportPos_and_Order(Vehicle *v)
--- a/src/airport.cpp
+++ b/src/airport.cpp
@@ -20,6 +20,7 @@
  * - false: give a summarized report which only shows current and next position */
 //#define DEBUG_AIRPORT false
 
+static AirportFTAClass *DummyAirport;
 static AirportFTAClass *CountryAirport;
 static AirportFTAClass *CityAirport;
 static AirportFTAClass *Oilrig;
@@ -34,6 +35,20 @@
 
 void InitializeAirports()
 {
+	DummyAirport = new AirportFTAClass(
+		_airport_moving_data_dummy,
+		NULL,
+		NULL,
+		_airport_entries_dummy,
+		AirportFTAClass::ALL,
+		_airport_fta_dummy,
+		NULL,
+		0,
+		0, 0,
+		0,
+		0
+	);
+
 	CountryAirport = new AirportFTAClass(
 		_airport_moving_data_country,
 		_airport_terminal_country,
@@ -463,6 +478,7 @@
 		case AT_HELIDEPOT:     return HeliDepot;
 		case AT_INTERCON:      return IntercontinentalAirport;
 		case AT_HELISTATION:   return HeliStation;
+		case AT_DUMMY:         return DummyAirport;
 	}
 }
 
--- a/src/airport.h
+++ b/src/airport.h
@@ -14,16 +14,17 @@
 
 // Airport types
 enum {
-	AT_SMALL         =  0,
-	AT_LARGE         =  1,
-	AT_HELIPORT      =  2,
-	AT_METROPOLITAN  =  3,
-	AT_INTERNATIONAL =  4,
-	AT_COMMUTER      =  5,
-	AT_HELIDEPOT     =  6,
-	AT_INTERCON      =  7,
-	AT_HELISTATION   =  8,
-	AT_OILRIG        = 15
+	AT_SMALL         =   0,
+	AT_LARGE         =   1,
+	AT_HELIPORT      =   2,
+	AT_METROPOLITAN  =   3,
+	AT_INTERNATIONAL =   4,
+	AT_COMMUTER      =   5,
+	AT_HELIDEPOT     =   6,
+	AT_INTERCON      =   7,
+	AT_HELISTATION   =   8,
+	AT_OILRIG        =  15,
+	AT_DUMMY         = 255
 };
 
 
--- a/src/airport_movement.h
+++ b/src/airport_movement.h
@@ -17,6 +17,14 @@
 
 ///////////////////////////////////////////////////////////////////////
 /////*********Movement Positions on Airports********************///////
+
+static const AirportMovingData _airport_moving_data_dummy[] = {
+	{    0,    0, AMED_NOSPDCLAMP | AMED_SLOWTURN,     {DIR_N} },
+	{    0,   96, AMED_NOSPDCLAMP | AMED_SLOWTURN,     {DIR_N} },
+	{   96,   96, AMED_NOSPDCLAMP | AMED_SLOWTURN,     {DIR_N} },
+	{   96,    0, AMED_NOSPDCLAMP | AMED_SLOWTURN,     {DIR_N} },
+};
+
 // Country Airfield (small) 4x3
 static const AirportMovingData _airport_moving_data_country[22] = {
 	{   53,    3, AMED_EXACTPOS,                   {DIR_SE} }, // 00 In Hangar
@@ -376,6 +384,15 @@
 
 ///////////////////////////////////////////////////////////////////////
 /////**********Movement Machine on Airports*********************///////
+static const byte _airport_entries_dummy[] = {0, 1, 2, 3};
+static const AirportFTAbuildup _airport_fta_dummy[] = {
+	{ 0, 0, 0, 3},
+	{ 1, 0, 0, 0},
+	{ 2, 0, 0, 1},
+	{ 3, 0, 0, 2},
+	{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
+};
+
 /* First element of terminals array tells us how many depots there are (to know size of array)
  * this may be changed later when airports are moved to external file  */
 static const TileIndexDiffC _airport_depots_country[] = {{3, 0}};
--- a/src/station.h
+++ b/src/station.h
@@ -118,7 +118,7 @@
 
 		const AirportFTAClass *Airport() const
 		{
-			assert(airport_tile != 0);
+			if (airport_tile == 0) return GetAirport(AT_DUMMY);
 			return GetAirport(airport_type);
 		}
 
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -1600,6 +1600,13 @@
 
 	int32 cost = w * h * _price.remove_airport;
 
+	Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (!(v->type == VEH_AIRCRAFT && IsNormalAircraft(v))) continue;
+
+		if (v->u.air.targetairport == st->index && v->u.air.state != FLYING) return CMD_ERROR;
+	}
+
 	BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
 		if (!EnsureNoVehicle(tile_cur)) return CMD_ERROR;