Index: src/aircraft.h =================================================================== --- src/aircraft.h (revision 27794) +++ src/aircraft.h (working copy) @@ -73,6 +73,7 @@ */ struct Aircraft FINAL : public SpecializedVehicle { uint16 crashed_counter; ///< Timer for handling crash animations. + uint64 flight_counter; ///< Timer for handling flight duration since last takeoff. byte pos; ///< Next desired position of the aircraft. byte previous_pos; ///< Previous desired position of the aircraft. StationID targetairport; ///< Airport to go to next. Index: src/aircraft_cmd.cpp =================================================================== --- src/aircraft_cmd.cpp (revision 27794) +++ src/aircraft_cmd.cpp (working copy) @@ -37,6 +37,7 @@ #include "core/backup_type.hpp" #include "zoom_func.h" #include "disaster_vehicle.h" +#include "settings_internal.h" #include "table/strings.h" @@ -1619,6 +1620,7 @@ static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc) { v->state = ENDLANDING; + v->flight_counter = 0; AircraftLandAirplane(v); // maybe crash airplane /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */ @@ -1632,6 +1634,7 @@ static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *apc) { v->state = HELIENDLANDING; + v->flight_counter = 0; v->UpdateDeltaXY(INVALID_DIR); } @@ -2034,6 +2037,20 @@ return true; } +static uint FlightTimeDelta() +{ + uint speed_factor_max = GetSettingFromName("vehicle.plane_speed", &speed_factor_max)->desc.max; + uint speed_factor_min = GetSettingFromName("vehicle.plane_speed", &speed_factor_min)->desc.min; + + uint m = 1; + for (uint i = speed_factor_min; i <= speed_factor_max; i++) { + uint l = LeastCommonMultiple(i, speed_factor_max); + m = l > m ? l : m; + } + + return m / _settings_game.vehicle.plane_speed; +} + bool Aircraft::Tick() { if (!this->IsNormalAircraft()) return true; @@ -2046,6 +2063,8 @@ this->current_order_time++; + if (this->state == FLYING) this->flight_counter += FlightTimeDelta(); + for (uint i = 0; i != 2; i++) { /* stop if the aircraft was deleted */ if (!AircraftEventHandler(this, i)) return false; Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 27794) +++ src/lang/english.txt (working copy) @@ -286,6 +286,7 @@ STR_SORT_BY_NUMBER :Number STR_SORT_BY_PROFIT_LAST_YEAR :Profit last year STR_SORT_BY_PROFIT_THIS_YEAR :Profit this year +STR_SORT_BY_PROFIT_LIFETIME :Lifetime profit STR_SORT_BY_AGE :Age STR_SORT_BY_RELIABILITY :Reliability STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Total capacity per cargo type @@ -3662,6 +3663,7 @@ 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} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) +STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_LIFETIME :{STRING2} (lifetime: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} Index: src/saveload/afterload.cpp =================================================================== --- src/saveload/afterload.cpp (revision 27794) +++ src/saveload/afterload.cpp (working copy) @@ -2977,6 +2977,12 @@ FOR_ALL_STATIONS(st) UpdateStationAcceptance(st, false); } + /* Set lifetime vehicle profit to 0 if save game before 197 */ + if (IsSavegameVersionBefore(197)) { + Vehicle *v; + FOR_ALL_VEHICLES(v) v->profit_lifetime = 0; + } + /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); Index: src/saveload/saveload.cpp =================================================================== --- src/saveload/saveload.cpp (revision 27794) +++ src/saveload/saveload.cpp (working copy) @@ -264,8 +264,9 @@ * 194 26881 1.5.x, 1.6.0 * 195 27572 1.6.x * 196 27778 1.7.x + * 197 */ -extern const uint16 SAVEGAME_VERSION = 196; ///< Current savegame version of OpenTTD. +extern const uint16 SAVEGAME_VERSION = 197; ///< Current savegame version of OpenTTD. SavegameType _savegame_type; ///< type of savegame we are loading FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop. Index: src/saveload/vehicle_sl.cpp =================================================================== --- src/saveload/vehicle_sl.cpp (revision 27794) +++ src/saveload/vehicle_sl.cpp (working copy) @@ -683,6 +683,7 @@ SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, 65, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, 65, SL_MAX_VERSION), + SLE_CONDVAR(Vehicle, profit_lifetime, SLE_INT64, 197, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, 51, 64), SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, 51, 67), Index: src/vehicle.cpp =================================================================== --- src/vehicle.cpp (revision 27794) +++ src/vehicle.cpp (working copy) @@ -1237,6 +1237,10 @@ * >2 - vehicle is counting down to the actual breakdown event */ switch (this->breakdown_ctr) { case 0: + if (this->type == VEH_AIRCRAFT) { + Aircraft *a = Aircraft::From(this); + if (false && a->flight_counter < 74 * 20 * 4 && !(this->vehstatus & VS_AIRCRAFT_BROKEN)) this->breakdown_ctr = 2; + } return false; case 2: @@ -2704,6 +2708,7 @@ } v->profit_last_year = v->profit_this_year; + v->profit_lifetime += v->profit_this_year; v->profit_this_year = 0; SetWindowDirty(WC_VEHICLE_DETAILS, v->index); } Index: src/vehicle_base.h =================================================================== --- src/vehicle_base.h (revision 27794) +++ src/vehicle_base.h (working copy) @@ -238,6 +238,7 @@ Money profit_this_year; ///< Profit this year << 8, low 8 bits are fract Money profit_last_year; ///< Profit last year << 8, low 8 bits are fract + Money profit_lifetime; ///< Profit lifetime << 8, low 8 bits are fract Money value; ///< Value of the vehicle CargoPayment *cargo_payment; ///< The cargo payment we're currently in @@ -571,6 +572,12 @@ */ Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); } + /** + * Gets the lifetime profit of vehicle. It can be sent into SetDParam for string processing. + * @return the vehicle's lifetime profit + */ + Money GetDisplayProfitLifetime() const { return ((this->profit_lifetime + this->profit_this_year) >> 8); } + void SetNext(Vehicle *next); /** Index: src/vehicle_gui.cpp =================================================================== --- src/vehicle_gui.cpp (revision 27794) +++ src/vehicle_gui.cpp (working copy) @@ -48,6 +48,7 @@ static GUIVehicleList::SortFunction VehicleNameSorter; static GUIVehicleList::SortFunction VehicleAgeSorter; static GUIVehicleList::SortFunction VehicleProfitThisYearSorter; +static GUIVehicleList::SortFunction VehicleProfitLifetimeSorter; static GUIVehicleList::SortFunction VehicleProfitLastYearSorter; static GUIVehicleList::SortFunction VehicleCargoSorter; static GUIVehicleList::SortFunction VehicleReliabilitySorter; @@ -64,6 +65,7 @@ &VehicleAgeSorter, &VehicleProfitThisYearSorter, &VehicleProfitLastYearSorter, + &VehicleProfitLifetimeSorter, &VehicleCargoSorter, &VehicleReliabilitySorter, &VehicleMaxSpeedSorter, @@ -80,6 +82,7 @@ STR_SORT_BY_AGE, STR_SORT_BY_PROFIT_THIS_YEAR, STR_SORT_BY_PROFIT_LAST_YEAR, + STR_SORT_BY_PROFIT_LIFETIME, STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE, STR_SORT_BY_RELIABILITY, STR_SORT_BY_MAX_SPEED, @@ -1132,6 +1135,13 @@ return (r != 0) ? r : VehicleNumberSorter(a, b); } +/** Sort vehicles by lifetime profit */ +static int CDECL VehicleProfitLifetimeSorter(const Vehicle * const *a, const Vehicle * const *b) +{ + int r = ClampToI32((*a)->GetDisplayProfitLifetime() - (*b)->GetDisplayProfitLifetime()); + return (r != 0) ? r : VehicleNumberSorter(a, b); +} + /** Sort vehicles by their cargo */ static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b) { @@ -1939,12 +1949,14 @@ STR_VEHICLE_INFO_MAX_SPEED, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE, - STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS }; for (uint i = 0; i < lengthof(info_strings); i++) { dim = maxdim(dim, GetStringBoundingBox(info_strings[i])); } + SetDParam(0, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); + for (uint i = 1; i < 4; i++) SetDParamMaxValue(i, 1 << 24); + dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_LIFETIME)); SetDParam(0, STR_VEHICLE_INFO_AGE); dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_AGE_RUNNING_COST_YR)); size->width = dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; @@ -2080,9 +2092,11 @@ y += FONT_HEIGHT_NORMAL; /* Draw profit */ - SetDParam(0, v->GetDisplayProfitThisYear()); - SetDParam(1, v->GetDisplayProfitLastYear()); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); + SetDParam(0, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); + SetDParam(1, v->GetDisplayProfitThisYear()); + SetDParam(2, v->GetDisplayProfitLastYear()); + SetDParam(3, v->GetDisplayProfitLifetime()); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_LIFETIME); y += FONT_HEIGHT_NORMAL; /* Draw breakdown & reliability */