changeset 18656:c107e4bb6187 draft

(svn r23504) -Feature: Aircraft range.
author michi_cc <michi_cc@openttd.org>
date Tue, 13 Dec 2011 00:43:35 +0000
parents 327afa314a42
children 599d7cf176cf
files src/aircraft.h src/aircraft_cmd.cpp src/build_vehicle_gui.cpp src/engine.cpp src/engine_base.h src/engine_gui.cpp src/engine_type.h src/lang/english.txt src/newgrf.cpp src/newgrf_properties.h src/order_base.h src/order_cmd.cpp src/saveload/saveload.cpp src/saveload/vehicle_sl.cpp src/table/engines.h src/vehicle_cmd.cpp src/vehicle_gui.cpp
diffstat 17 files changed, 176 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -25,17 +25,28 @@
 	AIR_ROTOR      = 6  ///< rotor of an helicopter
 };
 
+/** Aircraft flags. */
+enum VehicleAirFlags {
+	VAF_DEST_TOO_FAR = 0, ///< Next destination is too far away.
+};
+
 
 void HandleAircraftEnterHangar(Aircraft *v);
 void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, EngineImageType image_type);
 void UpdateAirplanesOnNewStation(const Station *st);
-void UpdateAircraftCache(Aircraft *v);
+void UpdateAircraftCache(Aircraft *v, bool update_range = false);
 
 void AircraftLeaveHangar(Aircraft *v, Direction exit_dir);
 void AircraftNextAirportPos_and_Order(Aircraft *v);
 void SetAircraftPosition(Aircraft *v, int x, int y, int z);
 int GetAircraftFlyingAltitude(const Aircraft *v);
 
+/** Variables that are cached to improve performance and such. */
+struct AircraftCache {
+	uint32 cached_max_range_sqr;   ///< Cached squared maximum range.
+	uint16 cached_max_range;       ///< Cached maximum range.
+};
+
 /**
  * Aircraft, helicopters, rotors and their shadows belong to this class.
  */
@@ -48,6 +59,9 @@
 	DirectionByte last_direction;
 	byte number_consecutive_turns; ///< Protection to prevent the aircraft of making a lot of turns in order to reach a specific point.
 	byte turn_counter;             ///< Ticks between each turn to prevent > 45 degree turns.
+	byte flags;                    ///< Aircraft flags. @see VehicleAirFlags
+
+	AircraftCache acache;
 
 	/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
 	Aircraft() : SpecializedVehicleBase() {}
@@ -83,6 +97,15 @@
 		 * return (this->subtype == AIR_HELICOPTER) || (this->subtype == AIR_AIRCRAFT); */
 		return this->subtype <= AIR_AIRCRAFT;
 	}
+
+	/**
+	 * Get the range of this aircraft.
+	 * @return Range in tiles or 0 if unlimited range.
+	 */
+	uint16 GetRange() const
+	{
+		return this->acache.cached_max_range;
+	}
 };
 
 /**
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -311,7 +311,7 @@
 
 		v->InvalidateNewGRFCacheOfChain();
 
-		UpdateAircraftCache(v);
+		UpdateAircraftCache(v, true);
 
 		VehicleMove(v, false);
 		VehicleMove(u, false);
@@ -537,8 +537,9 @@
  * Update cached values of an aircraft.
  * Currently caches callback 36 max speed.
  * @param v Vehicle
+ * @param update_range Update the aircraft range.
  */
-void UpdateAircraftCache(Aircraft *v)
+void UpdateAircraftCache(Aircraft *v, bool update_range)
 {
 	uint max_speed = GetVehicleProperty(v, PROP_AIRCRAFT_SPEED, 0);
 	if (max_speed != 0) {
@@ -555,6 +556,13 @@
 	v->vcache.cached_cargo_age_period = GetVehicleProperty(v, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(v->engine_type)->cargo_age_period);
 	Aircraft *u = v->Next(); // Shadow for mail
 	u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period);
+
+	/* Update aircraft range. */
+	if (update_range) {
+		v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range);
+		/* Squared it now so we don't have to do it later all the time. */
+		v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range;
+	}
 }
 
 
