Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update first pass component selection to avoid poison #70826

Merged
merged 6 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1777,7 +1777,7 @@ static bool construction_activity( Character &you, const zone_data * /*zone*/,
comp_selection<item_comp> sel;
sel.use_from = usage_from::both;
sel.comp = comp;
std::list<item> empty_consumed = you.consume_items( sel, 1, is_empty_crafting_component );
std::list<item> empty_consumed = you.consume_items( sel, 1, is_preferred_crafting_component );

int left_to_consume = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/basecamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ void basecamp_action_components::consume_components()
}
for( const comp_selection<item_comp> &sel : item_selections_ ) {
std::list<item> empty_consumed = player_character.consume_items( target_map, sel, batch_size_,
is_empty_crafting_component, src );
is_preferred_crafting_component, src );
int left_to_consume = 0;

if( !empty_consumed.empty() && empty_consumed.front().count_by_charges() ) {
Expand Down
2 changes: 1 addition & 1 deletion src/construction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ void place_construction( std::vector<construction_group_str_id> const &groups )
sel.use_from = usage_from::both;
sel.comp = comp;
std::list<item> empty_consumed = player_character.consume_items( sel, 1,
is_empty_crafting_component );
is_preferred_crafting_component );

int left_to_consume = 0;

Expand Down
6 changes: 3 additions & 3 deletions src/craft_command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,16 @@ bool craft_command::continue_prompt_liquids( const std::function<bool( const ite
static std::list<item> sane_consume_items( const comp_selection<item_comp> &it, Character *crafter,
int batch, const std::function<bool( const item & )> &filter )
{
std::function<bool( const item & )> empty_container_filter = [&filter]( const item & it ) {
return it.is_container_empty() && filter( it );
std::function<bool( const item & )> preferred_component_filter = [&filter]( const item & it ) {
return is_preferred_component( it ) && filter( it );
};
map &m = get_map();
const std::vector<pocket_data> it_pkt = it.comp.type->pockets;
if( ( item::count_by_charges( it.comp.type ) && it.comp.count > 0 ) ||
!std::any_of( it_pkt.begin(), it_pkt.end(), []( const pocket_data & p ) {
return p.type == pocket_type::CONTAINER && p.watertight;
} ) ) {
std::list<item> empty_consumed = crafter->consume_items( it, batch, empty_container_filter );
std::list<item> empty_consumed = crafter->consume_items( it, batch, preferred_component_filter );
int left_to_consume = 0;

if( !empty_consumed.empty() && empty_consumed.front().count_by_charges() ) {
Expand Down
92 changes: 48 additions & 44 deletions src/crafting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,10 @@ comp_selection<item_comp> Character::select_item_component( const std::vector<it
const std::function<bool( const item & )> &filter, bool player_inv, bool npc_query,
const recipe *rec )
{
std::function<bool( const item & )> preferred_component_filter = [&filter]( const item & it ) {
return is_preferred_component( it ) && filter( it );
};

Character &player_character = get_player_character();
std::vector<std::pair<item_comp, std::optional<nc_color>>> player_has;
std::vector<std::pair<item_comp, std::optional<nc_color>>> map_has;
Expand All @@ -1721,7 +1725,7 @@ comp_selection<item_comp> Character::select_item_component( const std::vector<it
int count = ( component.count > 0 ) ? component.count * batch : std::abs( component.count );

if( item::count_by_charges( type ) && count > 0 ) {
int map_charges = map_inv.charges_of( type, INT_MAX, filter );
int map_charges = map_inv.charges_of( type, INT_MAX, preferred_component_filter );

// If map has infinite charges, just use them
if( map_charges == item::INFINITE_CHARGES ) {
Expand All @@ -1730,20 +1734,39 @@ comp_selection<item_comp> Character::select_item_component( const std::vector<it
return selected;
}
if( player_inv ) {
int player_charges = charges_of( type, INT_MAX, filter );
bool found = false;
int player_charges = charges_of( type, INT_MAX, preferred_component_filter );
if( player_charges >= count ) {
player_has.emplace_back( component, std::nullopt );
found = true;
}
if( map_charges >= count ) {
} else if( map_charges >= count ) {
map_has.emplace_back( component, std::nullopt );
found = true;
}
if( !found && player_charges + map_charges >= count ) {
mixed.emplace_back( component, std::nullopt );
} else {
if( player_charges + map_charges >= count ) {
mixed.emplace_back( component, std::nullopt );
} else {
bool found = false;
player_charges = charges_of( type, INT_MAX, filter );

if( player_charges >= count ) {
player_has.emplace_back( component, std::nullopt );
found = true;
} else {
map_charges = map_inv.charges_of( type, INT_MAX, filter );

if( map_charges >= count ) {
map_has.emplace_back( component, std::nullopt );
found = true;
}
}

if( !found && player_charges + map_charges >= count ) {
mixed.emplace_back( component, std::nullopt );
}
}
}

} else {
map_charges = map_inv.charges_of( type, INT_MAX, filter );

if( map_charges >= count ) {
map_has.emplace_back( component, std::nullopt );
}
Expand All @@ -1752,42 +1775,23 @@ comp_selection<item_comp> Character::select_item_component( const std::vector<it

// Can't use pseudo items as components
if( player_inv ) {
bool found = false;
const item item_sought( type );
if( ( item_sought.is_software() && count_softwares( type ) > 0 ) ||
has_amount( type, count, false, filter ) ) {
std::optional<nc_color> colr = std::nullopt;
if( !has_amount( type, count, false, [&filter]( const item & it ) {
return filter( it ) && ( it.is_container_empty() || !it.is_watertight_container() );
} ) ) {
colr = c_magenta;
}
player_has.emplace_back( component, colr );
found = true;
}
if( map_inv.has_components( type, count, filter ) ) {
std::optional<nc_color> colr = std::nullopt;
if( !map_inv.has_components( type, count, [&filter]( const item & it ) {
return filter( it ) && ( it.is_container_empty() || !it.is_watertight_container() );
} ) ) {
colr = c_magenta;
}
map_has.emplace_back( component, colr );
found = true;
}
if( !found &&
amount_of( type, false, std::numeric_limits<int>::max(), filter ) +
map_inv.amount_of( type, false, std::numeric_limits<int>::max(), filter ) >= count ) {
std::optional<nc_color> colr = std::nullopt;
if( amount_of( type, false, std::numeric_limits<int>::max(), [&filter]( const item & it ) {
return filter( it ) && ( it.is_container_empty() || !it.is_watertight_container() );
} ) + map_inv.amount_of( type, false,
std::numeric_limits<int>::max(), [&filter]( const item & it ) {
return filter( it ) && ( it.is_container_empty() || !it.is_watertight_container() );
} ) < count ) {
colr = c_magenta;
}
mixed.emplace_back( component, colr );
has_amount( type, count, false, preferred_component_filter ) ) {
player_has.emplace_back( component, std::nullopt );
} else if( map_inv.has_components( type, count, preferred_component_filter ) ) {
map_has.emplace_back( component, std::nullopt );
} else if( amount_of( type, false, std::numeric_limits<int>::max(), preferred_component_filter ) +
map_inv.amount_of( type, false, std::numeric_limits<int>::max(),
preferred_component_filter ) >= count ) {
mixed.emplace_back( component, std::nullopt );
} else if( has_amount( type, count, false, filter ) ) {
player_has.emplace_back( component, c_magenta );
} else if( map_inv.has_components( type, count, filter ) ) {
map_has.emplace_back( component, c_magenta );
} else if( amount_of( type, false, std::numeric_limits<int>::max(), filter ) +
map_inv.amount_of( type, false, std::numeric_limits<int>::max(), filter ) >= count ) {
mixed.emplace_back( component, c_magenta );
}
} else {
if( map_inv.has_components( type, count, filter ) ) {
Expand Down
19 changes: 19 additions & 0 deletions src/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,25 @@ bool inventory::must_use_liq_container( const itype_id &id, int to_use ) const
return leftover < 0 && leftover * -1 <= total - iter->second;
}

bool inventory::must_use_hallu_poison( const itype_id &id, int to_use ) const
{
const int total = count_item( id );
int bad = 0;
for( const std::list<item> &item_list : items ) {
for( const item &it : item_list ) {
if( it.typeId() == id && ( it.has_flag( flag_HIDDEN_POISON ) ||
it.has_flag( flag_HIDDEN_HALLU ) ) ) {
if( it.count_by_charges() ) {
bad += it.charges;
} else {
bad += it.count();
}
}
}
}
return total - bad < to_use;
}

void inventory::replace_liq_container_count( const std::map<itype_id, int> &newmap, bool use_max )
{
for( const auto &it : newmap ) {
Expand Down
1 change: 1 addition & 0 deletions src/inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class inventory : public visitable

// specifically used to for displaying non-empty liquid container color in crafting screen
bool must_use_liq_container( const itype_id &id, int to_use ) const;
bool must_use_hallu_poison( const itype_id &id, int to_use ) const;
void update_liq_container_count( const itype_id &id, int count );
void replace_liq_container_count( const std::map<itype_id, int> &newmap, bool use_max = false );

Expand Down
11 changes: 11 additions & 0 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15112,3 +15112,14 @@ void item::combine( const item_contents &read_input, bool convert )
{
contents.combine( read_input, convert );
}

bool is_preferred_component( const item &component )
{
return component.is_container_empty() && !component.has_flag( flag_HIDDEN_POISON ) &&
!component.has_flag( flag_HIDDEN_HALLU );
}

bool is_preferred_crafting_component( const item &component )
{
return is_preferred_component( component ) && is_crafting_component( component );
}
10 changes: 6 additions & 4 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -3229,12 +3229,14 @@ inline bool is_crafting_component( const item &component )
!component.is_filthy();
}

/**
* Filter for crafting components first pass searches excluding undesirable properties.
*/
bool is_preferred_component( const item &component );

/**
* Filter for empty crafting components first pass searches
*/
inline bool is_empty_crafting_component( const item &component )
{
return component.is_container_empty() && is_crafting_component( component );
}
bool is_preferred_crafting_component( const item &component );

#endif // CATA_SRC_ITEM_H
3 changes: 3 additions & 0 deletions src/requirements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,9 @@ nc_color item_comp::get_color( bool has_one, const read_only_visitable &crafting
} ) && inv != nullptr && inv->must_use_liq_container( type, count * batch ) ) {
return c_magenta;
}
if( inv != nullptr && inv->must_use_hallu_poison( type, count * batch ) ) {
return c_magenta;
}
// Will use favorited component
if( !has( crafting_inv, [&filter]( const item & it ) {
return filter( it ) && !it.is_favorite;
Expand Down
Loading