Skip to content

Commit

Permalink
Use new deduped_requirements_data in recipes
Browse files Browse the repository at this point in the history
Each recipe now has a deduped_requirements() in addition to its
requirements, now accessed via simple_requirements().

Each caller has been ported to one or the other as appropriate.

Refactor craftability checks so that the "only needs 5% of charge"
property can now be specified via a flag, to obviate the need to
reconstruct an entire requirements object just for that change.

Limited in-game testing is promising so far.
  • Loading branch information
jbytheway committed Jan 2, 2020
1 parent ac13aa6 commit 0427acf
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 107 deletions.
14 changes: 8 additions & 6 deletions src/basecamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ std::string basecamp::om_upgrade_description( const std::string &bldg, bool trun

std::vector<std::string> component_print_buffer;
const int pane = FULL_SCREEN_WIDTH;
const auto tools = making.requirements().get_folded_tools_list( pane, c_white, _inv, 1 );
const auto comps = making.requirements().get_folded_components_list( pane, c_white, _inv,
const auto tools = making.simple_requirements().get_folded_tools_list( pane, c_white, _inv, 1 );
const auto comps = making.simple_requirements().get_folded_components_list( pane, c_white, _inv,
making.get_component_filter(), 1 );
component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() );
component_print_buffer.insert( component_print_buffer.end(), comps.begin(), comps.end() );
Expand Down Expand Up @@ -344,7 +344,7 @@ std::vector<basecamp_upgrade> basecamp::available_upgrades( const point &dir )
basecamp_upgrade data;
data.bldg = bldg;
data.name = recp.blueprint_name();
const auto &reqs = recp.requirements();
const auto &reqs = recp.deduped_requirements();
data.avail = reqs.can_make_with_inventory( _inv, recp.get_component_filter(), 1 );
data.in_progress = in_progress;
ret_data.emplace_back( data );
Expand Down Expand Up @@ -582,11 +582,13 @@ std::list<item> basecamp::use_charges( const itype_id &fake_id, int &quantity )
void basecamp::consume_components( map &target_map, const recipe &making, int batch_size )
{
const tripoint &origin = target_map.getlocal( get_dumping_spot() );
const auto &req = making.requirements();
auto filter = is_crafting_component;
const requirement_data &req =
making.deduped_requirements().select_alternative( g->u, _inv, filter, batch_size );
for( const auto &it : req.get_components() ) {
g->u.consume_items( target_map, g->u.select_item_component( it, batch_size, _inv,
true, is_crafting_component, !by_radio ), batch_size,
is_crafting_component, origin, range );
true, filter, !by_radio ), batch_size,
filter, origin, range );
}
// this may consume pseudo-resources from fake items
for( const auto &it : req.get_tools() ) {
Expand Down
2 changes: 1 addition & 1 deletion src/consumption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ std::pair<nutrients, nutrients> player::compute_nutrient_range(
our_extra_flags.insert( "COOKED" );
}

const requirement_data requirements = rec.requirements();
const requirement_data requirements = rec.simple_requirements();
const requirement_data::alter_item_comp_vector &component_requirements =
requirements.get_components();

Expand Down
3 changes: 2 additions & 1 deletion src/craft_command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,9 @@ void craft_command::execute( const tripoint &new_loc )
}

item_selections.clear();
const auto needs = rec->requirements();
const auto filter = rec->get_component_filter( flags );
const requirement_data &needs = rec->deduped_requirements().select_alternative(
*crafter, filter, batch_size, craft_flags::start_only );