@@ -1836,6 +1844,34 @@
 	return FreeTerminal(v, MAX_TERMINALS, apc->num_helipads + MAX_TERMINALS);
 }
 
+/**
+ * Handle the 'dest too far' flag and the corresponding news message for aircraft.
+ * @param v The aircraft.
+ * @param too_far True if the current destination is too far away.
+ */
+static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
+{
+	if (too_far) {
+		if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) {
+			SetBit(v->flags, VAF_DEST_TOO_FAR);
+			SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+			if (v->owner == _local_company) {
+				/* Post a news message. */
+				SetDParam(0, v->index);
+				AddVehicleNewsItem(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, NS_ADVICE, v->index);
+			}
+		}
+		return;
+	}
+
+	if (HasBit(v->flags, VAF_DEST_TOO_FAR)) {
+		/* Not too far anymore, clear flag and message. */
+		ClrBit(v->flags, VAF_DEST_TOO_FAR);
+		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
+		DeleteVehicleNews(v->index, STR_NEWS_AIRCRAFT_DEST_TOO_FAR);
+	}
+}
+
 static bool AircraftEventHandler(Aircraft *v, int loop)
 {
 	v->tick_counter++;
@@ -1854,7 +1890,22 @@
 
 	if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return true;
 
-	AirportGoToNextPosition(v);
+	if (v->state == FLYING) {
+		/* If we are flying, unconditionally clear the 'dest too far' state. */
+		AircraftHandleDestTooFar(v, false);
+	} else if (v->acache.cached_max_range_sqr != 0) {
+		/* Check the distance to the next destination. This code works because the target
+		 * airport is only updated after take off and not on the ground. */
+		Station *cur_st = Station::GetIfValid(v->targetairport);
+		Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : NULL;
+
+		if (cur_st != NULL && cur_st->airport.tile != INVALID_TILE && next_st != NULL && next_st->airport.tile != INVALID_TILE) {
+			uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile);
+			AircraftHandleDestTooFar(v, dist > v->acache.cached_max_range_sqr);
+		}
+	}
+
+	if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) AirportGoToNextPosition(v);
 
 	return true;
 }
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -739,6 +739,13 @@
 	DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
 	y += FONT_HEIGHT_NORMAL;
 
+	uint16 range = e->GetRange();
+	if (range != 0) {
+		SetDParam(0, range);
+		DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE);
+		y += FONT_HEIGHT_NORMAL;
+	}
+
 	return y;
 }
 
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -449,6 +449,20 @@
 }
 
 /**
+ * Get the range of an aircraft type.
+ * @return Range of the aircraft type in tiles or 0 if unlimited range.
+ */
+uint16 Engine::GetRange() const
+{
+	switch (this->type) {
+		case VEH_AIRCRAFT:
+			return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
+
+		default: NOT_REACHED();
+	}
+}
+
+/**
  * Initializes the EngineOverrideManager with the default engines.
  */
 void EngineOverrideManager::ResetToDefaultMapping()
--- a/src/engine_base.h
+++ b/src/engine_base.h
@@ -110,6 +110,7 @@
 	uint GetDisplayWeight() const;
 	uint GetDisplayMaxTractiveEffort() const;
 	Date GetLifeLengthInDays() const;
