From d0fa90f41a81e19cad35f59460f54dd2f8ac8cf5 Mon Sep 17 00:00:00 2001 From: Chaosvolt Date: Mon, 25 Oct 2021 12:25:59 -0500 Subject: [PATCH] Store power in joules to fix power storage cap (#1071) * [WIP] Store power in joules to fix power storage cap * Fix test * Possibly needed for legacy saves --- src/activity_handlers.cpp | 2 +- src/bionics.cpp | 8 +++---- src/bionics_ui.cpp | 14 ++++------- src/item.cpp | 11 ++++----- src/item_factory.cpp | 2 +- src/mutation.cpp | 6 ++--- src/panels.cpp | 5 +--- src/savegame_json.cpp | 10 ++++---- src/units.cpp | 15 ++++-------- src/units.h | 6 ++--- src/units_energy.h | 50 ++++++++------------------------------- tests/units_test.cpp | 9 ++----- 12 files changed, 41 insertions(+), 97 deletions(-) diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 473898fd0c48..407a36d81f35 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -3439,7 +3439,7 @@ void activity_handlers::operation_do_turn( player_activity *act, player *p ) if( p->has_bionic( bid ) ) { p->perform_uninstall( bid, act->values[0], act->values[1], - units::from_millijoule( act->values[2] ), act->values[3] ); + units::from_joule( act->values[2] ), act->values[3] ); } else { debugmsg( _( "Tried to uninstall %s, but you don't have this bionic installed." ), bid.c_str() ); p->remove_effect( effect_under_op ); diff --git a/src/bionics.cpp b/src/bionics.cpp index c262f3a1fb0c..faea75877cc3 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -462,7 +462,7 @@ void npc::check_or_use_weapon_cbm( const bionic_id &cbm_id ) } const float allowed_ratio = static_cast( rules.cbm_reserve ) / 100.0f; const units::energy free_power = get_power_level() - get_max_power_level() * allowed_ratio; - if( free_power <= 0_mJ ) { + if( free_power <= 0_J ) { return; } @@ -1535,7 +1535,7 @@ void Character::process_bionic( int b ) bio.charge_timer = bio.info().charge_time; } else { // Try to recharge our bionic if it is made for it - units::energy cost = 0_mJ; + units::energy cost = 0_J; bool recharged = attempt_recharge( *this, bio, cost, discharge_factor, discharge_rate ); if( !recharged ) { // No power to recharge, so deactivate @@ -1545,7 +1545,7 @@ void Character::process_bionic( int b ) deactivate_bionic( b, true ); return; } - if( cost > 0_mJ ) { + if( cost > 0_J ) { mod_power_level( -cost ); } } @@ -2231,7 +2231,7 @@ bool Character::install_bionics( const itype &type, player &installer, bool auto assign_activity( ACT_OPERATION, to_moves( difficulty * 20_minutes ) ); activity.values.push_back( difficulty ); activity.values.push_back( success ); - activity.values.push_back( units::to_millijoule( bioid->capacity ) ); + activity.values.push_back( units::to_joule( bioid->capacity ) ); activity.values.push_back( pl_skill ); activity.str_values.push_back( "install" ); activity.str_values.push_back( bioid.str() ); diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index 3501a62d1b98..c36d7a8e41de 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -224,24 +224,18 @@ static void draw_bionics_titlebar( const catacurses::window &window, player *p, fuel_string.clear(); } std::string power_string; - const int curr_power = units::to_millijoule( p->get_power_level() ); - const int kilo = curr_power / units::to_millijoule( 1_kJ ); - const int joule = ( curr_power % units::to_millijoule( 1_kJ ) ) / units::to_millijoule( 1_J ); - const int milli = curr_power % units::to_millijoule( 1_J ); + const int curr_power = units::to_joule( p->get_power_level() ); + const int kilo = curr_power / units::to_joule( 1_kJ ); + const int joule = ( curr_power % units::to_joule( 1_kJ ) ) / units::to_joule( 1_J ); if( kilo > 0 ) { power_string = std::to_string( kilo ); if( joule > 0 ) { power_string += pgettext( "decimal separator", "." ) + std::to_string( joule ); } power_string += pgettext( "energy unit: kilojoule", "kJ" ); - } else if( joule > 0 ) { + } else { power_string = std::to_string( joule ); - if( milli > 0 ) { - power_string += pgettext( "decimal separator", "." ) + std::to_string( milli ); - } power_string += pgettext( "energy unit: joule", "J" ); - } else { - power_string = std::to_string( milli ) + pgettext( "energy unit: millijoule", "mJ" ); } const int pwr_str_pos = right_print( window, 1, 1, c_white, diff --git a/src/item.cpp b/src/item.cpp index a9fab7be9461..5772a732bed7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2918,10 +2918,7 @@ void item::battery_info( std::vector &info, const iteminfo_query * /*p } std::string info_string; - if( type->battery->max_capacity < 1_J ) { - info_string = string_format( _( "Capacity: %dmJ" ), - to_millijoule( type->battery->max_capacity ) ); - } else if( type->battery->max_capacity < 1_kJ ) { + if( type->battery->max_capacity < 1_kJ ) { info_string = string_format( _( "Capacity: %dJ" ), to_joule( type->battery->max_capacity ) ); } else if( type->battery->max_capacity >= 1_kJ ) { @@ -3162,10 +3159,10 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); - if( bid->capacity > 0_mJ ) { - info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), + if( bid->capacity > 0_J ) { + info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " J" ), iteminfo::no_newline, - units::to_millijoule( bid->capacity ) ) ); + units::to_joule( bid->capacity ) ) ); } insert_separation_line( info ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 348ebb83fd04..1331717dcf46 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -1206,7 +1206,7 @@ void Item_factory::check_definitions() const } } if( type->battery ) { - if( type->battery->max_capacity < 0_mJ ) { + if( type->battery->max_capacity < 0_J ) { msg += "battery cannot have negative maximum charge\n"; } } diff --git a/src/mutation.cpp b/src/mutation.cpp index 5ebccf073be0..5206ee8aa02c 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -625,9 +625,9 @@ void Character::activate_mutation( const trait_id &mut ) return; } else if( mut == trait_DEBUG_BIONIC_POWERGEN ) { int npower; - if( query_int( npower, "Modify bionic power by how much? (Values are in millijoules)" ) ) { - mod_power_level( units::from_millijoule( npower ) ); - add_msg_if_player( m_good, "Bionic power increased by %dmJ.", npower ); + if( query_int( npower, "Modify bionic power by how much? (Values are in joules)" ) ) { + mod_power_level( units::from_joule( npower ) ); + add_msg_if_player( m_good, "Bionic power increased by %dJ.", npower ); tdata.powered = false; } return; diff --git a/src/panels.cpp b/src/panels.cpp index d070a7ee0691..fd1f8a8fb820 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -800,10 +800,7 @@ static std::pair power_stat( const avatar &u ) c_pwr = c_red; } - if( u.get_power_level() < 1_J ) { - s_pwr = std::to_string( units::to_millijoule( u.get_power_level() ) ) + - pgettext( "energy unit: millijoule", "mJ" ); - } else if( u.get_power_level() < 1_kJ ) { + if( u.get_power_level() < 1_kJ ) { s_pwr = std::to_string( units::to_joule( u.get_power_level() ) ) + pgettext( "energy unit: joule", "J" ); } else { diff --git a/src/savegame_json.cpp b/src/savegame_json.cpp index 34a3a14fb14e..e50a1ca13346 100644 --- a/src/savegame_json.cpp +++ b/src/savegame_json.cpp @@ -594,8 +594,8 @@ void Character::load( const JsonObject &data ) assign( data, "max_power_level", max_power_level, false, 0_kJ ); // Bionic power should not be negative! - if( power_level < 0_mJ ) { - power_level = 0_mJ; + if( power_level < 0_J ) { + power_level = 0_J; } JsonArray overmap_time_array = data.get_array( "overmap_time" ); @@ -723,9 +723,7 @@ void Character::store( JsonOut &json ) const json.end_object(); // npc; unimplemented - if( power_level < 1_J ) { - json.member( "power_level", std::to_string( units::to_millijoule( power_level ) ) + " mJ" ); - } else if( power_level < 1_kJ ) { + if( power_level < 1_kJ ) { json.member( "power_level", std::to_string( units::to_joule( power_level ) ) + " J" ); } else { json.member( "power_level", units::to_kilojoule( power_level ) ); @@ -2180,7 +2178,7 @@ void item::io( Archive &archive ) archive.io( "charges", charges, 0 ); charges = std::max( charges, 0 ); - archive.io( "energy", energy, 0_mJ ); + archive.io( "energy", energy, 0_J ); archive.io( "burnt", burnt, 0 ); archive.io( "poison", poison, 0 ); diff --git a/src/units.cpp b/src/units.cpp index 4435ac7de4d3..ac33c2aa7f05 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -31,12 +31,10 @@ void mass::serialize( JsonOut &jsout ) const template<> void energy::serialize( JsonOut &jsout ) const { - if( value_ % 1000000 == 0 ) { - jsout.write( string_format( "%d kJ", value_ / 1000000 ) ); - } else if( value_ % 1000 == 0 ) { - jsout.write( string_format( "%d J", value_ / 1000 ) ) ; + if( value_ % 1000 == 0 ) { + jsout.write( string_format( "%d kJ", value_ / 1000 ) ); } else { - jsout.write( string_format( "%d mJ", value_ ) ); + jsout.write( string_format( "%d J", value_ ) ) ; } } @@ -54,11 +52,6 @@ std::string display( const units::energy v ) if( kj >= 1 && float( j ) / kj == 1000 ) { return std::to_string( kj ) + ' ' + pgettext( "energy unit: kilojoule", "kJ" ); } - const int mj = units::to_millijoule( v ); - // at least 1 J and there is no fraction - if( j >= 1 && float( mj ) / j == 1000 ) { - return std::to_string( j ) + ' ' + pgettext( "energy unit: joule", "J" ); - } - return std::to_string( mj ) + ' ' + pgettext( "energy unit: millijoule", "mJ" ); + return std::to_string( j ) + ' ' + pgettext( "energy unit: joule", "J" ); } } // namespace units diff --git a/src/units.h b/src/units.h index 00868cf2905a..7403a23ea98e 100644 --- a/src/units.h +++ b/src/units.h @@ -31,9 +31,9 @@ inline std::ostream &operator<<( std::ostream &o, volume_in_milliliter_tag ) return o << "ml"; } -inline std::ostream &operator<<( std::ostream &o, energy_in_millijoule_tag ) +inline std::ostream &operator<<( std::ostream &o, energy_in_joule_tag ) { - return o << "mJ"; + return o << "J"; } inline std::ostream &operator<<( std::ostream &o, money_in_cent_tag ) @@ -59,7 +59,7 @@ std::string display( units::energy v ); namespace units { static const std::vector> energy_units = { { - { "mJ", 1_mJ }, + { "mJ", 1_J }, // Millijoules are depreciated, this is only defined to migrate old saves. { "J", 1_J }, { "kJ", 1_kJ }, } diff --git a/src/units_energy.h b/src/units_energy.h index 2fe389b66bae..57abc7331486 100644 --- a/src/units_energy.h +++ b/src/units_energy.h @@ -9,11 +9,11 @@ namespace units { -class energy_in_millijoule_tag +class energy_in_joule_tag { }; -using energy = quantity; +using energy = quantity; const energy energy_min = units::energy( std::numeric_limits::min(), units::energy::unit_type{} ); @@ -22,70 +22,40 @@ const energy energy_max = units::energy( std::numeric_limits -inline constexpr quantity from_millijoule( +inline constexpr quantity from_joule( const value_type v ) { - return quantity( v, energy_in_millijoule_tag{} ); + return quantity( v, energy_in_joule_tag{} ); } template -inline constexpr quantity from_joule( const value_type v ) +inline constexpr quantity from_kilojoule( const value_type v ) { const value_type max_energy_joules = std::numeric_limits::max() / 1000; - // Check for overflow - if the energy provided is greater than max energy, then it - // if overflow when converted to millijoules - const value_type energy = v > max_energy_joules ? max_energy_joules : v; - return from_millijoule( energy * 1000 ); -} - -template -inline constexpr quantity from_kilojoule( const value_type v ) -{ - const value_type max_energy_joules = std::numeric_limits::max() / 1000; - // This checks for value_type overflow - if the energy we are given in Joules is greater - // than the max energy in Joules, overflow will occur when it is converted to millijoules - // The value we are given is in kJ, multiply by 1000 to convert it to joules, for use in from_joule value_type energy = v * 1000 > max_energy_joules ? max_energy_joules : v * 1000; return from_joule( energy ); } template -inline constexpr value_type to_millijoule( const quantity &v ) -{ - return v / from_millijoule( 1 ); -} - -template -inline constexpr value_type to_joule( const quantity &v ) +inline constexpr value_type to_joule( const quantity &v ) { - return to_millijoule( v ) / 1000.0; + return v / from_joule( 1 ); } template -inline constexpr value_type to_kilojoule( const quantity &v ) +inline constexpr value_type to_kilojoule( const quantity &v ) { return to_joule( v ) / 1000.0; } } // namespace units -inline constexpr units::energy operator"" _mJ( const unsigned long long v ) -{ - return units::from_millijoule( v ); -} - -inline constexpr units::quantity operator"" _mJ( - const long double v ) -{ - return units::from_millijoule( v ); -} - inline constexpr units::energy operator"" _J( const unsigned long long v ) { return units::from_joule( v ); } -inline constexpr units::quantity operator"" _J( +inline constexpr units::quantity operator"" _J( const long double v ) { return units::from_joule( v ); @@ -96,7 +66,7 @@ inline constexpr units::energy operator"" _kJ( const unsigned long long v ) return units::from_kilojoule( v ); } -inline constexpr units::quantity operator"" _kJ( +inline constexpr units::quantity operator"" _kJ( const long double v ) { return units::from_kilojoule( v ); diff --git a/tests/units_test.cpp b/tests/units_test.cpp index f2adca2f82fd..00b1f34b2742 100644 --- a/tests/units_test.cpp +++ b/tests/units_test.cpp @@ -16,8 +16,6 @@ TEST_CASE( "units_have_correct_ratios", "[units]" ) CHECK( 1.0_gram == 1000.0_milligram ); CHECK( 1_kilogram == 1000_gram ); CHECK( 1.0_kilogram == 1000.0_gram ); - CHECK( 1_J == 1000_mJ ); - CHECK( 1.0_J == 1000.0_mJ ); CHECK( 1_kJ == 1000_J ); CHECK( 1.0_kJ == 1000.0_J ); CHECK( 1_USD == 100_cent ); @@ -28,7 +26,6 @@ TEST_CASE( "units_have_correct_ratios", "[units]" ) CHECK( 1_hours == 60_minutes ); CHECK( 1_minutes == 60_seconds ); - CHECK( 1_mJ == units::from_millijoule( 1 ) ); CHECK( 1_J == units::from_joule( 1 ) ); CHECK( 1_kJ == units::from_kilojoule( 1 ) ); @@ -52,15 +49,13 @@ TEST_CASE( "energy parsing from JSON", "[units]" ) CHECK_THROWS( parse_energy_quantity( "\" \"" ) ); // only spaces CHECK_THROWS( parse_energy_quantity( "\"27\"" ) ); // no energy unit - CHECK( parse_energy_quantity( "\"1 mJ\"" ) == 1_mJ ); CHECK( parse_energy_quantity( "\"1 J\"" ) == 1_J ); CHECK( parse_energy_quantity( "\"1 kJ\"" ) == 1_kJ ); - CHECK( parse_energy_quantity( "\"+1 mJ\"" ) == 1_mJ ); CHECK( parse_energy_quantity( "\"+1 J\"" ) == 1_J ); CHECK( parse_energy_quantity( "\"+1 kJ\"" ) == 1_kJ ); - CHECK( parse_energy_quantity( "\"1 mJ 1 J 1 kJ\"" ) == 1_mJ + 1_J + 1_kJ ); - CHECK( parse_energy_quantity( "\"1 mJ -4 J 1 kJ\"" ) == 1_mJ - 4_J + 1_kJ ); + CHECK( parse_energy_quantity( "\"1 J 1 kJ\"" ) == 1_J + 1_kJ ); + CHECK( parse_energy_quantity( "\"1 kJ -4 J\"" ) == 1_kJ - 4_J ); } static time_duration parse_time_duration( const std::string &json )