Skip to content

Commit

Permalink
Consistent UPS charge consumption when crafting (CleverRaven#45781)
Browse files Browse the repository at this point in the history
  • Loading branch information
RoyBerube authored and anothersimulacrum committed Dec 23, 2020
1 parent b890153 commit 8cae58b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 33 deletions.
40 changes: 29 additions & 11 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11090,10 +11090,11 @@ bool Character::use_charges_if_avail( const itype_id &it, int quantity )
return false;
}

std::list<item> Character::use_charges( const itype_id &what, int qty,
std::list<item> Character::use_charges( const itype_id &what, int qty, const int radius,
const std::function<bool( const item & )> &filter )
{
std::list<item> res;
inventory inv = crafting_inventory( pos(), radius, true );

if( qty <= 0 ) {
return res;
Expand Down Expand Up @@ -11121,16 +11122,16 @@ std::list<item> Character::use_charges( const itype_id &what, int qty,
qty -= std::min( qty, bio );
}

int adv = charges_of( itype_adv_UPS_off, static_cast<int>( std::ceil( qty * 0.6 ) ) );
int adv = inv.charges_of( itype_adv_UPS_off, static_cast<int>( std::ceil( qty * 0.6 ) ) );
if( adv > 0 ) {
std::list<item> found = use_charges( itype_adv_UPS_off, adv );
std::list<item> found = use_charges( itype_adv_UPS_off, adv, radius );
res.splice( res.end(), found );
qty -= std::min( qty, static_cast<int>( adv / 0.6 ) );
}

int ups = charges_of( itype_UPS_off, qty );
int ups = inv.charges_of( itype_UPS_off, qty );
if( ups > 0 ) {
std::list<item> found = use_charges( itype_UPS_off, ups );
std::list<item> found = use_charges( itype_UPS_off, ups, radius );
res.splice( res.end(), found );
qty -= std::min( qty, ups );
}
Expand All @@ -11140,27 +11141,44 @@ std::list<item> Character::use_charges( const itype_id &what, int qty,
std::vector<item *> del;

bool has_tool_with_UPS = false;
visit_items( [this, &what, &qty, &res, &del, &has_tool_with_UPS, &filter]( item * e ) {
if( e->use_charges( what, qty, res, pos(), filter ) ) {
del.push_back( e );
}
// Detection of UPS tool
inv.visit_items( [ &what, &qty, &has_tool_with_UPS, &filter]( item * e ) {
if( filter( *e ) && e->typeId() == what && e->has_flag( flag_USE_UPS ) ) {
has_tool_with_UPS = true;
return VisitResponse::ABORT;
}
return qty > 0 ? VisitResponse::NEXT : VisitResponse::ABORT;
} );

if( radius >= 0 ) {
get_map().use_charges( pos(), radius, what, qty, return_true<item> );
}
if( qty > 0 ) {
visit_items( [this, &what, &qty, &res, &del, &filter]( item * e ) {
if( e->use_charges( what, qty, res, pos(), filter ) ) {
del.push_back( e );
}
return qty > 0 ? VisitResponse::NEXT : VisitResponse::ABORT;
} );
}

for( item *e : del ) {
remove_item( *e );
inv.remove_item( e );
}

if( has_tool_with_UPS ) {
use_charges( itype_UPS, qty );
use_charges( itype_UPS, qty, radius );
}

return res;
}

std::list<item> Character::use_charges( const itype_id &what, int qty,
const std::function<bool( const item & )> &filter )
{
return use_charges( what, qty, -1, filter );
}

bool Character::has_fire( const int quantity ) const
{
// TODO: Replace this with a "tool produces fire" flag.
Expand Down
25 changes: 24 additions & 1 deletion src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -2007,9 +2007,25 @@ class Character : public Creature, public visitable<Character>
// Uses up charges
bool use_charges_if_avail( const itype_id &it, int quantity );

// Uses up charges
/**
* Use charges in character inventory.
* @param what itype_id of item using charges
* @param qty Number of charges
* @param filter Filter
* @return List of items used
*/
std::list<item> use_charges( const itype_id &what, int qty,
const std::function<bool( const item & )> &filter = return_true<item> );
/**
* Use charges within a radius. Includes character inventory.
* @param what itype_id of item using charges
* @param qty Number of charges
* @param radius Radius from the character. Use -1 to use from character inventory only.
* @param filter Filter
* @return List of items used
*/
std::list<item> use_charges( const itype_id &what, int qty, int radius,
const std::function<bool( const item & )> &filter = return_true<item> );

bool has_fire( int quantity ) const;
void use_fire( int quantity );
Expand Down Expand Up @@ -2401,6 +2417,13 @@ class Character : public Creature, public visitable<Character>
bool has_morale_to_read() const;
bool has_morale_to_craft() const;
const inventory &crafting_inventory( bool clear_path );
/**
* Returns items that can be used to craft with. Always includes character inventory.
* @param src_pos Character position.
* @param radius Radius from src_pos. -1 to return items in character inventory only.
* @param clear_path True to select only items within view. False to select all within the radius.
* @returns Craftable inventory items found.
* */
const inventory &crafting_inventory( const tripoint &src_pos = tripoint_zero,
int radius = PICKUP_RANGE, bool clear_path = true );
void invalidate_crafting_inventory();
Expand Down
77 changes: 56 additions & 21 deletions src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,13 +543,18 @@ const inventory &Character::crafting_inventory( const tripoint &src_pos, int rad
if( src_pos == tripoint_zero ) {
inv_pos = pos();
}
static int radius_mem = radius;
if( cached_moves == moves
&& radius_mem == radius
&& cached_time == calendar::turn
&& cached_position == inv_pos ) {
return *cached_crafting_inventory;
}
radius_mem = radius;
cached_crafting_inventory->clear();
cached_crafting_inventory->form_from_map( inv_pos, radius, this, false, clear_path );
if( radius >= 0 ) {
cached_crafting_inventory->form_from_map( inv_pos, radius, this, false, clear_path );
}

for( const item_location &it : all_items_loc() ) {
// can't craft with containers that have items in them
Expand Down Expand Up @@ -1793,19 +1798,24 @@ Character::select_tool_component( const std::vector<tool_comp> &tools, int batch
bool found_nocharge = false;
std::vector<tool_comp> player_has;
std::vector<tool_comp> map_has;
std::vector<tool_comp> both_has;
// Use charges of any tools that require charges used
for( auto it = tools.begin(); it != tools.end() && !found_nocharge; ++it ) {
itype_id type = it->type;
if( it->count > 0 ) {
const int count = calc_charges( *it );
if( player_inv ) {
if( has_charges( type, count ) ) {
player_has.push_back( *it );
}
if( player_inv && crafting_inventory( pos(), -1 ).has_charges( type, count ) ) {
player_has.push_back( *it );
}
if( map_inv.has_charges( type, count ) ) {
map_has.push_back( *it );
}
// Needed for tools that can have power in a different location, such as a UPS.
// Will only populate if no other options were found.
if( player_inv && crafting_inventory().has_charges( type, count )
&& player_has.size() + map_has.size() == 0 ) {
both_has.push_back( *it );
}
} else if( ( player_inv && has_amount( type, 1 ) ) || map_inv.has_tools( type, 1 ) ) {
selected.comp = *it;
found_nocharge = true;
Expand All @@ -1816,21 +1826,16 @@ Character::select_tool_component( const std::vector<tool_comp> &tools, int batch
return selected; // Default to using a tool that doesn't require charges
}

if( player_has.size() + map_has.size() == 1 ) {
if( map_has.empty() ) {
selected.use_from = usage_from::player;
selected.comp = player_has[0];
} else {
if( ( both_has.size() + player_has.size() + map_has.size() == 1 ) || is_npc() ) {
if( !both_has.empty() ) {
selected.use_from = usage_from::both;
selected.comp = both_has[0];
} else if( !map_has.empty() ) {
selected.use_from = usage_from::map;
selected.comp = map_has[0];
}
} else if( is_npc() ) {
if( !player_has.empty() ) {
} else if( !player_has.empty() ) {
selected.use_from = usage_from::player;
selected.comp = player_has[0];
} else if( !map_has.empty() ) {
selected.use_from = usage_from::map;
selected.comp = map_has[0];
} else {
selected.use_from = usage_from::none;
return selected;
Expand Down Expand Up @@ -1861,6 +1866,18 @@ Character::select_tool_component( const std::vector<tool_comp> &tools, int batch
tmenu.addentry( item::nname( player_ha.type ) );
}
}
for( auto &both_ha : both_has ) {
if( item::find_type( both_ha.type )->maximum_charges() > 1 ) {
const int charge_count = calc_charges( both_ha );
std::string tmpStr = string_format( _( "%s (%d/%d charges nearby or on person)" ),
item::nname( both_ha.type ), charge_count,
charges_of( both_ha.type ) );
tmenu.addentry( tmpStr );
} else {
std::string tmpStr = item::nname( both_ha.type ) + _( " (at hand)" );
tmenu.addentry( tmpStr );
}
}

if( tmenu.entries.empty() ) { // This SHOULD only happen if cooking with a fire,
selected.use_from = usage_from::none;
Expand All @@ -1873,7 +1890,8 @@ Character::select_tool_component( const std::vector<tool_comp> &tools, int batch
tmenu.title = _( "Use which tool?" );
tmenu.query();

if( tmenu.ret < 0 || static_cast<size_t>( tmenu.ret ) >= map_has.size() + player_has.size() ) {
if( tmenu.ret < 0 || static_cast<size_t>( tmenu.ret ) >= map_has.size()
+ player_has.size() + both_has.size() ) {
selected.use_from = usage_from::cancel;
return selected;
}
Expand All @@ -1882,10 +1900,14 @@ Character::select_tool_component( const std::vector<tool_comp> &tools, int batch
if( uselection < map_has.size() ) {
selected.use_from = usage_from::map;
selected.comp = map_has[uselection];
} else {
} else if( uselection < map_has.size() + player_has.size() ) {
uselection -= map_has.size();
selected.use_from = usage_from::player;
selected.comp = player_has[uselection];
} else {
uselection -= map_has.size() + player_has.size();
selected.use_from = usage_from::both;
selected.comp = both_has[uselection];
}
}

Expand Down Expand Up @@ -1958,6 +1980,14 @@ bool Character::craft_consume_tools( item &craft, int multiplier, bool start_cra
}
break;
case usage_from::both:
if( !( crafting_inventory() ).has_charges( type, count ) ) {
add_msg_player_or_npc(
_( "You have insufficient %s charges and can't continue crafting" ),
_( "<npcname> has insufficient %s charges and can't continue crafting" ),
item::nname( type ) );
craft.set_tools_to_continue( false );
return false;
}
case usage_from::none:
case usage_from::cancel:
case usage_from::num_usages_from:
Expand Down Expand Up @@ -1997,11 +2027,16 @@ void Character::consume_tools( map &m, const comp_selection<tool_comp> &tool, in

const itype *tmp = item::find_type( tool.comp.type );
int quantity = tool.comp.count * batch * tmp->charge_factor();
if( tool.use_from & usage_from::player ) {
if( tool.use_from == usage_from::both ) {
use_charges( tool.comp.type, quantity, radius );
} else if( tool.use_from == usage_from::player ) {
use_charges( tool.comp.type, quantity );
}
if( tool.use_from & usage_from::map ) {
} else if( tool.use_from == usage_from::map ) {
m.use_charges( origin, radius, tool.comp.type, quantity, return_true<item>, bcp );
// Map::use_charges() does not handle UPS charges.
if( quantity > 0 ) {
use_charges( tool.comp.type, quantity, radius );
}
}

// else, usage_from::none (or usage_from::cancel), so we don't use up any tools;
Expand Down

0 comments on commit 8cae58b

Please sign in to comment.