+	uint16 GetRange() const;
 
 	/**
 	 * Check if the engine is a ground vehicle.
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -170,20 +170,22 @@
 	CargoID cargo = e->GetDefaultCargoType();
 	uint16 mail_capacity;
 	uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
+	uint16 range = e->GetRange();
 
 	SetDParam(0, e->GetCost());
 	SetDParam(1, e->GetDisplayMaxSpeed());
 	SetDParam(2, cargo);
 	SetDParam(3, capacity);
+	SetDParam(7, range);
 
 	if (mail_capacity > 0) {
 		SetDParam(4, CT_MAIL);
 		SetDParam(5, mail_capacity);
 		SetDParam(6, e->GetRunningCost());
-		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST;
+		return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST;
 	} else {
 		SetDParam(4, e->GetRunningCost());
-		return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
+		return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
 	}
 }
 
--- a/src/engine_type.h
+++ b/src/engine_type.h
@@ -105,6 +105,7 @@
 	uint16 max_speed;           ///< Maximum speed (1 unit = 8 mph = 12.8 km-ish/h)
 	byte mail_capacity;         ///< Mail capacity (bags).
 	uint16 passenger_capacity;  ///< Passenger capacity (persons).
+	uint16 max_range;           ///< Maximum range of this aircraft.
 };
 
 /** Information about a road vehicle. */
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -822,6 +822,7 @@
 STR_NEWS_TRAIN_IS_STUCK                                         :{WHITE}{VEHICLE} can't find a path to continue
 STR_NEWS_VEHICLE_IS_LOST                                        :{WHITE}{VEHICLE} is lost
 STR_NEWS_VEHICLE_IS_UNPROFITABLE                                :{WHITE}{VEHICLE}'s profit last year was {CURRENCY_LONG}
+STR_NEWS_AIRCRAFT_DEST_TOO_FAR                                  :{WHITE}{VEHICLE} can't get to the next destination because it is out of range
 
 STR_NEWS_ORDER_REFIT_FAILED                                     :{WHITE}{VEHICLE} stopped because an ordered refit failed
 STR_NEWS_VEHICLE_AUTORENEW_FAILED                               :{WHITE}Autorenew failed on {VEHICLE}{}{STRING}
@@ -2927,6 +2928,7 @@
 STR_PURCHASE_INFO_ALL_TYPES                                     :All cargo types
 STR_PURCHASE_INFO_ALL_BUT                                       :All but {GOLD}
 STR_PURCHASE_INFO_MAX_TE                                        :{BLACK}Max. Tractive Effort: {GOLD}{FORCE}
+STR_PURCHASE_INFO_AIRCRAFT_RANGE                                :{BLACK}Range: {GOLD}{COMMA} tiles
 
 STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP                              :{BLACK}Train vehicle selection list - click on vehicle for information
 STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP                       :{BLACK}Road vehicle selection list - click on vehicle for information
@@ -3047,6 +3049,8 @@
 STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE               :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY}  Power: {POWER}  Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG}
 STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST     :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr
 STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST              :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr
+STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {7:COMMA} tiles{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr
+STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST        :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {7:COMMA} tiles{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr
 
 # Autoreplace window
 STR_REPLACE_VEHICLES_WHITE                                      :{WHITE}Replace {STRING}
@@ -3132,6 +3136,7 @@
 STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL                           :{RED}Stopping, {VELOCITY}
 STR_VEHICLE_STATUS_TRAIN_NO_POWER                               :{RED}No power
 STR_VEHICLE_STATUS_TRAIN_STUCK                                  :{ORANGE}Waiting for free path
+STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR                             :{ORANGE}Too far to next destination
 
 STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL                      :{LTBLUE}Heading for {STATION}, {VELOCITY}
 STR_VEHICLE_STATUS_NO_ORDERS_VEL                                :{LTBLUE}No orders, {VELOCITY}
@@ -3160,6 +3165,7 @@
 STR_VEHICLE_INFO_AGE_RED                                        :{RED}{COMMA} year{P "" s} ({COMMA})
 
 STR_VEHICLE_INFO_MAX_SPEED                                      :{BLACK}Max. speed: {LTBLUE}{VELOCITY}
+STR_VEHICLE_INFO_MAX_SPEED_RANGE                                :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Range: {LTBLUE}{COMMA} tiles
 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED                         :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY}
 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE                  :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE}
 
@@ -3883,6 +3889,7 @@
 STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST                         :{WHITE}Can't stop sharing order list...
 STR_ERROR_CAN_T_COPY_ORDER_LIST                                 :{WHITE}Can't copy order list...
 STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION                     :{WHITE}... too far from previous destination
+STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE                             :{WHITE}... aircraft has not enough range
 
 # Timetable related errors
 STR_ERROR_CAN_T_TIMETABLE_VEHICLE                               :{WHITE}Can't timetable vehicle...
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -1646,6 +1646,10 @@
 				break;
 			}
 
+			case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range
+				avi->max_range = buf->ReadWord();
+				break;
+
 			default:
 				ret = CommonVehicleChangeInfo(ei, prop, buf);
 				break;
--- a/src/newgrf_properties.h
+++ b/src/newgrf_properties.h
@@ -53,6 +53,7 @@
 	PROP_AIRCRAFT_PASSENGER_CAPACITY            = 0x0F, ///< Passenger Capacity
 	PROP_AIRCRAFT_MAIL_CAPACITY                 = 0x11, ///< Mail Capacity
 	PROP_AIRCRAFT_CARGO_AGE_PERIOD              = 0x1C, ///< Number of ticks before carried cargo is aged
+	PROP_AIRCRAFT_RANGE                         = 0x1F, ///< Aircraft range
 };
 
 #endif /* NEWGRF_PROPERTIES_H */
--- a/src/order_base.h
+++ b/src/order_base.h
@@ -166,7 +166,7 @@
 	inline void SetConditionValue(uint16 value) { SB(this->dest, 0, 11, value); }
 
 	bool ShouldStopAtStation(const Vehicle *v, StationID station) const;
-	TileIndex GetLocation(const Vehicle *v) const;
+	TileIndex GetLocation(const Vehicle *v, bool airport = false) const;
 
 	/** Checks if this order has travel_time and if needed wait_time set. */
 	inline bool IsCompletelyTimetabled() const
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -559,14 +559,16 @@
 /**
  * Returns a tile somewhat representing the order destination (not suitable for pathfinding).
  * @param v The vehicle to get the location for.
+ * @param airport Get the airport tile and not the station location for aircraft.
  * @return destination of order, or INVALID_TILE if none.
  */
-TileIndex Order::GetLocation(const Vehicle *v) const
+TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
 {
 	switch (this->GetType()) {
 		case OT_GOTO_WAYPOINT:
 		case OT_GOTO_STATION:
 		case OT_IMPLICIT:
+			if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
 			return BaseStation::Get(this->GetDestination())->xy;
 
 		case OT_GOTO_DEPOT:
@@ -580,8 +582,6 @@
 
 static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0)
 {
-	assert(v->type == VEH_SHIP);
-
 	if (cur->IsType(OT_CONDITIONAL)) {
 		if (conditional_depth > v->GetNumOrders()) return 0;
 
@@ -592,10 +592,10 @@
 		return max(dist1, dist2);
 	}
 
-	TileIndex prev_tile = prev->GetLocation(v);
-	TileIndex cur_tile = cur->GetLocation(v);
+	TileIndex prev_tile = prev->GetLocation(v, true);
+	TileIndex cur_tile = cur->GetLocation(v, true);
 	if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
-	return DistanceManhattan(prev_tile, cur_tile);
+	return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
 }
 
 /**
@@ -1385,6 +1385,34 @@
 }
 
 /**
+ * Check if an aircraft has enough range for an order list.
+ * @param v Aircraft to check.
+ * @param first First order in the source order list.
+ * @return True if the aircraft has enough range for the orders, false otherwise.
+ */
+bool CheckAircraftOrderDistance(const Aircraft *v, const Order *first)
+{
+	if (first == NULL) return true;
+
+	/* Iterate over all orders to check the distance between all
+	 * 'goto' orders and their respective next order (of any type). */
+	for (const Order *o = first; o != NULL; o = o->next) {
+		switch (o->GetType()) {
+			case OT_GOTO_STATION:
+			case OT_GOTO_DEPOT:
+			case OT_GOTO_WAYPOINT:
+				/* If we don't have a next order, we've reached the end and must check the first order instead. */
+				if (GetOrderDistance(o, o->next != NULL ? o->next : first, v) > v->acache.cached_max_range_sqr) return false;
+				break;
+
+			default: break;
+		}
+	}
+
+	return true;
+}
+
+/**
  * Clone/share/copy an order-list of another vehicle.
  * @param tile unused
  * @param flags operation to perform
@@ -1433,6 +1461,11 @@
 				}
 			}
 
+			/* Check for aircraft range limits. */
+			if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src->GetFirstOrder())) {
+				return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
+			}
+
 			if (src->orders.list == NULL && !OrderList::CanAllocateItem()) {
 				return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
 			}
