summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichi_cc <michi_cc@openttd.org>2011-12-13 00:43:35 +0000
committermichi_cc <michi_cc@openttd.org>2011-12-13 00:43:35 +0000
commitdef8e7215bdabee99ad49adedb8730ae33b6c47f (patch)
tree77accd58c6e79e746605fdf851b84720c7600836
parent686f51d810f9fa8303639c979f0ba76f1993ce9b (diff)
downloadopenttd-def8e7215bdabee99ad49adedb8730ae33b6c47f.tar.xz
(svn r23504) -Feature: Aircraft range.
-rw-r--r--src/aircraft.h25
-rw-r--r--src/aircraft_cmd.cpp57
-rw-r--r--src/build_vehicle_gui.cpp7
-rw-r--r--src/engine.cpp14
-rw-r--r--src/engine_base.h1
-rw-r--r--src/engine_gui.cpp6
-rw-r--r--src/engine_type.h1
-rw-r--r--src/lang/english.txt7
-rw-r--r--src/newgrf.cpp4
-rw-r--r--src/newgrf_properties.h1
-rw-r--r--src/order_base.h2
-rw-r--r--src/order_cmd.cpp50
-rw-r--r--src/saveload/saveload.cpp3
-rw-r--r--src/saveload/vehicle_sl.cpp3
-rw-r--r--src/table/engines.h2
-rw-r--r--src/vehicle_cmd.cpp2
-rw-r--r--src/vehicle_gui.cpp9
17 files changed, 176 insertions, 18 deletions
diff --git a/src/aircraft.h b/src/aircraft.h
index 42463492c..8ba313cfa 100644
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -25,17 +25,28 @@ enum AircraftSubType {
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 @@ struct Aircraft : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
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 @@ struct Aircraft : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
* 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;
+ }
};
/**
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
index 70fb63051..a0b7349f1 100644
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -311,7 +311,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *
v->InvalidateNewGRFCacheOfChain();
- UpdateAircraftCache(v);
+ UpdateAircraftCache(v, true);
VehicleMove(v, false);
VehicleMove(u, false);
@@ -537,8 +537,9 @@ static void PlayAircraftSound(const Vehicle *v)
* 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 @@ void UpdateAircraftCache(Aircraft *v)
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 @@ static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc)
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 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
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;
}
diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp
index d3446f058..43b109030 100644
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -739,6 +739,13 @@ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_
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;
}
diff --git a/src/engine.cpp b/src/engine.cpp
index c90d13297..a5ed31fd5 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -449,6 +449,20 @@ Date Engine::GetLifeLengthInDays() const
}
/**
+ * 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()
diff --git a/src/engine_base.h b/src/engine_base.h
index 1c798ccf1..ab4d8252d 100644
--- a/src/engine_base.h
+++ b/src/engine_base.h
@@ -110,6 +110,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
uint GetDisplayWeight() const;
uint GetDisplayMaxTractiveEffort() const;
Date GetLifeLengthInDays() const;
+ uint16 GetRange() const;
/**
* Check if the engine is a ground vehicle.
diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp
index 9dde1a7e1..7fd02b5ab 100644
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -170,20 +170,22 @@ static StringID GetAircraftEngineInfoString(const Engine *e)
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;
}
}
diff --git a/src/engine_type.h b/src/engine_type.h
index a291bce07..d4a553839 100644
--- a/src/engine_type.h
+++ b/src/engine_type.h
@@ -105,6 +105,7 @@ struct AircraftVehicleInfo {
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. */
diff --git a/src/lang/english.txt b/src/lang/english.txt
index e0a079b91..ace581ed2 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -822,6 +822,7 @@ STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE
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_REFITTABLE_TO :{BLACK}Refittab
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 :{BLACK}Cost: {C
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_STOPPED :{RED}Stopped
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 :{COMMA} year{P
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_SHARE_ORDER_LIST :{WHITE}Can't sh
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...
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 844d1fdae..a37c14b52 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -1646,6 +1646,10 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int
break;
}
+ case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range
+ avi->max_range = buf->ReadWord();
+ break;
+
default:
ret = CommonVehicleChangeInfo(ei, prop, buf);
break;
diff --git a/src/newgrf_properties.h b/src/newgrf_properties.h
index 090ac1413..e1240f29e 100644
--- a/src/newgrf_properties.h
+++ b/src/newgrf_properties.h
@@ -53,6 +53,7 @@ enum PropertyID {
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 */
diff --git a/src/order_base.h b/src/order_base.h
index e2279da81..c724df241 100644
--- a/src/order_base.h
+++ b/src/order_base.h
@@ -166,7 +166,7 @@ public:
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
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index 7b7fc8f57..44012a085 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -559,14 +559,16 @@ static void DeleteOrderWarnings(const Vehicle *v)
/**
* 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 @@ TileIndex Order::GetLocation(const Vehicle *v) const
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 @@ static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle
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 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
/**
+ * 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 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
}
}
+ /* 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 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
}
}
+ /* 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) ||
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index b6eaf662c..55fabe77b 100644
--- 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
diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp
index 1e47094eb..9c8f25800 100644
--- a/src/saveload/vehicle_sl.cpp
+++ b/src/saveload/vehicle_sl.cpp
@@ -434,7 +434,7 @@ void AfterLoadVehicles(bool part_of_load)
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 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
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
diff --git a/src/table/engines.h b/src/table/engines.h
index b70787941..102d8d79c 100644
--- a/src/table/engines.h
+++ b/src/table/engines.h
@@ -585,7 +585,7 @@ static const ShipVehicleInfo _orig_ship_vehicle_info[] = {
* @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
diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp
index 146b81659..4914bcfb3 100644
--- a/src/vehicle_cmd.cpp
+++ b/src/vehicle_cmd.cpp
@@ -433,7 +433,7 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
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();
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index c8918ce75..62617d875 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -1996,7 +1996,12 @@ struct VehicleDetailsWindow : Window {
}
} 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 @@ public:
}
} 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: {