for( const auto &it : needs.get_components() ) {
comp_selection<item_comp> is =
Expand Down
60 changes: 16 additions & 44 deletions src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ bool player::making_would_work( const recipe_id &id_to_make, int batch_size )
if( !can_make( &making, batch_size ) ) {
std::string buffer = _( "You can no longer make that craft!" );
buffer += "\n";
buffer += making.requirements().list_missing();
buffer += making.simple_requirements().list_missing();
popup( buffer, PF_NONE );
return false;
}
Expand Down Expand Up @@ -472,14 +472,14 @@ std::vector<const item *> player::get_eligible_containers_for_crafting() const

bool player::can_make( const recipe *r, int batch_size )
{
const inventory &crafting_inv = crafting_inventory();
inventory crafting_inv = crafting_inventory();

if( has_recipe( r, crafting_inv, get_crafting_helpers() ) < 0 ) {
return false;
}

return r->requirements().can_make_with_inventory( crafting_inv, r->get_component_filter(),
batch_size );
return r->deduped_requirements().can_make_with_inventory(
crafting_inv, r->get_component_filter(), batch_size );
}

bool player::can_start_craft( const recipe *rec, recipe_filter_flags flags, int batch_size )
Expand All @@ -488,45 +488,9 @@ bool player::can_start_craft( const recipe *rec, recipe_filter_flags flags, int
return false;
}

const std::vector<std::vector<tool_comp>> &tool_reqs = rec->requirements().get_tools();

// For tools adjust the reqired charges
std::vector<std::vector<tool_comp>> adjusted_tool_reqs;
for( const std::vector<tool_comp> &alternatives : tool_reqs ) {
std::vector<tool_comp> adjusted_alternatives;
for( const tool_comp &alternative : alternatives ) {
tool_comp adjusted_alternative = alternative;
if( adjusted_alternative.count > 0 ) {
adjusted_alternative.count *= batch_size;
// Only for the first 5% progress
adjusted_alternative.count = std::max( adjusted_alternative.count / 20, 1 );
}
adjusted_alternatives.push_back( adjusted_alternative );
}
adjusted_tool_reqs.push_back( adjusted_alternatives );
}

const std::vector<std::vector<item_comp>> &comp_reqs = rec->requirements().get_components();

// For components we need to multiply by batch size to stay even with tools
std::vector<std::vector<item_comp>> adjusted_comp_reqs;
for( const std::vector<item_comp> &alternatives : comp_reqs ) {
std::vector<item_comp> adjusted_alternatives;
for( const item_comp &alternative : alternatives ) {
item_comp adjusted_alternative = alternative;
adjusted_alternative.count *= batch_size;
adjusted_alternatives.push_back( adjusted_alternative );
}
adjusted_comp_reqs.push_back( adjusted_alternatives );
}

// Qualities don't need adjustment
const requirement_data start_reqs( adjusted_tool_reqs,
rec->requirements().get_qualities(),
adjusted_comp_reqs );

return start_reqs.can_make_with_inventory( crafting_inventory(),
rec->get_component_filter( flags ) );
inventory inv = crafting_inventory();
return rec->deduped_requirements().can_make_with_inventory(
inv, rec->get_component_filter( flags ), batch_size, craft_flags::start_only );
}

const inventory &player::crafting_inventory( bool clear_path )
Expand Down Expand Up @@ -1306,7 +1270,7 @@ bool player::can_continue_craft( item &craft )

if( !craft.has_tools_to_continue() ) {

const std::vector<std::vector<tool_comp>> &tool_reqs = rec.requirements().get_tools();
const std::vector<std::vector<tool_comp>> &tool_reqs = rec.simple_requirements().get_tools();
const int batch_size = craft.charges;

std::vector<std::vector<tool_comp>> adjusted_tool_reqs;
Expand Down Expand Up @@ -1357,6 +1321,14 @@ bool player::can_continue_craft( item &craft )

return true;
}
const requirement_data &player::select_requirements(
const std::vector<const requirement_data *> &alternatives, int /*batch*/, const inventory &,
const std::function<bool( const item & )> &/*filter*/ ) const
{
assert( !alternatives.empty() );
// TODO: when this is the avatar, offer the choice to the player
return *alternatives.front();
}

