From 59dbcdb5ba0ada6a5a960a02d32d4aa57bc94231 Mon Sep 17 00:00:00 2001 From: Henry Wilson Date: Mon, 31 Oct 2022 19:47:25 +0000 Subject: [PATCH] Feature: Display power-to-weight ratio in ground vehicle details GUI --- src/lang/english.txt | 11 +++++++++++ src/roadveh.h | 6 ++++++ src/roadveh_cmd.cpp | 13 +++++++++++++ src/strings.cpp | 28 +++++++++++++++++++++++++++- src/table/control_codes.h | 1 + src/table/strgen_tables.h | 1 + src/train.h | 6 ++++++ src/train_cmd.cpp | 17 +++++++++++++++++ src/vehicle.cpp | 26 ++++++++++++++++++++++++++ src/vehicle_base.h | 12 ++++++++++++ src/vehicle_gui.cpp | 7 ++++++- 11 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 34ea3b6775..f8ef8cb4fe 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -200,6 +200,16 @@ STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}hp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}hp STR_UNITS_POWER_SI :{COMMA}{NBSP}kW +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}hp/t +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}hp/t +STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_SI :{DECIMAL}{NBSP}hp/Mg +STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}hp/t +STR_UNITS_POWER_METRIC_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}hp/t +STR_UNITS_POWER_METRIC_TO_WEIGHT_SI :{DECIMAL}{NBSP}hp/Mg +STR_UNITS_POWER_SI_TO_WEIGHT_IMPERIAL :{DECIMAL}{NBSP}kW/t +STR_UNITS_POWER_SI_TO_WEIGHT_METRIC :{DECIMAL}{NBSP}kW/t +STR_UNITS_POWER_SI_TO_WEIGHT_SI :{DECIMAL}{NBSP}W/kg + STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg @@ -4201,6 +4211,7 @@ STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Weight: 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_MIN_PERFORMANCE :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) {BLACK}Min. performance: {LTBLUE}{POWER_TO_WEIGHT} 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} diff --git a/src/roadveh.h b/src/roadveh.h index e1406cb7cb..8dac7b5d51 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -189,6 +189,12 @@ protected: // These functions should not be called outside acceleration code. return weight; } + /** + * Calculates the weight value that this vehicle will have when fully loaded with its current cargo. + * @return Weight value in tonnes. + */ + uint16 GetMaxWeight() const override; + /** * Allows to know the tractive effort value that this vehicle will use. * @return Tractive effort value from the engine. diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 35558bd58d..ae09fda403 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1753,3 +1753,16 @@ Trackdir RoadVehicle::GetVehicleTrackdir() const * otherwise transform it into a valid track direction */ return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state); } + +uint16 RoadVehicle::GetMaxWeight() const +{ + uint16 weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnits(this->GetEngine()->DetermineCapacity(this)); + + /* Vehicle weight is not added for articulated parts. */ + if (!this->IsArticulatedPart()) { + /* Road vehicle weight is in units of 1/4 t. */ + weight += GetVehicleProperty(this, PROP_ROADVEH_WEIGHT, RoadVehInfo(this->engine_type)->weight) / 4; + } + + return weight; +} diff --git a/src/strings.cpp b/src/strings.cpp index c589b0eef5..4c78e0fe7b 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -708,13 +708,26 @@ static const Units _units_velocity[] = { { {37888, 16}, STR_UNITS_VELOCITY_GAMEUNITS, 1 }, }; -/** Unit conversions for velocity. */ +/** Unit conversions for power. */ static const Units _units_power[] = { { { 1, 0}, STR_UNITS_POWER_IMPERIAL, 0 }, { {4153, 12}, STR_UNITS_POWER_METRIC, 0 }, { {6109, 13}, STR_UNITS_POWER_SI, 0 }, }; +/** Unit conversions for power to weight. */ +static const Units _units_power_to_weight[] = { + { { 29, 5}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_IMPERIAL, 1}, + { { 1, 0}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_METRIC, 1}, + { { 1, 0}, STR_UNITS_POWER_IMPERIAL_TO_WEIGHT_SI, 1}, + { { 59, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_IMPERIAL, 1}, + { { 65, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_METRIC, 1}, + { { 65, 6}, STR_UNITS_POWER_METRIC_TO_WEIGHT_SI, 1}, + { { 173, 8}, STR_UNITS_POWER_SI_TO_WEIGHT_IMPERIAL, 1}, + { { 3, 2}, STR_UNITS_POWER_SI_TO_WEIGHT_METRIC, 1}, + { { 3, 2}, STR_UNITS_POWER_SI_TO_WEIGHT_SI, 1}, +}; + /** Unit conversions for weight. */ static const UnitsLong _units_weight[] = { { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL }, @@ -1252,6 +1265,19 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg break; } + case SCC_POWER_TO_WEIGHT: { // {POWER_TO_WEIGHT} + auto setting = _settings_game.locale.units_power * 3u + _settings_game.locale.units_weight; + assert(setting < lengthof(_units_power_to_weight)); + + auto const &x = _units_power_to_weight[setting]; + + int64 args_array[] = {x.c.ToDisplay(args->GetInt64()), x.decimal_places}; + + StringParameters tmp_params(args_array); + buff = FormatString(buff, GetStringPtr(x.s), &tmp_params, last); + break; + } + case SCC_VELOCITY: { // {VELOCITY} assert(_settings_game.locale.units_velocity < lengthof(_units_velocity)); unsigned int decimal_places = _units_velocity[_settings_game.locale.units_velocity].decimal_places; diff --git a/src/table/control_codes.h b/src/table/control_codes.h index 7f42d2c4f6..ef3f8ff268 100644 --- a/src/table/control_codes.h +++ b/src/table/control_codes.h @@ -56,6 +56,7 @@ enum StringControlCode { SCC_CARGO_TINY, SCC_CARGO_LIST, SCC_POWER, + SCC_POWER_TO_WEIGHT, SCC_VOLUME_LONG, SCC_VOLUME_SHORT, SCC_WEIGHT_LONG, diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index 7ce480f6fa..19ce4b0a7d 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -78,6 +78,7 @@ static const CmdStruct _cmd_structs[] = { {"CARGO_TINY", EmitSingleChar, SCC_CARGO_TINY, 2, 1, C_NONE}, // tiny cargo description with only the amount, not a specifier for the amount or the actual cargo name {"CARGO_LIST", EmitSingleChar, SCC_CARGO_LIST, 1, -1, C_CASE}, {"POWER", EmitSingleChar, SCC_POWER, 1, 0, C_NONE}, + {"POWER_TO_WEIGHT", EmitSingleChar, SCC_POWER_TO_WEIGHT, 1, 0, C_NONE}, {"VOLUME_LONG", EmitSingleChar, SCC_VOLUME_LONG, 1, 0, C_NONE}, {"VOLUME_SHORT", EmitSingleChar, SCC_VOLUME_SHORT, 1, 0, C_NONE}, {"WEIGHT_LONG", EmitSingleChar, SCC_WEIGHT_LONG, 1, 0, C_NONE}, diff --git a/src/train.h b/src/train.h index 8ff597ebb8..4b0a739b01 100644 --- a/src/train.h +++ b/src/train.h @@ -228,6 +228,12 @@ protected: // These functions should not be called outside acceleration code. return weight; } + /** + * Calculates the weight value that this vehicle will have when fully loaded with its current cargo. + * @return Weight value in tonnes. + */ + uint16 GetMaxWeight() const override; + /** * Allows to know the tractive effort value that this vehicle will use. * @return Tractive effort value from the engine. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e5789d807f..eeae7f1e9d 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4119,3 +4119,20 @@ Trackdir Train::GetVehicleTrackdir() const return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction); } + +uint16 Train::GetMaxWeight() const +{ + uint16 weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnitsInTrain(this->GetEngine()->DetermineCapacity(this)); + + /* Vehicle weight is not added for articulated parts. */ + if (!this->IsArticulatedPart()) { + weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight); + } + + /* Powered wagons have extra weight added. */ + if (HasBit(this->flags, VRF_POWEREDWAGON)) { + weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight; + } + + return weight; +} diff --git a/src/vehicle.cpp b/src/vehicle.cpp index af4d4d9ff1..eeb22be5be 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2987,3 +2987,29 @@ void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles) } } } + +/** + * Calculates the maximum weight of the ground vehicle when loaded. + * @return Weight in tonnes + */ +uint32 Vehicle::GetDisplayMaxWeight() const +{ + uint32 max_weight = 0; + + for (const Vehicle* u = this; u != nullptr; u = u->Next()) { + max_weight += u->GetMaxWeight(); + } + + return max_weight; +} + +/** + * Calculates the minimum power-to-weight ratio using the maximum weight of the ground vehicle + * @return power-to-weight ratio in 10ths of hp(I) per tonne + */ +uint32 Vehicle::GetDisplayMinPowerToWeight() const +{ + uint32 max_weight = GetDisplayMaxWeight(); + if (max_weight == 0) return 0; + return GetGroundVehicleCache()->cached_power * 10u / max_weight; +} diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 9316a76477..63fc7b524b 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -346,6 +346,15 @@ public: mutable MutableSpriteCache sprite_cache; ///< Cache of sprites and values related to recalculating them, see #MutableSpriteCache + /** + * Calculates the weight value that this vehicle will have when fully loaded with its current cargo. + * @return Weight value in tonnes. + */ + virtual uint16 GetMaxWeight() const + { + return 0; + } + Vehicle(VehicleType type = VEH_INVALID); void PreDestructor(); @@ -1040,6 +1049,9 @@ public: * @return an iterable ensemble of orders of a vehicle */ IterateWrapper Orders() const { return IterateWrapper(this->orders); } + + uint32 GetDisplayMaxWeight() const; + uint32 GetDisplayMinPowerToWeight() const; }; /** diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 49e57c605e..c840a09d71 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2343,7 +2343,12 @@ struct VehicleDetailsWindow : Window { /* 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); + if (v->IsGroundVehicle()) { + SetDParam(2, v->GetDisplayMinPowerToWeight()); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_MIN_PERFORMANCE); + } else { + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); + } y += FONT_HEIGHT_NORMAL; /* Draw breakdown & reliability */