diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 8287374ee8a83..a5f6e6a928695 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -70,21 +70,22 @@ const int ACTIVITY_SEARCH_DISTANCE = 60; /** Activity-associated item */ struct act_item { - /// Pointer to the inventory item - const item *it; + /// inventory item + item_location loc; /// How many items need to be processed int count; /// Amount of moves that processing will consume int consumed_moves; - act_item( const item *it, int count, int consumed_moves ) - : it( it ), + act_item( const item_location &loc, int count, int consumed_moves ) + : loc( loc ), count( count ), consumed_moves( consumed_moves ) {} }; // TODO: Deliberately unified with multidrop. Unify further. -using drop_indexes = std::list>; +using drop_location = std::pair; +using drop_locations = std::list>; static bool same_type( const std::list &items ) { @@ -351,30 +352,28 @@ void put_into_vehicle_or_drop( Character &c, item_drop_reason reason, const std: drop_on_map( c, reason, items, where ); } -static drop_indexes convert_to_indexes( const player_activity &act ) +static drop_locations convert_to_locations( const player_activity &act ) { - drop_indexes res; + drop_locations res; - if( act.values.size() % 2 != 0 ) { + if( act.values.size() != act.targets.size() ) { debugmsg( "Drop/stash activity contains an odd number of values." ); return res; } - for( auto iter = act.values.begin(); iter != act.values.end(); iter += 2 ) { - res.emplace_back( *iter, *std::next( iter ) ); + for( size_t i = 0; i < act.values.size(); i++ ) { + res.emplace_back( act.targets[i], act.values[i] ); } return res; } -static drop_indexes convert_to_indexes( const player &p, const std::list &items ) +static drop_locations convert_to_locations( const std::list &items ) { - drop_indexes res; + drop_locations res; - for( const auto &ait : items ) { - const int pos = p.get_item_position( ait.it ); - - if( pos != INT_MIN && ait.count > 0 ) { - if( res.empty() || res.back().first != pos ) { - res.emplace_back( pos, ait.count ); + for( const act_item &ait : items ) { + if( ait.loc && ait.count > 0 ) { + if( res.empty() || res.back().first != ait.loc ) { + res.emplace_back( ait.loc, ait.count ); } else { res.back().second += ait.count; } @@ -383,31 +382,30 @@ static drop_indexes convert_to_indexes( const player &p, const std::list convert_to_items( const player &p, const drop_indexes &drop, - int min_pos, int max_pos ) +static std::list convert_to_items( Character &p, const drop_locations &drop, + std::function filter ) { std::list res; - for( const auto &rec : drop ) { - const auto pos = rec.first; - const auto count = rec.second; + for( const drop_location &rec : drop ) { + const item_location loc = rec.first; + const int count = rec.second; - if( pos < min_pos || pos > max_pos ) { + if( !filter( loc ) ) { continue; - } else if( pos >= 0 ) { + } else if( !p.is_worn( *loc ) && !p.is_wielding( *loc ) ) { int obtained = 0; - for( const auto &it : p.inv.const_stack( pos ) ) { + for( const item &it : p.inv.const_stack( p.get_item_position( &*loc ) ) ) { if( obtained >= count ) { break; } const int qty = it.count_by_charges() ? std::min( it.charges, count - obtained ) : 1; obtained += qty; - // TODO: Use a calculated cost - res.emplace_back( &it, qty, 100 ); + item_location loc( p, const_cast( &it ) ); + res.emplace_back( loc, qty, loc.obtain_cost( p, qty ) ); } } else { - // TODO: Use a calculated cost - res.emplace_back( &p.i_at( pos ), count, pos == -1 ? 0 : 100 ); + res.emplace_back( loc, count, p.is_wielding( *loc ) ? 0 : loc.obtain_cost( p ) ); } } @@ -417,35 +415,46 @@ static std::list convert_to_items( const player &p, const drop_indexes // Prepares items for dropping by reordering them so that the drop // cost is minimal and "dependent" items get taken off first. // Implements the "backpack" logic. -static std::list reorder_for_dropping( const player &p, const drop_indexes &drop ) +static std::list reorder_for_dropping( Character &p, const drop_locations &drop ) { - auto res = convert_to_items( p, drop, -1, -1 ); - auto inv = convert_to_items( p, drop, 0, INT_MAX ); - auto worn = convert_to_items( p, drop, INT_MIN, -2 ); + std::list res = convert_to_items( p, drop, + [&p]( item_location loc ) { + return p.is_wielding( *loc ); + } ); + std::list inv = convert_to_items( p, drop, + [&p]( item_location loc ) { + return !p.is_wielding( *loc ) && !p.is_worn( *loc ); + } ); + std::list worn = convert_to_items( p, drop, + [&p]( item_location loc ) { + return p.is_worn( *loc ); + } ); // Sort inventory items by volume in ascending order inv.sort( []( const act_item & first, const act_item & second ) { - return first.it->volume() < second.it->volume(); + return first.loc->volume() < second.loc->volume(); } ); // Add missing dependent worn items (if any). for( const auto &wait : worn ) { - for( const auto dit : p.get_dependent_worn_items( *wait.it ) ) { + for( item *dit : p.get_dependent_worn_items( *wait.loc ) ) { const auto iter = std::find_if( worn.begin(), worn.end(), [dit]( const act_item & ait ) { - return ait.it == dit; + return &*ait.loc == dit; } ); if( iter == worn.end() ) { // TODO: Use a calculated cost - worn.emplace_front( dit, dit->count(), 100 ); + const item_location loc( p, dit ); + act_item act( loc, loc->count(), loc.obtain_cost( p, loc->count() ) ); + worn.emplace_front( loc, loc->count(), loc.obtain_cost( p ) ); } } } // Sort worn items by storage in descending order, but dependent items always go first. worn.sort( []( const act_item & first, const act_item & second ) { - return first.it->is_worn_only_with( *second.it ) - || ( first.it->get_storage() > second.it->get_storage() - && !second.it->is_worn_only_with( *first.it ) ); + return first.loc->is_worn_only_with( *second.loc ) + || ( first.loc->get_storage() > second.loc->get_storage() + && !second.loc->is_worn_only_with( *first.loc ) ); } ); // Cumulatively increases @@ -454,9 +463,9 @@ static std::list reorder_for_dropping( const player &p, const drop_ind units::volume remaining_storage = p.volume_capacity(); while( !worn.empty() && !inv.empty() ) { - storage_loss += worn.front().it->get_storage(); + storage_loss += worn.front().loc->get_storage(); remaining_storage -= p.volume_capacity_reduced_by( storage_loss ); - units::volume inventory_item_volume = inv.front().it->volume(); + units::volume inventory_item_volume = inv.front().loc->volume(); // Does not fit if( remaining_storage < inventory_item_volume ) { break; @@ -492,7 +501,7 @@ static void debug_drop_list( const std::list &list ) std::string res( "Items ordered to drop:\n" ); for( const auto &ait : list ) { res += string_format( "Drop %d %s for %d moves\n", - ait.count, ait.it->display_name( ait.count ), ait.consumed_moves ); + ait.count, ait.loc->display_name( ait.count ), ait.consumed_moves ); } popup( res, PF_GET_KEY ); } @@ -501,21 +510,21 @@ static std::list obtain_activity_items( player_activity &act, player &p ) { std::list res; - auto items = reorder_for_dropping( p, convert_to_indexes( act ) ); + std::list items = reorder_for_dropping( p, convert_to_locations( act ) ); debug_drop_list( items ); while( !items.empty() && ( p.is_npc() || p.moves > 0 || items.front().consumed_moves == 0 ) ) { - const auto &ait = items.front(); + act_item &ait = items.front(); p.mod_moves( -ait.consumed_moves ); - if( p.is_worn( *ait.it ) ) { - p.takeoff( *ait.it, &res ); - } else if( ait.it->count_by_charges() ) { - res.push_back( p.reduce_charges( const_cast( ait.it ), ait.count ) ); + if( p.is_worn( *ait.loc ) ) { + p.takeoff( *ait.loc, &res ); + } else if( ait.loc->count_by_charges() ) { + res.push_back( p.reduce_charges( const_cast( &*ait.loc ), ait.count ) ); } else { - res.push_back( p.i_rem( ait.it ) ); + res.push_back( p.i_rem( &*ait.loc ) ); } items.pop_front(); @@ -527,10 +536,11 @@ static std::list obtain_activity_items( player_activity &act, player &p ) res.insert( res.begin(), excess.begin(), excess.end() ); } // Load anything that remains (if any) into the activity + act.targets.clear(); act.values.clear(); if( !items.empty() ) { - for( const auto &drop : convert_to_indexes( p, items ) ) { - act.values.push_back( drop.first ); + for( const drop_location &drop : convert_to_locations( items ) ) { + act.targets.push_back( drop.first ); act.values.push_back( drop.second ); } } @@ -607,14 +617,14 @@ void activity_on_turn_wear( player_activity &act, player &p ) void activity_handlers::washing_finish( player_activity *act, player *p ) { - auto items = reorder_for_dropping( *p, convert_to_indexes( *act ) ); + std::list items = reorder_for_dropping( *p, convert_to_locations( *act ) ); // Check again that we have enough water and soap incase the amount in our inventory changed somehow // Consume the water and soap units::volume total_volume = 0_ml; for( const act_item &filthy_item : items ) { - total_volume += filthy_item.it->volume(); + total_volume += filthy_item.loc->volume(); } washing_requirements required = washing_requirements_for_volume( total_volume ); @@ -638,7 +648,7 @@ void activity_handlers::washing_finish( player_activity *act, player *p ) } for( const auto &ait : items ) { - item *filthy_item = const_cast( ait.it ); + item *filthy_item = const_cast( &*ait.loc ); filthy_item->item_tags.erase( "FILTHY" ); p->on_worn_item_washed( *filthy_item ); } @@ -1926,10 +1936,11 @@ static bool tidy_activity( player &p, const tripoint &src_loc, } // we are adjacent to an unsorted zone, we came here to just drop items we are carrying if( mgr.has( zone_type_id( z_loot_unsorted ), g->m.getabs( src_loc ) ) ) { - for( auto inv_elem : p.inv_dump() ) { + for( item *inv_elem : p.inv_dump() ) { if( inv_elem->has_var( "activity_var" ) ) { inv_elem->erase_var( "activity_var" ); - p.drop( p.get_item_position( inv_elem ), src_loc ); + item_location loc( p, inv_elem ); + p.drop( loc, src_loc ); } } } diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index 64ee19edfe6c5..8f51b1b03ec59 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -759,8 +759,8 @@ enum aim_entry { bool advanced_inventory::move_all_items( bool nested_call ) { - auto &spane = panes[src]; - auto &dpane = panes[dest]; + advanced_inventory_pane &spane = panes[src]; + advanced_inventory_pane &dpane = panes[dest]; // AIM_ALL source area routine if( spane.get_area() == AIM_ALL ) { @@ -775,8 +775,8 @@ bool advanced_inventory::move_all_items( bool nested_call ) return false; } - auto &sarea = squares[spane.get_area()]; - auto &darea = squares[dpane.get_area()]; + advanced_inv_area &sarea = squares[spane.get_area()]; + advanced_inv_area &darea = squares[dpane.get_area()]; // Check first if the destination area still have enough room for moving all. if( !is_processing() && sarea.volume > darea.free_volume( dpane.in_vehicle() ) && @@ -787,12 +787,12 @@ bool advanced_inventory::move_all_items( bool nested_call ) // make sure that there are items to be moved bool done = false; // copy the current pane, to be restored after the move is queued - auto shadow = panes[src]; + advanced_inventory_pane shadow = panes[src]; // here we recursively call this function with each area in order to // put all items in the proper destination area, with minimal fuss - auto &loc = uistate.adv_inv_aim_all_location; + int &loc = uistate.adv_inv_aim_all_location; // re-entry nonsense - auto &entry = uistate.adv_inv_re_enter_move_all; + int &entry = uistate.adv_inv_re_enter_move_all; // if we are just starting out, set entry to initial value switch( static_cast( entry++ ) ) { case ENTRY_START: @@ -855,8 +855,8 @@ bool advanced_inventory::move_all_items( bool nested_call ) popup( _( "You can't put items there!" ) ); return false; } - auto &sarea = squares[spane.get_area()]; - auto &darea = squares[dpane.get_area()]; + advanced_inv_area &sarea = squares[spane.get_area()]; + advanced_inv_area &darea = squares[dpane.get_area()]; // Make sure source and destination are different, otherwise items will disappear // Need to check actual position to account for dragged vehicles @@ -882,31 +882,43 @@ bool advanced_inventory::move_all_items( bool nested_call ) } if( spane.get_area() == AIM_INVENTORY || spane.get_area() == AIM_WORN ) { - std::list> dropped; + drop_locations dropped; // keep a list of favorites separated, only drop non-fav first if they exist - std::list> dropped_favorite; + drop_locations dropped_favorite; if( spane.get_area() == AIM_INVENTORY ) { for( size_t index = 0; index < g->u.inv.size(); ++index ) { - const auto &stack = g->u.inv.const_stack( index ); - const auto &it = stack.front(); + const std::list &stack = g->u.inv.const_stack( index ); + const item &it = stack.front(); + item_location indexed_item( g->u, const_cast( &it ) ); if( !spane.is_filtered( it ) ) { - ( it.is_favorite ? dropped_favorite : dropped ).emplace_back( static_cast( index ), - it.count_by_charges() ? static_cast( it.charges ) : static_cast( stack.size() ) ); + int count; + if( it.count_by_charges() ) { + count = it.charges; + } else { + count = stack.size(); + } + if( it.is_favorite ) { + dropped_favorite.emplace_back( indexed_item, count ); + } else { + dropped.emplace_back( indexed_item, count ); + } } } } else if( spane.get_area() == AIM_WORN ) { // do this in reverse, to account for vector item removal messing with future indices auto iter = g->u.worn.rbegin(); for( size_t idx = 0; idx < g->u.worn.size(); ++idx, ++iter ) { - const size_t index = g->u.worn.size() - idx - 1; - const auto &it = *iter; + item &it = *iter; if( !spane.is_filtered( it ) ) { - ( it.is_favorite ? dropped_favorite : dropped ).emplace_back( player::worn_position_to_index( - index ), - it.count() ); + item_location loc( g->u, &it ); + if( it.is_favorite ) { + dropped_favorite.emplace_back( loc, it.count() ); + } else { + dropped.emplace_back( loc, it.count() ); + } } } } @@ -1264,7 +1276,7 @@ void advanced_inventory::display() g->u.activity.str_values.push_back( "force_ground" ); } - g->u.activity.values.push_back( idx ); + g->u.activity.targets.push_back( item_location( g->u, &g->u.i_at( idx ) ) ); g->u.activity.values.push_back( amount_to_move ); // exit so that the activity can be carried out diff --git a/src/character.cpp b/src/character.cpp index 10740e870ac85..c485178a1ee1f 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1726,15 +1726,39 @@ bool Character::i_add_or_drop( item &it, int qty ) return retval; } -void Character::drop( int pos, const tripoint &where ) +std::list Character::get_dependent_worn_items( const item &it ) { - const item &it = i_at( pos ); - const int count = it.count(); + std::list dependent; + // Adds dependent worn items recursively + const std::function add_dependent = [&]( const item & it ) { + for( item &wit : worn ) { + if( &wit == &it || !wit.is_worn_only_with( it ) ) { + continue; + } + const auto iter = std::find_if( dependent.begin(), dependent.end(), + [&wit]( const item * dit ) { + return &wit == dit; + } ); + if( iter == dependent.end() ) { // Not in the list yet + add_dependent( wit ); + dependent.push_back( &wit ); + } + } + }; - drop( { std::make_pair( pos, count ) }, where ); + if( is_worn( it ) ) { + add_dependent( it ); + } + + return dependent; +} + +void Character::drop( item_location loc, const tripoint &where ) +{ + drop( { std::make_pair( loc, loc->count() ) }, where ); } -void Character::drop( const std::list> &what, const tripoint &target, +void Character::drop( const drop_locations &what, const tripoint &target, bool stash ) { const activity_id type( stash ? "ACT_STASH" : "ACT_DROP" ); @@ -1752,9 +1776,9 @@ void Character::drop( const std::list> &what, const tripoint assign_activity( type ); activity.placement = target - pos(); - for( auto item_pair : what ) { - if( can_unwield( i_at( item_pair.first ) ).success() ) { - activity.values.push_back( item_pair.first ); + for( drop_location item_pair : what ) { + if( can_unwield( *item_pair.first ).success() ) { + activity.targets.push_back( item_pair.first ); activity.values.push_back( item_pair.second ); } } diff --git a/src/character.h b/src/character.h index 64f16bd158a2a..18c33b6ec8a38 100644 --- a/src/character.h +++ b/src/character.h @@ -59,6 +59,9 @@ struct points_left; class faction; struct construction; +using drop_location = std::pair; +using drop_locations = std::list; + enum vision_modes { DEBUG_NIGHTVISION, NV_GOGGLES, @@ -1075,10 +1078,11 @@ class Character : public Creature, public visitable ret_val can_unwield( const item &it ) const; void drop_invalid_inventory(); + /** Returns all items that must be taken off before taking off this item */ + std::list get_dependent_worn_items( const item &it ); /** Drops an item to the specified location */ - void drop( int pos, const tripoint &where ); - virtual void drop( const std::list> &what, const tripoint &target, - bool stash = false ); + void drop( item_location loc, const tripoint &where ); + virtual void drop( const drop_locations &what, const tripoint &target, bool stash = false ); virtual bool has_artifact_with( art_effect_passive effect ) const; diff --git a/src/game.cpp b/src/game.cpp index 0299df68b9534..11eb9e6e55478 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2095,7 +2095,7 @@ int game::inventory_item_menu( int pos, int iStartX, int iWidth, u.takeoff( oThisItem ); break; case 'd': - u.drop( pos, u.pos() ); + u.drop( locThisItem, u.pos() ); break; case 'U': unload( oThisItem ); diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index 9e12d92f2c4f3..067e2c7c0ac3b 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -224,7 +224,7 @@ item_location game_menus::inv::titled_menu( avatar &you, const std::string &titl class armor_inventory_preset: public inventory_selector_preset { public: - armor_inventory_preset( const player &pl, const std::string &color_in ) : + armor_inventory_preset( player &pl, const std::string &color_in ) : p( pl ), color( color_in ) { append_cell( [ this ]( const item_location & loc ) { return get_number_string( loc->get_encumber( p ) ); @@ -265,7 +265,7 @@ class armor_inventory_preset: public inventory_selector_preset } protected: - const player &p; + player &p; private: std::string get_number_string( int number ) const { return number ? string_format( "<%s>%d", color, number ) : std::string(); @@ -277,7 +277,7 @@ class armor_inventory_preset: public inventory_selector_preset class wear_inventory_preset: public armor_inventory_preset { public: - wear_inventory_preset( const player &p, const std::string &color ) : + wear_inventory_preset( player &p, const std::string &color ) : armor_inventory_preset( p, color ) {} @@ -305,7 +305,7 @@ item_location game_menus::inv::wear( player &p ) class take_off_inventory_preset: public armor_inventory_preset { public: - take_off_inventory_preset( const player &p, const std::string &color ) : + take_off_inventory_preset( player &p, const std::string &color ) : armor_inventory_preset( p, color ) {} @@ -314,7 +314,7 @@ class take_off_inventory_preset: public armor_inventory_preset } std::string get_denial( const item_location &loc ) const override { - const auto ret = p.can_takeoff( *loc ); + const ret_val ret = p.can_takeoff( *loc ); if( !ret.success() ) { return trim_punctuation_marks( ret.str() ); @@ -1324,7 +1324,7 @@ item_location game_menus::inv::saw_barrel( player &p, item &tool ) ); } -std::list> game_menus::inv::multidrop( player &p ) +drop_locations game_menus::inv::multidrop( player &p ) { p.inv.restack( p ); @@ -1340,7 +1340,7 @@ std::list> game_menus::inv::multidrop( player &p ) if( inv_s.empty() ) { popup( std::string( _( "You have nothing to drop." ) ), PF_GET_KEY ); - return std::list >(); + return drop_locations(); } return inv_s.execute(); diff --git a/src/game_inventory.h b/src/game_inventory.h index 069605dc183c9..0d2c69c302e49 100644 --- a/src/game_inventory.h +++ b/src/game_inventory.h @@ -24,6 +24,8 @@ class repair_item_actor; using item_filter = std::function; using item_location_filter = std::function; +using drop_location = std::pair; +using drop_locations = std::list; class inventory_filter_preset : public inventory_selector_preset { @@ -65,9 +67,9 @@ void swap_letters( player &p ); /** * Select items to drop. - * @return A list of pairs of position, quantity. + * @return A list of pairs of item_location, quantity. */ -std::list> multidrop( player &p ); +drop_locations multidrop( player &p ); /** Consuming an item. */ item_location consume( player &p ); diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index e078ceebe2e82..fbc8c9f4f17c9 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -1608,7 +1608,7 @@ void inventory_selector::draw_footer( const catacurses::window &w ) const } } -inventory_selector::inventory_selector( const player &u, const inventory_selector_preset &preset ) +inventory_selector::inventory_selector( player &u, const inventory_selector_preset &preset ) : u( u ) , preset( preset ) , ctxt( "INVENTORY" ) @@ -1838,7 +1838,7 @@ item_location inventory_pick_selector::execute() } } -inventory_multiselector::inventory_multiselector( const player &p, +inventory_multiselector::inventory_multiselector( player &p, const inventory_selector_preset &preset, const std::string &selection_column_title ) : inventory_selector( p, preset ), @@ -1867,7 +1867,7 @@ void inventory_multiselector::on_entry_add( const inventory_entry &entry ) } } -inventory_compare_selector::inventory_compare_selector( const player &p ) : +inventory_compare_selector::inventory_compare_selector( player &p ) : inventory_multiselector( p, default_preset, _( "ITEMS TO COMPARE" ) ) {} std::pair inventory_compare_selector::execute() @@ -1929,7 +1929,7 @@ void inventory_compare_selector::toggle_entry( inventory_entry *entry ) } inventory_iuse_selector::inventory_iuse_selector( - const player &p, + player &p, const std::string &selector_title, const inventory_selector_preset &preset, const GetStats &get_st @@ -1938,8 +1938,7 @@ inventory_iuse_selector::inventory_iuse_selector( get_stats( get_st ), max_chosen_count( std::numeric_limits::max() ) {} - -std::list> inventory_iuse_selector::execute() +drop_locations inventory_iuse_selector::execute() { int count = 0; while( true ) { @@ -1984,7 +1983,7 @@ std::list> inventory_iuse_selector::execute() } break; } else if( input.action == "QUIT" ) { - return std::list >(); + return drop_locations(); } else if( input.action == "INVENTORY_FILTER" ) { set_filter(); } else { @@ -1993,11 +1992,11 @@ std::list> inventory_iuse_selector::execute() } } - std::list> dropped_pos_and_qty; + drop_locations dropped_pos_and_qty; - for( auto use_pair : to_use ) { - dropped_pos_and_qty.push_back( std::make_pair( u.get_item_position( use_pair.first ), - use_pair.second ) ); + for( const std::pair &use_pair : to_use ) { + item_location loc( u, const_cast( use_pair.first ) ); + dropped_pos_and_qty.push_back( std::make_pair( loc, use_pair.second ) ); } return dropped_pos_and_qty; @@ -2029,7 +2028,7 @@ inventory_selector::stats inventory_iuse_selector::get_raw_stats() const return stats{{ stat{{ "", "", "", "" }}, stat{{ "", "", "", "" }} }}; } -inventory_drop_selector::inventory_drop_selector( const player &p, +inventory_drop_selector::inventory_drop_selector( player &p, const inventory_selector_preset &preset ) : inventory_multiselector( p, preset, _( "ITEMS TO DROP" ) ), max_chosen_count( std::numeric_limits::max() ) @@ -2060,7 +2059,7 @@ void inventory_drop_selector::process_selected( int &count, count = 0; } -std::list> inventory_drop_selector::execute() +drop_locations inventory_drop_selector::execute() { int count = 0; while( true ) { @@ -2132,7 +2131,7 @@ std::list> inventory_drop_selector::execute() } break; } else if( input.action == "QUIT" ) { - return std::list >(); + return drop_locations(); } else if( input.action == "INVENTORY_FILTER" ) { set_filter(); } else if( input.action == "TOGGLE_FAVORITE" ) { @@ -2143,11 +2142,11 @@ std::list> inventory_drop_selector::execute() } } - std::list> dropped_pos_and_qty; + drop_locations dropped_pos_and_qty; - for( auto drop_pair : dropping ) { - dropped_pos_and_qty.push_back( std::make_pair( u.get_item_position( drop_pair.first ), - drop_pair.second ) ); + for( const std::pair &drop_pair : dropping ) { + item_location loc( u, const_cast( drop_pair.first ) ); + dropped_pos_and_qty.push_back( std::make_pair( loc, drop_pair.second ) ); } return dropped_pos_and_qty; diff --git a/src/inventory_ui.h b/src/inventory_ui.h index 2faa88ef67bca..157b66290bd53 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -41,6 +41,9 @@ enum class scroll_direction : int { struct navigation_mode_data; struct inventory_input; +using drop_location = std::pair; +using drop_locations = std::list; + class inventory_entry { public: @@ -420,7 +423,7 @@ class selection_column : public inventory_column class inventory_selector { public: - inventory_selector( const player &u, const inventory_selector_preset &preset = default_preset ); + inventory_selector( player &u, const inventory_selector_preset &preset = default_preset ); ~inventory_selector(); /** These functions add items from map / vehicles. */ void add_character_items( Character &character ); @@ -453,7 +456,7 @@ class inventory_selector bool keep_open = false; protected: - const player &u; + player &u; const inventory_selector_preset &preset; /** @@ -622,7 +625,7 @@ inventory_selector::stat display_stat( const std::string &caption, int cur_value class inventory_pick_selector : public inventory_selector { public: - inventory_pick_selector( const player &p, + inventory_pick_selector( player &p, const inventory_selector_preset &preset = default_preset ) : inventory_selector( p, preset ) {} @@ -632,7 +635,7 @@ class inventory_pick_selector : public inventory_selector class inventory_multiselector : public inventory_selector { public: - inventory_multiselector( const player &p, const inventory_selector_preset &preset = default_preset, + inventory_multiselector( player &p, const inventory_selector_preset &preset = default_preset, const std::string &selection_column_title = "" ); protected: void rearrange_columns( size_t client_width ) override; @@ -645,7 +648,7 @@ class inventory_multiselector : public inventory_selector class inventory_compare_selector : public inventory_multiselector { public: - inventory_compare_selector( const player &p ); + inventory_compare_selector( player &p ); std::pair execute(); protected: @@ -660,11 +663,11 @@ class inventory_iuse_selector : public inventory_multiselector { public: using GetStats = std::function & )>; - inventory_iuse_selector( const player &p, + inventory_iuse_selector( player &p, const std::string &selector_title, const inventory_selector_preset &preset = default_preset, const GetStats & = {} ); - std::list> execute(); + drop_locations execute(); protected: stats get_raw_stats() const override; @@ -679,9 +682,9 @@ class inventory_iuse_selector : public inventory_multiselector class inventory_drop_selector : public inventory_multiselector { public: - inventory_drop_selector( const player &p, + inventory_drop_selector( player &p, const inventory_selector_preset &preset = default_preset ); - std::list> execute(); + drop_locations execute(); protected: stats get_raw_stats() const override; diff --git a/src/iuse.cpp b/src/iuse.cpp index 8e1307b0b3def..5357c8be6fa64 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -9508,19 +9508,19 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) popup( std::string( _( "You have nothing to clean." ) ), PF_GET_KEY ); return 0; } - const std::list> to_clean = inv_s.execute(); + const drop_locations to_clean = inv_s.execute(); if( to_clean.empty() ) { return 0; } // Determine if we have enough water and cleanser for all the items. units::volume total_volume = 0_ml; - for( std::pair pair : to_clean ) { - item i = p->i_at( pair.first ); - if( pair.first == INT_MIN ) { + for( drop_location pair : to_clean ) { + if( !pair.first ) { p->add_msg_if_player( m_info, _( "Never mind." ) ); return 0; } + item &i = *pair.first; total_volume += i.volume() * pair.second / ( i.count_by_charges() ? i.charges : 1 ); } @@ -9547,8 +9547,8 @@ int iuse::wash_items( player *p, bool soft_items, bool hard_items ) // Assign the activity values. p->assign_activity( activity_id( "ACT_WASH" ), required.time ); - for( std::pair pair : to_clean ) { - p->activity.values.push_back( pair.first ); + for( drop_location pair : to_clean ) { + p->activity.targets.push_back( pair.first ); p->activity.values.push_back( pair.second ); } diff --git a/src/npc.cpp b/src/npc.cpp index 195c9bbdb8728..c3fa30f902229 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1181,7 +1181,7 @@ bool npc::wield( item &it ) return true; } -void npc::drop( const std::list> &what, const tripoint &target, +void npc::drop( const drop_locations &what, const tripoint &target, bool stash ) { Character::drop( what, target, stash ); diff --git a/src/npc.h b/src/npc.h index 837ed246ea1c0..cc40cfc466a5c 100644 --- a/src/npc.h +++ b/src/npc.h @@ -61,6 +61,8 @@ using npc_class_id = string_id; using mission_type_id = string_id; using mfaction_id = int_id; using overmap_location_str_id = string_id; +using drop_location = std::pair; +using drop_locations = std::list; void parse_tags( std::string &phrase, const Character &u, const Character &me, const itype_id &item_type = "null" ); @@ -915,7 +917,7 @@ class npc : public player void do_npc_read(); void stow_item( item &it ); bool wield( item &it ) override; - void drop( const std::list> &what, const tripoint &target, + void drop( const drop_locations &what, const tripoint &target, bool stash ) override; bool adjust_worn(); bool has_healing_item( healing_options try_to_fix ); diff --git a/src/player.cpp b/src/player.cpp index ec1f13a8c1d25..7eed05e7e231f 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -4824,34 +4824,7 @@ hint_rating player::rate_action_takeoff( const item &it ) const return HINT_IFFY; } -std::list player::get_dependent_worn_items( const item &it ) const -{ - std::list dependent; - // Adds dependent worn items recursively - const std::function add_dependent = [ & ]( const item & it ) { - for( const auto &wit : worn ) { - if( &wit == &it || !wit.is_worn_only_with( it ) ) { - continue; - } - const auto iter = std::find_if( dependent.begin(), dependent.end(), - [ &wit ]( const item * dit ) { - return &wit == dit; - } ); - if( iter == dependent.end() ) { // Not in the list yet - add_dependent( wit ); - dependent.push_back( &wit ); - } - } - }; - - if( is_worn( it ) ) { - add_dependent( it ); - } - - return dependent; -} - -ret_val player::can_takeoff( const item &it, const std::list *res ) const +ret_val player::can_takeoff( const item &it, const std::list *res ) { auto iter = std::find_if( worn.begin(), worn.end(), [ &it ]( const item & wit ) { return &it == &wit; @@ -4875,7 +4848,7 @@ ret_val player::can_takeoff( const item &it, const std::list *res ) return ret_val::make_success(); } -bool player::takeoff( const item &it, std::list *res ) +bool player::takeoff( item &it, std::list *res ) { const auto ret = can_takeoff( it, res ); if( !ret.success() ) { @@ -4891,7 +4864,8 @@ bool player::takeoff( const item &it, std::list *res ) if( volume_carried() + it.volume() > volume_capacity_reduced_by( it.get_storage() ) ) { if( is_npc() || query_yn( _( "No room in inventory for your %s. Drop it?" ), colorize( it.tname(), it.color_in_inventory() ) ) ) { - drop( get_item_position( &it ), pos() ); + item_location loc( *this, &it ); + drop( loc, pos() ); return true; // the drop activity ends up taking off the item anyway so shouldn't try to do it again here } else { return false; diff --git a/src/player.h b/src/player.h index f7a002b23cd5c..b7fde069cb32d 100644 --- a/src/player.h +++ b/src/player.h @@ -734,7 +734,7 @@ class player : public Character * Check player capable of taking off an item. * @param it Thing to be taken off */ - ret_val can_takeoff( const item &it, const std::list *res = nullptr ) const; + ret_val can_takeoff( const item &it, const std::list *res = nullptr ); /** * Check player capable of wielding an item. @@ -798,10 +798,8 @@ class player : public Character bool change_side( item &it, bool interactive = true ); bool change_side( int pos, bool interactive = true ); - /** Returns all items that must be taken off before taking off this item */ - std::list get_dependent_worn_items( const item &it ) const; /** Takes off an item, returning false on fail. The taken off item is processed in the interact */ - bool takeoff( const item &it, std::list *res = nullptr ); + bool takeoff( item &it, std::list *res = nullptr ); bool takeoff( int pos ); /** So far only called by unload() from game.cpp */ diff --git a/src/suffer.cpp b/src/suffer.cpp index 541e149fcb433..78e23b8cf3682 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -480,7 +480,8 @@ void Character::suffer_from_schizophrenia() str[0] = toupper( str[0] ); add_msg_if_player( m_bad, "%s", str ); - drop( get_item_position( &weapon ), pos() ); + item_location loc( *this, &weapon ); + drop( loc, pos() ); return; } // Talk to self diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 3119a59d654a9..9206a14f66666 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -244,9 +244,9 @@ static void drop_at_feet( player &p, const int id ) item *found = retrieve_item( p, id ); REQUIRE( found ); - int pos = p.get_item_position( found ); + item_location loc( p, found ); p.moves = 100; - p.drop( pos, p.pos() ); + p.drop( loc, p.pos() ); p.activity.do_turn( p ); REQUIRE( g->m.i_at( p.pos() ).size() == size_before + 1 );