@@ -1475,6 +1508,11 @@
 				}
 			}
 
+			/* Check for aircraft range limits. */
+			if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src->GetFirstOrder())) {
+				return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE);
+			}
+
 			/* make sure there are orders available */
 			int delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
 			if (!Order::CanAllocateItem(delta) ||
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -231,8 +231,9 @@
  *  164   23290
  *  165   23304
  *  166   23415
+ *  167   23504
  */
-extern const uint16 SAVEGAME_VERSION = 166; ///< Current savegame version of OpenTTD.
+extern const uint16 SAVEGAME_VERSION = 167; ///< Current savegame version of OpenTTD.
 
 SavegameType _savegame_type; ///< type of savegame we are loading
 
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -434,7 +434,7 @@
 						rotor->cur_image = GetRotorImage(Aircraft::From(v), EIT_ON_MAP);
 					}
 
-					UpdateAircraftCache(Aircraft::From(v));
+					UpdateAircraftCache(Aircraft::From(v), true);
 				}
 				break;
 			default: break;
@@ -745,6 +745,7 @@
 		 SLE_CONDVAR(Aircraft, number_consecutive_turns, SLE_UINT8,                 2, SL_MAX_VERSION),
 
 		 SLE_CONDVAR(Aircraft, turn_counter,          SLE_UINT8,                  136, SL_MAX_VERSION),
+		 SLE_CONDVAR(Aircraft, flags,                 SLE_UINT8,                  167, SL_MAX_VERSION),
 
 		SLE_CONDNULL(13,                                                           2, 143), // old reserved space
 
--- a/src/table/engines.h
+++ b/src/table/engines.h
@@ -585,7 +585,7 @@
  * @param h mail_capacity (bags)
  * @param i passenger_capacity (persons)
  */
-#define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, e, f, (g * 128) / 10, h, i }
+#define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, e, f, (g * 128) / 10, h, i, 0 }
 #define H AIR_HELI
 #define P AIR_CTOL
 #define J AIR_CTOL | AIR_FAST
--- a/src/vehicle_cmd.cpp
+++ b/src/vehicle_cmd.cpp
@@ -433,7 +433,7 @@
 			case VEH_AIRCRAFT:
 				v->InvalidateNewGRFCacheOfChain();
 				v->colourmap = PAL_NONE; // invalidate vehicle colour map
-				UpdateAircraftCache(Aircraft::From(v));
+				UpdateAircraftCache(Aircraft::From(v), true);
 				break;
 
 			default: NOT_REACHED();
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -1996,7 +1996,12 @@
 					}
 				} else {
 					SetDParam(0, v->GetDisplayMaxSpeed());
-					string = STR_VEHICLE_INFO_MAX_SPEED;
+					if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0) {
+						SetDParam(1, Aircraft::From(v)->GetRange());
+						string = STR_VEHICLE_INFO_MAX_SPEED_RANGE;
+					} else {
+						string = STR_VEHICLE_INFO_MAX_SPEED;
+					}
 				}
 				DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, string);
 				y += FONT_HEIGHT_NORMAL;
@@ -2477,6 +2482,8 @@
 			}
 		} else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {
 			str = STR_VEHICLE_STATUS_TRAIN_STUCK;
+		} else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) {
+			str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR;
 		} else { // vehicle is in a "normal" state, show current order
 			switch (v->current_order.GetType()) {
 				case OT_GOTO_STATION: {