void inventory::update_invlet( item &newit, bool assign_invlet ) { // Avoid letters that have been manually assigned to other things. if( newit.invlet && assigned_invlet.find( newit.invlet ) != assigned_invlet.end() && assigned_invlet[newit.invlet] != newit.typeId() ) { newit.invlet = '\0'; } // Remove letters that are not in the favorites cache if( newit.invlet ) { auto invlet_list_iter = invlet_cache.find( newit.typeId() ); bool found = false; if( invlet_list_iter != invlet_cache.end() ) { auto &invlet_list = invlet_list_iter->second; found = std::find( invlet_list.begin(), invlet_list.end(), newit.invlet ) != invlet_list.end(); } if( !found ) { newit.invlet = '\0'; } } // Remove letters that have been assigned to other items in the inventory if( newit.invlet ) { char tmp_invlet = newit.invlet; newit.invlet = '\0'; if( g->u.invlet_to_position( tmp_invlet ) == INT_MIN ) { newit.invlet = tmp_invlet; } } if( assign_invlet ) { // Assign a cached letter to the item if( !newit.invlet ) { newit.invlet = find_usable_cached_invlet( newit.typeId() ); } // Give the item an invlet if it has none if( !newit.invlet ) { assign_empty_invlet( newit, g->u ); } } }
std::vector<item> json_item_substitution::get_substitution( const item &it, const std::vector<trait_id> &traits ) const { auto iter = substitutions.find( it.typeId() ); std::vector<item> ret; if( iter == substitutions.end() ) { for( const item &con : it.contents ) { const auto sub = get_substitution( con, traits ); ret.insert( ret.end(), sub.begin(), sub.end() ); } return ret; } const auto sub = std::find_if( iter->second.begin(), iter->second.end(), [&traits]( const substitution & s ) { return s.trait_reqs.meets_condition( traits ); } ); if( sub == iter->second.end() ) { return ret; } const long old_amt = it.count(); for( const substitution::info &inf : sub->infos ) { item result( inf.new_item ); const long new_amt = std::max( 1l, static_cast<long>( std::round( inf.ratio * old_amt ) ) ); if( !result.count_by_charges() ) { for( long i = 0; i < new_amt; i++ ) { ret.push_back( result.in_its_container() ); } } else { result.mod_charges( -result.charges + new_amt ); while( result.charges > 0 ) { const item pushed = result.in_its_container(); ret.push_back( pushed ); result.mod_charges( pushed.contents.empty() ? -pushed.charges : -pushed.contents.back().charges ); } } } return ret; }
void inventory::assign_empty_invlet( item &it, const Character &p, const bool force ) { if( !get_option<bool>( "AUTO_INV_ASSIGN" ) ) { return; } invlets_bitset cur_inv = p.allocated_invlets(); itype_id target_type = it.typeId(); for( auto iter : assigned_invlet ) { if( iter.second == target_type && !cur_inv[iter.first] ) { it.invlet = iter.first; return; } } if( cur_inv.count() < inv_chars.size() ) { for( const auto &inv_char : inv_chars ) { if( assigned_invlet.count( inv_char ) ) { // don't overwrite assigned keys continue; } if( !cur_inv[inv_char] ) { it.invlet = inv_char; return; } } } if( !force ) { it.invlet = 0; return; } // No free hotkey exist, re-use some of the existing ones for( auto &elem : items ) { item &o = elem.front(); if( o.invlet != 0 ) { it.invlet = o.invlet; o.invlet = 0; return; } } debugmsg( "could not find a hotkey for %s", it.tname() ); }
// firing is the item that is fired. It may be the wielded gun, but it can also be an attached // gunmod. p is the character that is firing, this may be a pseudo-character (used by monattack/ // vehicle turrets) or a NPC. void sfx::generate_gun_sound( const player &p, const item &firing ) { end_sfx_timestamp = std::chrono::high_resolution_clock::now(); sfx_time = end_sfx_timestamp - start_sfx_timestamp; if( std::chrono::duration_cast<std::chrono::milliseconds> ( sfx_time ).count() < 80 ) { return; } const tripoint source = p.pos(); int heard_volume = get_heard_volume( source ); if( heard_volume <= 30 ) { heard_volume = 30; } itype_id weapon_id = firing.typeId(); int angle; int distance; std::string selected_sound; // this does not mean p == g->u (it could be a vehicle turret) if( g->u.pos() == source ) { angle = 0; distance = 0; selected_sound = "fire_gun"; const auto mods = firing.gunmods(); if( std::any_of( mods.begin(), mods.end(), []( const item *e ) { return e->type->gunmod->loudness < 0; } ) ) { weapon_id = "weapon_fire_suppressed"; } } else { angle = get_heard_angle( source ); distance = rl_dist( g->u.pos(), source ); if( distance <= 17 ) { selected_sound = "fire_gun"; } else { selected_sound = "fire_gun_distant"; } } play_variant_sound( selected_sound, weapon_id, heard_volume, angle, 0.8, 1.2 ); start_sfx_timestamp = std::chrono::high_resolution_clock::now(); }
item_location game_menus::inv::container_for( player &p, const item &liquid, int radius ) { const auto filter = [ &liquid ]( const item_location & location ) { if( location.where() == item_location::type::character ) { Character *character = dynamic_cast<Character *>( g->critter_at( location.position() ) ); if( character == nullptr ) { debugmsg( "Invalid location supplied to the liquid filter: no character found." ); return false; } return location->get_remaining_capacity_for_liquid( liquid, *character ) > 0; } const bool allow_buckets = location.where() == item_location::type::map; return location->get_remaining_capacity_for_liquid( liquid, allow_buckets ) > 0; }; return inv_internal( p, inventory_filter_preset( filter ), string_format( _( "Container for %s" ), liquid.display_name( liquid.charges ).c_str() ), radius, string_format( _( "You don't have a suitable container for carrying %s." ), liquid.tname().c_str() ) ); }
void set_item_inventory( item &newit ) { if( newit.made_of( LIQUID ) ) { g->handle_all_liquid( newit, PICKUP_RANGE ); } else { g->u.inv.assign_empty_invlet( newit ); // We might not have space for the item if( !g->u.can_pickVolume( newit ) ) { //Accounts for result_mult add_msg( _( "There's no room in your inventory for the %s, so you drop it." ), newit.tname().c_str() ); g->m.add_item_or_charges( g->u.pos(), newit ); } else if( !g->u.can_pickWeight( newit, !get_option<bool>( "DANGEROUS_PICKUPS" ) ) ) { add_msg( _( "The %s is too heavy to carry, so you drop it." ), newit.tname().c_str() ); g->m.add_item_or_charges( g->u.pos(), newit ); } else { newit = g->u.i_add( newit ); add_msg( m_info, "%c - %s", newit.invlet == 0 ? ' ' : newit.invlet, newit.tname().c_str() ); } } }
int Character::aim_per_time( const item& gun, int recoil ) const { int penalty = 0; // Range [0 - 10] after adjustment penalty += skill_dispersion( gun, false ) / 60; // Ranges [0 - 12] after adjustment penalty += ranged_dex_mod() / 15; // Range [0 - 10] penalty += gun.aim_speed( recoil ); // @todo consider character status effects // always improve by at least 1MOC penalty = std::max( 1, 32 - penalty ); // improvement capped by max aim level of the gun sight being used. return std::min( penalty, recoil - gun.sight_dispersion( recoil ) ); }
// technique std::vector<matec_id> player::get_all_techniques( const item &weap ) const { std::vector<matec_id> tecs; // Grab individual item techniques const auto &weapon_techs = weap.get_techniques(); tecs.insert( tecs.end(), weapon_techs.begin(), weapon_techs.end() ); // and martial art techniques const auto &style = style_selected.obj(); tecs.insert( tecs.end(), style.techniques.begin(), style.techniques.end() ); return tecs; }
pickup_answer handle_problematic_pickup( const item &it, bool &offered_swap, const std::string &explain ) { player &u = g->u; uimenu amenu; amenu.return_invalid = true; amenu.selected = 0; amenu.text = explain; offered_swap = true; // @todo Gray out if not enough hands amenu.addentry( WIELD, !u.weapon.has_flag( "NO_UNWIELD" ), 'w', _("Dispose of %s and wield %s"), u.weapon.display_name().c_str(), it.display_name().c_str() ); if( it.is_armor() ) { amenu.addentry( WEAR, u.can_wear( it ), 'W', _("Wear %s"), it.display_name().c_str() ); } if( !it.is_container_empty() && u.can_pickVolume( it.volume() ) ) { amenu.addentry( SPILL, true, 's', _("Spill %s, then pick up %s"), it.contents.front().tname().c_str(), it.display_name().c_str() ); } amenu.query(); int choice = amenu.ret; if( choice <= CANCEL || choice >= NUM_ANSWERS ) { return CANCEL; } return static_cast<pickup_answer>( choice ); }
// TODO: Move pizza scraping here. // Same for other kinds of nutrition alterations // This is used by item display, making actual nutrition available to player. int player::nutrition_for( const item &comest ) const { static const trait_id trait_CARNIVORE( "CARNIVORE" ); static const trait_id trait_GIZZARD( "GIZZARD" ); static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); static const std::string flag_CARNIVORE_OK( "CARNIVORE_OK" ); if( !comest.is_comestible() ) { return 0; } // As float to avoid rounding too many times float nutr = comest.type->comestible->nutr; if( has_trait( trait_GIZZARD ) ) { nutr *= 0.6f; } if( has_trait( trait_CARNIVORE ) && comest.has_flag( flag_CARNIVORE_OK ) && comest.has_any_flag( carnivore_blacklist ) ) { // TODO: Comment pizza scrapping nutr *= 0.5f; } const float relative_rot = comest.get_relative_rot(); // Saprophages get full nutrition from rotting food if( relative_rot > 1.0f && !has_trait( trait_SAPROPHAGE ) ) { // everyone else only gets a portion of the nutrition // Scaling linearly from 100% at just-rotten to 0 at halfway-rotten-away const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f ); nutr *= ( 1.0f - rottedness ); } // Bio-digestion gives extra nutrition if( has_bionic( bio_digestion ) ) { nutr *= 1.5f; } return ( int )nutr; }
invlet_state check_invlet( player &p, item &it, char invlet ) { if( it.invlet == '\0' ) { return NONE; } else if( it.invlet == invlet ) { if( p.inv.assigned_invlet.find( invlet ) != p.inv.assigned_invlet.end() && p.inv.assigned_invlet[invlet] == it.typeId() ) { return ASSIGNED; } else { return CACHED; } } return UNEXPECTED; }
void player_morale::set_worn( const item &it, bool worn ) { const bool just_fancy = it.has_flag( "FANCY" ); const bool super_fancy = it.has_flag( "SUPER_FANCY" ); if( just_fancy || super_fancy ) { const int sign = ( worn ) ? 1 : -1; for( int i = 0; i < num_bp; i++ ) { const auto bp = static_cast<body_part>( i ); if( it.covers( bp ) ) { covered[i] = std::max( covered[i] + sign, 0 ); } } if( super_fancy ) { super_fancy_bonus += 2 * sign; } update_stylish_bonus(); } }
/** * Determine what a funnel has filled out of game, using funnelcontainer.bday as a starting point. */ void retroactively_fill_from_funnel( item &it, const trap &tr, int startturn, int endturn, const tripoint &location ) { if( startturn > endturn || !tr.is_funnel() ) { return; } it.bday = endturn; // bday == last fill check auto data = sum_conditions( startturn, endturn, location ); // Technically 0.0 division is OK, but it will be cleaner without it if( data.rain_amount > 0 ) { const int rain = divide_roll_remainder( 1.0 / tr.funnel_turns_per_charge( data.rain_amount ), 1.0f ); it.add_rain_to_container( false, rain ); // add_msg(m_debug, "Retroactively adding %d water from turn %d to %d", rain, startturn, endturn); } if( data.acid_amount > 0 ) { const int acid = divide_roll_remainder( 1.0 / tr.funnel_turns_per_charge( data.acid_amount ), 1.0f ); it.add_rain_to_container( true, acid ); } }
void inventory::add_item(item newit, bool keep_invlet) { if (keep_invlet && !newit.invlet_is_okay()) assign_empty_invlet(newit); // Keep invlet is true, but invlet is invalid! if (newit.is_style()) return; // Styles never belong in our inventory. for (unsigned int i = 0; i < items.size(); i++) { if (items[i][0].stacks_with(newit)) { newit.invlet = items[i][0].invlet; items[i].push_back(newit); return; } else if (keep_invlet && items[i][0].invlet == newit.invlet) assign_empty_invlet(items[i][0]); } if (!newit.invlet_is_okay() || index_by_letter(newit.invlet) != -1) assign_empty_invlet(newit); std::vector<item> newstack; newstack.push_back(newit); items.push_back(newstack); }
//helper function for Pickup::pick_up //return value is amount of ammo added to quiver int Pickup::handle_quiver_insertion(item &here, bool inv_on_fail, int &moves_to_decrement, bool &picked_up) { //add ammo to quiver int quivered = here.add_ammo_to_quiver(&g->u, true); if(quivered > 0) { moves_to_decrement = 0; //moves already decremented in item::add_ammo_to_quiver() picked_up = true; return quivered; } else if (inv_on_fail) { //add to inventory instead g->u.i_add(here); picked_up = true; //display output message std::map<std::string, int> map_pickup; int charges = (here.count_by_charges()) ? here.charges : 1; map_pickup.insert(std::pair<std::string, int>(here.tname(), charges)); show_pickup_message(map_pickup); } return 0; }
bool player::feed_furnace_with( item &it ) { if( !can_feed_furnace_with( it ) ) { return false; } const int energy = get_acquirable_energy( it, rechargeable_cbm::furnace ); if( energy == 0 ) { add_msg_player_or_npc( m_info, _( "You digest your %s, but fail to acquire energy from it." ), _( "<npcname> digests their %s for energy, but fails to acquire energy from it." ), it.tname().c_str() ); } else if( power_level >= max_power_level ) { add_msg_player_or_npc( _( "You digest your %s, but you're fully powered already, so the energy is wasted." ), _( "<npcname> digests a %s for energy, they're fully powered already, so the energy is wasted." ), it.tname().c_str() ); } else { const int profitable_energy = std::min( energy, max_power_level - power_level ); add_msg_player_or_npc( m_info, ngettext( "You digest your %s and recharge %d point of energy.", "You digest your %s and recharge %d points of energy.", profitable_energy ), ngettext( "<npcname> digests a %s and recharges %d point of energy.", "<npcname> digests a %s and recharges %d points of energy.", profitable_energy ), it.tname().c_str(), profitable_energy ); charge_power( profitable_energy ); } it.charges = 0; mod_moves( -250 ); return true; }
static void move_item( player &p, item &it, int quantity, const tripoint &src, const tripoint &dest, vehicle *src_veh, int src_part ) { item leftovers = it; if( quantity != 0 && it.count_by_charges() ) { // Reinserting leftovers happens after item removal to avoid stacking issues. leftovers.charges = it.charges - quantity; if( leftovers.charges > 0 ) { it.charges = quantity; } } else { leftovers.charges = 0; } // Check that we can pick it up. if( !it.made_of_from_type( LIQUID ) ) { p.mod_moves( -move_cost( it, src, dest ) ); put_into_vehicle_or_drop( p, item_drop_reason::deliberate, { it }, dest ); // Remove from map or vehicle. if( src_veh ) { src_veh->remove_item( src_part, &it ); } else { g->m.i_rem( src, &it ); } } // If we didn't pick up a whole stack, put the remainder back where it came from. if( leftovers.charges > 0 ) { if( src_veh ) { if( !src_veh->add_item( src_part, leftovers ) ) { debugmsg( "SortLoot: Source vehicle failed to receive leftover charges." ); } } else { g->m.add_item_or_charges( src, leftovers ); } } }
double trap::funnel_turns_per_charge( double rain_depth_mm_per_hour ) const { // 1mm rain on 1m^2 == 1 liter water == 1000ml // 1 liter == 4 volume // 1 volume == 250ml: containers // 1 volume == 200ml: water // How many turns should it take for us to collect 1 charge of rainwater? // "..." if ( rain_depth_mm_per_hour == 0 ) { return 0; } const item water(item_controller->find_template("water"), 0); const double charge_ml = (double) (water.weight()) / water.charges; // 250ml const double PI = 3.14159265358979f; const double surface_area_mm2 = PI * (funnel_radius_mm * funnel_radius_mm); const double vol_mm3_per_hour = surface_area_mm2 * rain_depth_mm_per_hour; const double vol_mm3_per_turn = vol_mm3_per_hour / 600; const double ml_to_mm3 = 1000; const double turns_per_charge = (charge_ml * ml_to_mm3) / vol_mm3_per_turn; return turns_per_charge;// / rain_depth_mm_per_hour; }
double funnel_charges_per_turn( const double surface_area_mm2, const double rain_depth_mm_per_hour ) { // 1mm rain on 1m^2 == 1 liter water == 1000ml // 1 liter == 4 volume // 1 volume == 250ml: containers // 1 volume == 200ml: water // How many charges of water can we collect in a turn (usually <1.0)? if( rain_depth_mm_per_hour == 0.0 ) { return 0.0; } // Calculate once, because that part is expensive static const item water("water", 0); static const double charge_ml = (double) (water.weight()) / water.charges; // 250ml const double vol_mm3_per_hour = surface_area_mm2 * rain_depth_mm_per_hour; const double vol_mm3_per_turn = vol_mm3_per_hour / 600; const double ml_to_mm3 = 1000; const double charges_per_turn = vol_mm3_per_turn / (charge_ml * ml_to_mm3); return charges_per_turn; }
/** * Determine what a funnel has filled out of game, using funnelcontainer.bday as a starting point. */ void retroactively_fill_from_funnel( item &it, const trap &tr, const calendar &endturn, const tripoint &location ) { const calendar startturn = calendar( it.bday > 0 ? it.bday - 1 : 0 ); if ( startturn > endturn || !tr.is_funnel() ) { return; } it.bday = endturn; // bday == last fill check auto data = sum_conditions( startturn, endturn, location ); // Technically 0.0 division is OK, but it will be cleaner without it if( data.rain_amount > 0 ) { const int rain = 1.0 / tr.funnel_turns_per_charge( data.rain_amount ); it.add_rain_to_container( false, rain ); } if( data.acid_amount > 0 ) { const int acid = 1.0 / tr.funnel_turns_per_charge( data.acid_amount ); it.add_rain_to_container( true, acid ); } }
// This function keeps the invlet cache updated when a new item is added. void inventory::update_cache_with_item( item &newit ) { // This function does two things: // 1. It adds newit's invlet to the list of favorite letters for newit's item type. // 2. It removes newit's invlet from the list of favorite letters for all other item types. // no invlet item, just return. // TODO: Should we instead remember that the invlet was cleared? if( newit.invlet == 0 ) { return; } invlet_cache.set( newit.invlet, newit.typeId() ); }
bool vehicle_part::can_reload( const item &obj ) const { // first check part is not destroyed and can contain ammo if( !is_fuel_store() ) { return false; } if( !obj.is_null() ) { const itype_id obj_type = obj.typeId(); if( is_reactor() ) { return base.is_reloadable_with( obj_type ); } // forbid filling tanks with solids or non-material things if( is_tank() && ( obj.made_of( SOLID ) || obj.made_of( PNULL ) ) ) { return false; } // forbid putting liquids, gasses, and plasma in things that aren't tanks else if( !obj.made_of( SOLID ) && !is_tank() ) { return false; } // prevent mixing of different ammo if( ammo_current() != "null" && ammo_current() != obj_type ) { return false; } // For storage with set type, prevent filling with different types if( info().fuel_type != fuel_type_none && info().fuel_type != obj_type ) { return false; } // don't fill magazines with inappropriate fuel if( !is_tank() && !base.is_reloadable_with( obj_type ) ) { return false; } } return ammo_remaining() < ammo_capacity(); }
int Pickup::cost_to_move_item( const Character &who, const item &it ) { // Do not involve inventory capacity, it's not like you put it in backpack int ret = 50; if( who.is_armed() ) { // No free hand? That will cost you extra ret += 20; } // Is it too heavy? It'll take 10 moves per kg over limit ret += std::max( 0, ( it.weight() - who.weight_capacity() ) / 100_gram ); // Keep it sane - it's not a long activity return std::min( 400, ret ); }
bool player::feed_reactor_with( item &it ) { if( !can_feed_reactor_with( it ) ) { return false; } const auto iter = plut_charges.find( it.typeId() ); const int max_amount = iter != plut_charges.end() ? iter->second : 0; const int amount = std::min( get_acquirable_energy( it, rechargeable_cbm::reactor ), max_amount ); if( amount >= PLUTONIUM_CHARGES * 10 && !query_yn( _( "Thats a LOT of plutonium. Are you sure you want that much?" ) ) ) { return false; } add_msg_player_or_npc( _( "You add your %s to your reactor's tank." ), _( "<npcname> pours %s into their reactor's tank." ), it.tname().c_str() ); tank_plut += amount; // @todo Encapsulate it.charges -= 1; mod_moves( -250 ); return true; }
void inventory::update_invlet( item &newit, bool assign_invlet ) { // Avoid letters that have been manually assigned to other things. if( newit.invlet && assigned_invlet.find( newit.invlet ) != assigned_invlet.end() && assigned_invlet[newit.invlet] != newit.typeId() ) { newit.invlet = '\0'; } // Remove letters that are not in the favorites cache if( newit.invlet ) { if( !invlet_cache.contains( newit.invlet, newit.typeId() ) ) { newit.invlet = '\0'; } } // Remove letters that have been assigned to other items in the inventory if( newit.invlet ) { char tmp_invlet = newit.invlet; newit.invlet = '\0'; if( g->u.invlet_to_position( tmp_invlet ) == INT_MIN ) { newit.invlet = tmp_invlet; } } if( assign_invlet ) { // Assign a cached letter to the item if( !newit.invlet ) { newit.invlet = find_usable_cached_invlet( newit.typeId() ); } // Give the item an invlet if it has none if( !newit.invlet ) { assign_empty_invlet( newit, g->u ); } } }
void monster::init_from_item( const item &itm ) { if( itm.typeId() == "corpse" ) { const int burnt_penalty = itm.burnt; set_speed_base( static_cast<int>( get_speed_base() * 0.8 ) - ( burnt_penalty / 2 ) ); hp = static_cast<int>( hp * 0.7 ) - burnt_penalty; if( itm.damage > 0 ) { set_speed_base( speed_base / ( itm.damage + 1 ) ); hp /= itm.damage + 1; } } else { // must be a robot const int damfac = 5 - std::max<int>( 0, itm.damage ); // 5 (no damage) ... 1 (max damage) // One hp at least, everything else would be unfair (happens only to monster with *very* low hp), hp = std::max( 1, hp * damfac / 5 ); } }
void inventory::reassign_item( item &it, char invlet, bool remove_old ) { if( it.invlet == invlet ) { // no change needed return; } if( remove_old && it.invlet ) { auto invlet_list_iter = invlet_cache.find( it.typeId() ); if( invlet_list_iter != invlet_cache.end() ) { auto &invlet_list = invlet_list_iter->second; invlet_list.erase( std::remove_if( invlet_list.begin(), invlet_list.end(), [&it]( char cached_invlet ) { return cached_invlet == it.invlet; } ), invlet_list.end() ); } } it.invlet = invlet; update_cache_with_item( it ); }
//Adds the weight of aItem to the inventory's total weight //Returns whether or not it succeeded. bool inventory::incWeight(const item& aItem) { //If the new items weight added to the inventory total weight exceeds the //MAX_WEIGHT value, return a failure. double item_weight = aItem.getWeight(); if((item_weight + weight) > MAX_WEIGHT) { cout << "You're not strong enough to pick up the " << aItem << " with everything else you're carrying." << endl; return false; } else { cout << "You picked up a " << aItem << "." << endl; weight+=item_weight; return true; } }
item_location game_menus::inv::saw_barrel( player &p, item &tool ) { const auto actor = dynamic_cast<const saw_barrel_actor *> ( tool.type->get_use( "saw_barrel" )->get_actor_ptr() ); if( !actor ) { debugmsg( "Tried to use a wrong item." ); return item_location(); } return inv_internal( p, saw_barrel_inventory_preset( p, tool, *actor ), _( "Saw barrel" ), 1, _( "You don't have any guns." ), string_format( _( "Choose a weapon to use your %s on" ), tool.tname( 1, false ).c_str() ) ); }
bool player::can_feed_reactor_with( const item &it ) const { static const std::set<ammotype> acceptable = {{ ammotype( "reactor_slurry" ), ammotype( "plutonium" ) } }; if( !it.is_ammo() || can_eat( it ).success() ) { return false; } if( !has_active_bionic( bio_reactor ) && !has_active_bionic( bio_advreactor ) ) { return false; } return std::any_of( acceptable.begin(), acceptable.end(), [ &it ]( const ammotype & elem ) { return it.type->ammo->type.count( elem ); } ); }