Skip to content

Commit

Permalink
Energy Rework 6.1
Browse files Browse the repository at this point in the history
Updates the code for `units_sufficient()` as it no longer needs the character input.

Added `energy_available()` for when you need to calculate energy available to a tool beyond just what's in it (ie: UPS tools/guns)

Updated ranged.cpp to use UPS charges for guns.

Next I need to convert vehicles to run off energy instead of battery charges.
  • Loading branch information
KheirFerrum committed Jan 8, 2025
1 parent a420615 commit 8cd471a
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 123 deletions.
2 changes: 1 addition & 1 deletion src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2721,7 +2721,7 @@ void activity_handlers::repair_item_finish( player_activity *act, player *p )

// TODO: Allow setting this in the actor
// TODO: Don't use charges_to_use: welder has 50 charges per use, soldering iron has 1
if( !used_tool->units_sufficient( *p ) ) {
if( !used_tool->units_sufficient() ) {
p->add_msg_if_player( _( "Your %s ran out of charges" ), used_tool->tname() );
act->set_to_null();
return;
Expand Down
31 changes: 4 additions & 27 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7751,10 +7751,7 @@ bool Character::has_enough_power( const item &it, bool show_msg ) const
return true;
}
if( it.is_power_armor() ) {
if( ( character_funcs::can_interface_armor( *this ) &&
has_charges( itype_bio_armor, it.ammo_required() ) ) ||
( it.has_flag( flag_USE_UPS ) && has_charges( itype_UPS, it.ammo_required() ) ) ||
it.ammo_sufficient() ) {
if( it.energy_sufficient( *this ) ) {
return true;
}

Expand Down Expand Up @@ -7826,27 +7823,7 @@ bool Character::consume_charges( item &used, int qty )
return false;
}

if( used.is_power_armor() ) {
if( used.charges >= qty ) {
used.ammo_consume( qty, pos() );
} else if( character_funcs::can_interface_armor( *this ) &&
use_charges_if_avail( itype_bio_armor, qty ) ) {
} else {
use_charges( itype_UPS, qty );
}
}

// USE_UPS may occur on base items and is added by the UPS tool mod
// If an item has the flag, then it should not be consumed on use.
if( used.has_flag( flag_USE_UPS ) ) {
// With the new UPS system, we'll want to use any charges built up in the tool before pulling from the UPS
// The usage of the item was already approved, so drain item if possible, otherwise use UPS
if( used.charges >= qty ) {
used.ammo_consume( qty, pos() );
} else {
use_charges( itype_UPS, qty );
}
} else if( used.is_tool() && used.units_remaining( *this ) == 0 && !used.ammo_required() ) {
if( used.is_tool() && used.units_remaining() == 0 && !used.ammo_required() ) {
// Tools which don't require ammo are instead destroyed.
// Put here cause tools may have use actions that require charges without charges_per_use
used.detach();
Expand Down Expand Up @@ -10064,13 +10041,13 @@ bool Character::has_energy( const itype_id &it, units::energy amount,
units::energy UPS_needed = amount;
if( is_mounted() && mounted_creature.get()->has_flag( MF_RIDEABLE_MECH ) ) {
auto mons = mounted_creature.get();
UPS_needed -= mons->get_battery_item()->energy_remaining();
UPS_needed -= std::min( mons->get_battery_item()->energy_remaining(), UPS_needed );
if( UPS_needed == 0_J ) {
return true;
}
}
if( has_power() && has_active_bionic( bio_ups ) ) {
UPS_needed -= get_power_level();
UPS_needed -= std::min( get_power_level(), UPS_needed );
if( UPS_needed == 0_J ) {
return true;
}
Expand Down
12 changes: 6 additions & 6 deletions src/character_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1275,9 +1275,9 @@ int ammo_count_for( const Character &who, const item &gun )
return item::INFINITE_CHARGES;
}
int ammo_drain = gun.ammo_required();
int energy_drain = gun.get_gun_ups_drain();
units::energy energy_drain = gun.get_gun_ups_drain();

units::energy power = units::from_kilojoule( who.charges_of( itype_UPS ) );
units::energy power = who.energy_of( itype_UPS );
int total_ammo = gun.ammo_remaining();
const std::vector<item *> inv_ammo = find_ammo_items_or_mags( who, gun, true, -1 );

Expand All @@ -1293,12 +1293,12 @@ int ammo_count_for( const Character &who, const item &gun )
}
}

if( ammo_drain > 0 && energy_drain > 0 ) {
if( ammo_drain > 0 && energy_drain > 0_J ) {
// Both UPS and ammo, lower is limiting.
return std::min( total_ammo / ammo_drain, power / units::from_kilojoule( energy_drain ) );
} else if( energy_drain > 0 ) {
return std::min( total_ammo / ammo_drain, power / energy_drain );
} else if( energy_drain > 0_J ) {
//Only one of the two, it is limiting.
return power / units::from_kilojoule( energy_drain );
return power / energy_drain;
} else if( ammo_drain > 0 ) {
return total_ammo / ammo_drain;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/handle_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,7 @@ static void sleep()
std::vector<std::string> active;
for( auto &it : u.inv_dump() ) {
if( it->has_flag( flag_LITCIG ) ||
( it->is_active() && ( it->charges > 0 || it->units_remaining( u ) > 0 ) && it->is_tool() &&
( it->is_active() && ( it->charges > 0 || it->units_remaining() > 0 ) && it->is_tool() &&
!it->has_flag( flag_SLEEP_IGNORE ) ) ) {
active.push_back( it->tname() );
}
Expand Down
52 changes: 35 additions & 17 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2524,12 +2524,10 @@ void item::gun_info( const item *mod, std::vector<iteminfo> &info, const iteminf
mod->ammo_data()->nname( mod->ammo_remaining() ) ) );
}

if( mod->get_gun_ups_drain() && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) {
if( mod->get_gun_ups_drain() > 0_J && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) {
info.emplace_back( "AMMO",
string_format( vgettext( "Uses <stat>%i</stat> charge of UPS per shot",
"Uses <stat>%i</stat> charges of UPS per shot",
mod->get_gun_ups_drain() ),
mod->get_gun_ups_drain() ) );
string_format( "Uses <stat>%s</stat> of UPS per shot",
units::display( mod->get_gun_ups_drain() ) ) );
}

if( skill.ident() == skill_throw ) {
Expand Down Expand Up @@ -7861,6 +7859,28 @@ int item::gun_range( const player *p ) const
return std::max( 0, ret );
}

units::energy item::energy_available( const Character &ch, units::energy limit ) const
{
units::energy res = energy_remaining();

if( limit > res ) {
if( is_power_armor() ) {
if( character_funcs::can_interface_armor( ch ) && has_flag( flag_USE_UPS ) ) {
res += std::max( ch.energy_of( itype_UPS, limit - res ), ch.energy_of( itype_bio_armor,
limit - res ) );
} else if( character_funcs::can_interface_armor( ch ) ) {
res += ch.energy_of( itype_bio_armor, limit - res );
} else {
res += ch.energy_of( itype_UPS, limit - res );
}
} else if( res < limit && has_flag( flag_USE_UPS ) ) {
res += ch.energy_of( itype_UPS, limit - res );
}
}

return res;
}

units::energy item::energy_remaining() const
{
const item *bat = battery_current();
Expand Down Expand Up @@ -7912,7 +7932,7 @@ bool item::energy_sufficient( const Character &ch, units::energy p_needed ) cons
if( p_needed == 0_J ) {
return true;
}
return energy_remaining() >= p_needed;
return energy_available( ch, p_needed ) >= p_needed;
}

units::energy item::energy_consume( const units::energy power, const tripoint &pos )
Expand Down Expand Up @@ -8614,7 +8634,7 @@ item *item::get_usable_item( const std::string &use_name )
return const_cast<item *>( const_cast<const item *>( this )->get_usable_item( use_name ) );
}

int item::units_remaining( const Character &ch, int limit ) const
int item::units_remaining( int limit ) const
{
if( count_by_charges() ) {
return std::min( static_cast<int>( charges ), limit );
Expand All @@ -8625,7 +8645,7 @@ int item::units_remaining( const Character &ch, int limit ) const
return std::min( res, limit );
}

bool item::units_sufficient( const Character &ch, int qty ) const
bool item::units_sufficient( int qty ) const
{
if( qty < 0 ) {
qty = count_by_charges() ? 1 : ammo_required();
Expand All @@ -8634,7 +8654,7 @@ bool item::units_sufficient( const Character &ch, int qty ) const
return true;
}

return units_remaining( ch, qty ) == qty;
return units_remaining( qty ) == qty;
}

item_reload_option::item_reload_option( const item_reload_option & ) = default;
Expand Down Expand Up @@ -10191,11 +10211,9 @@ detached_ptr<item> item::process_tool( detached_ptr<item> &&self, player *carrie
}
}

// HACK: this means that UPS items will last one more check longer than they should since they don't trigger when
// their ammo_remaining is 0, since that doesn't check the UPS "stock" available (which is an expensive check)
// It's done like this cause grenades must be destroyed when charge reaches 0, or it will linger an extra turn.
if( ( charge_dependent && self->ammo_remaining() == 0 ) ||
( energy_dependent && self->energy_remaining() == 0_J && !uses_UPS ) ||
( energy_dependent && self->energy_available( *carrier ) == 0_J ) ||
energy_to_use > 0_J || charges_to_use > 0 ) {
revert_destroy = true;
if( carrier ) {
Expand Down Expand Up @@ -10649,17 +10667,17 @@ bool item::count_by_charges( const itype_id &id )
return id->count_by_charges();
}

int item::get_gun_ups_drain() const
units::energy item::get_gun_ups_drain() const
{
int draincount = 0;
units::energy draincount = 0_J;
if( type->gun ) {
int modifier = 0;
units::energy modifier = 0_J;
float multiplier = 1.0f;
for( const item *mod : gunmods() ) {
modifier += mod->type->gunmod->ups_charges_modifier;
modifier += units::from_kilojoule( mod->type->gunmod->ups_charges_modifier );
multiplier *= mod->type->gunmod->ups_charges_multiplier;
}
draincount = ( units::to_joule( type->gun->energy_draw ) * multiplier ) + modifier;
draincount = type->gun->energy_draw * multiplier + modifier;
}
return draincount;
}
Expand Down
19 changes: 13 additions & 6 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1854,7 +1854,16 @@ class item : public location_visitable<item>, public game_object<item>
*/
bool is_gun() const;

/** Amount of energy currently loaded in tool, gun or battery */
/**
* Amount of energy available to a tool including UPS
* if you want only the energy in the tool, use energy_remaining()
*/
units::energy energy_available( const Character &ch,
units::energy p_needed = units::from_joule( INT_MAX ) ) const;
/**
* Amount of energy currently loaded in tool, gun or battery
* For total including UPS use energy_available()
*/
units::energy energy_remaining() const;
/** Maximum quantity of energy loadable for tool, gun or battery*/
units::energy energy_capacity() const;
Expand Down Expand Up @@ -2123,18 +2132,16 @@ class item : public location_visitable<item>, public game_object<item>

/**
* How many units (ammo or charges) are remaining?
* @param ch character responsible for invoking the item
* @param limit stop searching after this many units found
* @note also checks availability of UPS charges if applicable
*/
int units_remaining( const Character &ch, int limit = INT_MAX ) const;
int units_remaining( int limit = INT_MAX ) const;

/**
* Check if item has sufficient units (ammo or charges) remaining
* @param ch Character to check (used if ammo is UPS charges)
* @param qty units required, if unspecified use item default
*/
bool units_sufficient( const Character &ch, int qty = -1 ) const;
bool units_sufficient( int qty = -1 ) const;
/**
* Returns name of deceased being if it had any or empty string if not
**/
Expand Down Expand Up @@ -2181,7 +2188,7 @@ class item : public location_visitable<item>, public game_object<item>
time_point birthday() const;
void set_birthday( const time_point &bday );
void handle_pickup_ownership( Character &c );
int get_gun_ups_drain() const;
units::energy get_gun_ups_drain() const;
void validate_ownership() const;
inline void set_old_owner( const faction_id &temp_owner ) {
old_owner = temp_owner;
Expand Down
8 changes: 4 additions & 4 deletions src/item_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ int shots_remaining( const Character &who, const item &it )
}

int ammo_drain = it.ammo_required();
int energy_drain = it.get_gun_ups_drain();
int power = who.charges_of( itype_UPS );
units::energy energy_drain = it.get_gun_ups_drain();
units::energy power = who.energy_of( itype_UPS );

if( ammo_drain > 0 && energy_drain > 0 ) {
if( ammo_drain > 0 && energy_drain > 0_J ) {
// Both UPS and ammo, lower is limiting.
return std::min( it.ammo_remaining() / ammo_drain, power / energy_drain );
} else if( energy_drain > 0 ) {
} else if( energy_drain > 0_J ) {
//Only one of the two, it is limiting.
return power / energy_drain;
} else if( ammo_drain > 0 ) {
Expand Down
Loading

0 comments on commit 8cd471a

Please sign in to comment.