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; }
// Returns false if pickup caused a prompt and the player selected to cancel pickup bool pick_one_up( const tripoint &pickup_target, item &newit, vehicle *veh, int cargo_part, int index, int quantity, bool &got_water, bool &offered_swap, PickupMap &mapPickup, bool autopickup ) { player &u = g->u; int moves_taken = 100; bool picked_up = false; pickup_answer option = CANCEL; item leftovers = newit; const auto wield_check = u.can_wield( newit ); if( newit.invlet != '\0' && u.invlet_to_position( newit.invlet ) != INT_MIN ) { // Existing invlet is not re-usable, remove it and let the code in player.cpp/inventory.cpp // add a new invlet, otherwise keep the (usable) invlet. newit.invlet = '\0'; } if( quantity != 0 && newit.count_by_charges() ) { // Reinserting leftovers happens after item removal to avoid stacking issues. leftovers.charges = newit.charges - quantity; if( leftovers.charges > 0 ) { newit.charges = quantity; } } else { leftovers.charges = 0; } bool did_prompt = false; newit.charges = u.i_add_to_container( newit, false ); if( newit.is_ammo() && newit.charges == 0 ) { picked_up = true; option = NUM_ANSWERS; //Skip the options part } else if( newit.made_of_from_type( LIQUID ) ) { got_water = true; } else if( !u.can_pickWeight( newit, false ) ) { if( !autopickup ) { const std::string &explain = string_format( _( "The %s is too heavy!" ), newit.display_name() ); option = handle_problematic_pickup( newit, offered_swap, explain ); did_prompt = true; } else { option = CANCEL; } } else if( newit.is_bucket() && !newit.is_container_empty() ) { if( !autopickup ) { const std::string &explain = string_format( _( "Can't stash %s while it's not empty" ), newit.display_name() ); option = handle_problematic_pickup( newit, offered_swap, explain ); did_prompt = true; } else { option = CANCEL; } } else if( !u.can_pickVolume( newit ) ) { if( !autopickup ) { const std::string &explain = string_format( _( "Not enough capacity to stash %s" ), newit.display_name() ); option = handle_problematic_pickup( newit, offered_swap, explain ); did_prompt = true; } else { option = CANCEL; } } else { option = STASH; } switch( option ) { case NUM_ANSWERS: // Some other option break; case CANCEL: picked_up = false; break; case WEAR: picked_up = !!u.wear_item( newit ); break; case WIELD: if( wield_check.success() ) { picked_up = u.wield( newit ); if( u.weapon.invlet ) { add_msg( m_info, _( "Wielding %c - %s" ), u.weapon.invlet, u.weapon.display_name() ); } else { add_msg( m_info, _( "Wielding - %s" ), u.weapon.display_name() ); } } else { add_msg( m_neutral, wield_check.c_str() ); } break; case SPILL: if( newit.is_container_empty() ) { debugmsg( "Tried to spill contents from an empty container" ); break; } picked_up = newit.spill_contents( u ); if( !picked_up ) { break; } // Intentional fallthrough case STASH: auto &entry = mapPickup[newit.tname()]; entry.second += newit.count(); entry.first = u.i_add( newit ); picked_up = true; break; } if( picked_up ) { remove_from_map_or_vehicle( pickup_target, veh, cargo_part, moves_taken, index ); } if( leftovers.charges > 0 ) { bool to_map = veh == nullptr; if( !to_map ) { to_map = !veh->add_item( cargo_part, leftovers ); } if( to_map ) { g->m.add_item_or_charges( pickup_target, leftovers ); } } return picked_up || !did_prompt; }