/* selection of component if a recipe requirement has multiple options (e.g. 'duct tap' or 'welder') */
comp_selection<item_comp> player::select_item_component( const std::vector<item_comp> &components,
Expand Down
10 changes: 10 additions & 0 deletions src/crafting.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ class item;
class player;
class recipe;

enum class craft_flags : int {
none = 0,
start_only = 1, // Only require 5% (plus remainder) of tool charges
};

inline constexpr craft_flags operator&( craft_flags l, craft_flags r )
{
return static_cast<craft_flags>( static_cast<unsigned>( l ) & static_cast<unsigned>( r ) );
}

// removes any (removable) ammo from the item and stores it in the
// players inventory.
void remove_ammo( item &dis_item, player &p );
Expand Down
4 changes: 2 additions & 2 deletions src/crafting_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ const recipe *select_crafting_recipe( int &batch_size )
int count = batch ? line + 1 : 1; // batch size
nc_color col = available[ line ].color();

const auto &req = current[ line ]->requirements();
const auto &req = current[ line ]->simple_requirements();

draw_can_craft_indicator( w_head, 0, *current[line] );
wrefresh( w_head );
Expand Down Expand Up @@ -851,7 +851,7 @@ std::string peek_related_recipe( const recipe *current, const recipe_subset &ava
{
// current recipe components
std::vector<std::pair<itype_id, std::string>> related_components;
const requirement_data &req = current->requirements();
const requirement_data &req = current->simple_requirements();
for( const std::vector<item_comp> &comp_list : req.get_components() ) {
for( const item_comp &a : comp_list ) {
related_components.push_back( { a.type, item::nname( a.type, 1 ) } );
Expand Down
22 changes: 12 additions & 10 deletions src/faction_camp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,8 @@ void basecamp::add_available_recipes( mission_data &mission_key, const point &di
const std::string &title_e = dir_abbr + recipe_data.second;
const std::string &entry = craft_description( recipe_data.first );
const recipe &recp = recipe_data.first.obj();
bool craftable = recp.requirements().can_make_with_inventory( _inv,
recp.get_component_filter() );
bool craftable = recp.deduped_requirements().can_make_with_inventory(
_inv, recp.get_component_filter() );
mission_key.add_start( id, title_e, dir, entry, craftable );
}
}
Expand Down Expand Up @@ -1533,7 +1533,8 @@ void basecamp::start_upgrade( const std::string &bldg, const point &dir,
{
const recipe &making = recipe_id( bldg ).obj();
//Stop upgrade if you don't have materials
if( making.requirements().can_make_with_inventory( _inv, making.get_component_filter(), 1 ) ) {
if( making.deduped_requirements().can_make_with_inventory(
_inv, making.get_component_filter() ) ) {
bool must_feed = bldg != "faction_base_camp_1";

time_duration work_days = base_camps::to_workdays( making.batch_duration() );
Expand Down Expand Up @@ -1939,7 +1940,7 @@ void basecamp::start_fortifications( std::string &bldg_exp )
if( !query_yn( _( "Trip Estimate:\n%s" ), camp_trip_description( total_time, build_time,
travel_time, dist, trips, need_food ) ) ) {
return;
} else if( !making.requirements().can_make_with_inventory( _inv,
} else if( !making.deduped_requirements().can_make_with_inventory( _inv,
making.get_component_filter(), ( fortify_om.size() * 2 ) - 2 ) ) {
popup( _( "You don't have the material to build the fortification." ) );
return;
Expand Down Expand Up @@ -1999,8 +2000,8 @@ void basecamp::start_crafting( const std::string &cur_id, const point &cur_dir,
if( it != recipes.end() ) {
const recipe &making = it->first.obj();

if( !making.requirements().can_make_with_inventory( _inv,
making.get_component_filter(), 1 ) ) {
if( !making.deduped_requirements().can_make_with_inventory(
_inv, making.get_component_filter() ) ) {
popup( _( "You don't have the materials to craft that" ) );
return;
}
Expand Down Expand Up @@ -2808,8 +2809,8 @@ int basecamp::recipe_batch_max( const recipe &making ) const
time_duration work_days = base_camps::to_workdays( making.batch_duration(
max_batch + batch_size ) );
int food_req = time_to_food( work_days );
bool can_make = making.requirements().can_make_with_inventory( _inv,
making.get_component_filter(), max_batch + batch_size );
bool can_make = making.deduped_requirements().can_make_with_inventory(
_inv, making.get_component_filter(), max_batch + batch_size );
if( can_make && camp_food_supply() > food_req ) {
max_batch += batch_size;
} else {
Expand Down Expand Up @@ -3429,8 +3430,9 @@ std::string basecamp::craft_description( const recipe_id &itm )

std::vector<std::string> component_print_buffer;
int pane = FULL_SCREEN_WIDTH;
auto tools = making.requirements().get_folded_tools_list( pane, c_white, _inv, 1 );
auto comps = making.requirements().get_folded_components_list( pane, c_white, _inv,
const requirement_data &req = making.simple_requirements();
auto tools = req.get_folded_tools_list( pane, c_white, _inv, 1 );
auto comps = req.get_folded_components_list( pane, c_white, _inv,
making.get_component_filter(), 1 );

component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() );
Expand Down
3 changes: 2 additions & 1 deletion src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3234,7 +3234,8 @@ void item::final_info( std::vector<iteminfo> &info, const iteminfo_query *parts,
} else {
const std::string recipes = enumerate_as_string( known_recipes.begin(), known_recipes.end(),
[ &inv ]( const recipe * r ) {
if( r->requirements().can_make_with_inventory( inv, r->get_component_filter() ) ) {
if( r->deduped_requirements().can_make_with_inventory(
inv, r->get_component_filter() ) ) {
return r->result_name();
} else {
return string_format( "<dark>%s</dark>", r->result_name() );
Expand Down
10 changes: 6 additions & 4 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8684,8 +8684,8 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos )
for( const auto &r : g->u.get_learned_recipes().in_category( "CC_FOOD" ) ) {
if( multicooked_subcats.count( r->subcategory ) > 0 ) {
dishes.push_back( r );
const bool can_make = r->requirements().can_make_with_inventory( crafting_inv,
r->get_component_filter() );
const bool can_make = r->deduped_requirements().can_make_with_inventory(
crafting_inv, r->get_component_filter() );

dmenu.addentry( counter++, can_make, -1, r->result_name() );
}
Expand Down Expand Up @@ -8717,9 +8717,11 @@ int iuse::multicooker( player *p, item *it, bool t, const tripoint &pos )
return 0;
}

auto reqs = meal->requirements();
const auto filter = is_crafting_component;
const requirement_data &reqs =
meal->deduped_requirements().select_alternative( *p, filter );
for( auto it : reqs.get_components() ) {
p->consume_items( it, 1, is_crafting_component );
p->consume_items( it, 1, filter );
}

it->set_var( "RECIPE", meal->ident().str() );
Expand Down
3 changes: 3 additions & 0 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,9 @@ class player : public Character
const inventory &crafting_inventory( bool clear_path );
const inventory &crafting_inventory( const tripoint &src_pos = tripoint_zero,
int radius = PICKUP_RANGE, bool clear_path = true );
const requirement_data &select_requirements(
const std::vector<const requirement_data *> &, int batch, const inventory &,
const std::function<bool( const item & )> &filter ) const;
comp_selection<item_comp>
select_item_component( const std::vector<item_comp> &components,
int batch, inventory &map_inv, bool can_cancel = false,
Expand Down
4 changes: 3 additions & 1 deletion src/recipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ void recipe::finalize()
requirements_.consolidate();
}

deduped_requirements_ = deduped_requirement_data( requirements_, ident() );

if( contained && container == "null" ) {
container = item::find_type( result_ )->default_container.value_or( "null" );
}
Expand Down Expand Up @@ -613,7 +615,7 @@ bool recipe::hot_result() const
//
// TODO: Make this less of a hack
if( create_result().is_food() ) {
const requirement_data::alter_tool_comp_vector &tool_lists = requirements().get_tools();
const requirement_data::alter_tool_comp_vector &tool_lists = simple_requirements().get_tools();
for( const std::vector<tool_comp> &tools : tool_lists ) {
for( const tool_comp &t : tools ) {
if( t.type == "hotplate" ) {
Expand Down
21 changes: 18 additions & 3 deletions src/recipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,19 @@ class recipe
int time = 0; // in movement points (100 per turn)
int difficulty = 0;

/** Fetch combined requirement data (inline and via "using" syntax) */
const requirement_data &requirements() const {
/** Fetch combined requirement data (inline and via "using" syntax).
*
* Use simple_requirements() for player display or when you just want to
* know the requirements as listed in the json files. Use
* deduped_requirements() to calculate actual craftability of a recipe. */
const requirement_data &simple_requirements() const {
return requirements_;
}

const deduped_requirement_data &deduped_requirements() const {
return deduped_requirements_;
}

const recipe_id &ident() const {
return ident_;
}
Expand All @@ -85,7 +93,11 @@ class recipe

/** If recipe can be used for disassembly fetch the combined requirements */
requirement_data disassembly_requirements() const {
return reversible ? requirements().disassembly_requirements() : requirement_data();
if( reversible ) {
return simple_requirements().disassembly_requirements();
} else {
return {};
}
}

/// @returns The name (@ref item::nname) of the resulting item (@ref result).
Expand Down Expand Up @@ -183,6 +195,9 @@ class recipe
/** Combined requirements cached when recipe finalized */
requirement_data requirements_;

/** Deduped version constructed from the above requirements_ */
deduped_requirement_data deduped_requirements_;

std::set<std::string> flags;

/** If set (zero or positive) set charges of output result for items counted by charges */
Expand Down
Loading

0 comments on commit 0427acf

Please sign in to comment.