From def8e7215bdabee99ad49adedb8730ae33b6c47f Mon Sep 17 00:00:00 2001 From: michi_cc Date: Tue, 13 Dec 2011 00:43:35 +0000 Subject: [PATCH] (svn r23504) -Feature: Aircraft range. --- src/aircraft.h | 25 +++++++++++++++- src/aircraft_cmd.cpp | 57 +++++++++++++++++++++++++++++++++++-- src/build_vehicle_gui.cpp | 7 +++++ src/engine.cpp | 14 +++++++++ src/engine_base.h | 1 + src/engine_gui.cpp | 6 ++-- src/engine_type.h | 1 + src/lang/english.txt | 7 +++++ src/newgrf.cpp | 4 +++ src/newgrf_properties.h | 1 + src/order_base.h | 2 +- src/order_cmd.cpp | 50 ++++++++++++++++++++++++++++---- src/saveload/saveload.cpp | 3 +- src/saveload/vehicle_sl.cpp | 3 +- src/table/engines.h | 2 +- src/vehicle_cmd.cpp | 2 +- src/vehicle_gui.cpp | 9 +++++- 17 files changed, 176 insertions(+), 18 deletions(-) diff --git a/src/aircraft.h b/src/aircraft.h index 42463492ca..8ba313cfa2 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 { 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 { * 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 70fb63051e..a0b7349f11 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 d3446f058e..43b1090303 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 c90d13297a..a5ed31fd59 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -448,6 +448,20 @@ Date Engine::GetLifeLengthInDays() const return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * DAYS_IN_LEAP_YEAR; } +/** + * 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. */ diff --git a/src/engine_base.h b/src/engine_base.h index 1c798ccf17..ab4d8252d9 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 9dde1a7e10..7fd02b5ab9 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 a291bce070..d4a5538397 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 e0a079b917..ace581ed2c 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 844d1fdaeb..a37c14b52d 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 090ac1413b..e1240f29ee 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 e2279da812..c724df241e 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 7b7fc8f575..44012a0852 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); } /** @@ -1384,6 +1384,34 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 return CommandCost(); } +/** + * 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 @@ -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 b6eaf662c7..55fabe77bb 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 1e47094eb8..9c8f258000 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 b707879416..102d8d79ce 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 146b816598..4914bcfb35 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 c8918ce755..62617d875c 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: {