Skip to content

Commit

Permalink
Store power in joules to fix power storage cap (cataclysmbnteam#1071)
Browse files Browse the repository at this point in the history
* [WIP] Store power in joules to fix power storage cap

* Fix test

* Possibly needed for legacy saves
  • Loading branch information
chaosvolt authored Oct 25, 2021
1 parent a5245a6 commit d0fa90f
Show file tree
Hide file tree
Showing 12 changed files with 41 additions and 97 deletions.
2 changes: 1 addition & 1 deletion src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
8 changes: 4 additions & 4 deletions src/bionics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ void npc::check_or_use_weapon_cbm( const bionic_id &cbm_id )
}
const float allowed_ratio = static_cast<int>( 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;
}

Expand Down Expand Up @@ -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
Expand All @@ -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 );
}
}
Expand Down Expand Up @@ -2231,7 +2231,7 @@ bool Character::install_bionics( const itype &type, player &installer, bool auto
assign_activity( ACT_OPERATION, to_moves<int>( 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() );
Expand Down
14 changes: 4 additions & 10 deletions src/bionics_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 4 additions & 7 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2918,10 +2918,7 @@ void item::battery_info( std::vector<iteminfo> &info, const iteminfo_query * /*p
}

std::string info_string;
if( type->battery->max_capacity < 1_J ) {
info_string = string_format( _( "<bold>Capacity</bold>: %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( _( "<bold>Capacity</bold>: %dJ" ),
to_joule( type->battery->max_capacity ) );
} else if( type->battery->max_capacity >= 1_kJ ) {
Expand Down Expand Up @@ -3162,10 +3159,10 @@ void item::bionic_info( std::vector<iteminfo> &info, const iteminfo_query *parts

insert_separation_line( info );

if( bid->capacity > 0_mJ ) {
info.push_back( iteminfo( "CBM", _( "<bold>Power Capacity</bold>:" ), _( " <num> mJ" ),
if( bid->capacity > 0_J ) {
info.push_back( iteminfo( "CBM", _( "<bold>Power Capacity</bold>:" ), _( " <num> J" ),
iteminfo::no_newline,
units::to_millijoule( bid->capacity ) ) );
units::to_joule( bid->capacity ) ) );
}

insert_separation_line( info );
Expand Down
2 changes: 1 addition & 1 deletion src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/mutation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 1 addition & 4 deletions src/panels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,10 +800,7 @@ static std::pair<nc_color, std::string> 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 {
Expand Down
10 changes: 4 additions & 6 deletions src/savegame_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand Down Expand Up @@ -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 ) );
Expand Down Expand Up @@ -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 );
Expand Down
15 changes: 4 additions & 11 deletions src/units.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_ ) ) ;
}
}

Expand All @@ -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
6 changes: 3 additions & 3 deletions src/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -59,7 +59,7 @@ std::string display( units::energy v );
namespace units
{
static const std::vector<std::pair<std::string, energy>> 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 },
}
Expand Down
50 changes: 10 additions & 40 deletions src/units_energy.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
namespace units
{

class energy_in_millijoule_tag
class energy_in_joule_tag
{
};

using energy = quantity<int, energy_in_millijoule_tag>;
using energy = quantity<int, energy_in_joule_tag>;

const energy energy_min = units::energy( std::numeric_limits<units::energy::value_type>::min(),
units::energy::unit_type{} );
Expand All @@ -22,70 +22,40 @@ const energy energy_max = units::energy( std::numeric_limits<units::energy::valu
units::energy::unit_type{} );

template<typename value_type>
inline constexpr quantity<value_type, energy_in_millijoule_tag> from_millijoule(
inline constexpr quantity<value_type, energy_in_joule_tag> from_joule(
const value_type v )
{
return quantity<value_type, energy_in_millijoule_tag>( v, energy_in_millijoule_tag{} );
return quantity<value_type, energy_in_joule_tag>( v, energy_in_joule_tag{} );
}

template<typename value_type>
inline constexpr quantity<value_type, energy_in_millijoule_tag> from_joule( const value_type v )
inline constexpr quantity<value_type, energy_in_joule_tag> from_kilojoule( const value_type v )
{
const value_type max_energy_joules = std::numeric_limits<value_type>::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<value_type>( energy * 1000 );
}

template<typename value_type>
inline constexpr quantity<value_type, energy_in_millijoule_tag> from_kilojoule( const value_type v )
{
const value_type max_energy_joules = std::numeric_limits<value_type>::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<value_type>( energy );
}

template<typename value_type>
inline constexpr value_type to_millijoule( const quantity<value_type, energy_in_millijoule_tag> &v )
{
return v / from_millijoule<value_type>( 1 );
}

template<typename value_type>
inline constexpr value_type to_joule( const quantity<value_type, energy_in_millijoule_tag> &v )
inline constexpr value_type to_joule( const quantity<value_type, energy_in_joule_tag> &v )
{
return to_millijoule( v ) / 1000.0;
return v / from_joule<value_type>( 1 );
}

template<typename value_type>
inline constexpr value_type to_kilojoule( const quantity<value_type, energy_in_millijoule_tag> &v )
inline constexpr value_type to_kilojoule( const quantity<value_type, energy_in_joule_tag> &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<double, units::energy_in_millijoule_tag> 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<double, units::energy_in_millijoule_tag> operator"" _J(
inline constexpr units::quantity<double, units::energy_in_joule_tag> operator"" _J(
const long double v )
{
return units::from_joule( v );
Expand All @@ -96,7 +66,7 @@ inline constexpr units::energy operator"" _kJ( const unsigned long long v )
return units::from_kilojoule( v );
}

inline constexpr units::quantity<double, units::energy_in_millijoule_tag> operator"" _kJ(
inline constexpr units::quantity<double, units::energy_in_joule_tag> operator"" _kJ(
const long double v )
{
return units::from_kilojoule( v );
Expand Down
9 changes: 2 additions & 7 deletions tests/units_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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 ) );

Expand All @@ -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 )
Expand Down

0 comments on commit d0fa90f

Please sign in to comment.