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

refactor drop activity and associated functions #36205

Merged
merged 3 commits into from
Dec 30, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
127 changes: 69 additions & 58 deletions src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::pair<int, int>>;
using drop_location = std::pair<item_location, int>;
using drop_locations = std::list<std::pair<item_location, int>>;

static bool same_type( const std::list<item> &items )
{
Expand Down Expand Up @@ -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." );
KorGgenT marked this conversation as resolved.
Show resolved Hide resolved
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<act_item> &items )
static drop_locations convert_to_locations( const std::list<act_item> &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;
}
Expand All @@ -383,31 +382,30 @@ static drop_indexes convert_to_indexes( const player &p, const std::list<act_ite
return res;
}

static std::list<act_item> convert_to_items( const player &p, const drop_indexes &drop,
int min_pos, int max_pos )
static std::list<act_item> convert_to_items( Character &p, const drop_locations &drop,
std::function<bool( item_location loc )> filter )
{
std::list<act_item> 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<int>( it.charges, count - obtained ) : 1;
obtained += qty;
// TODO: Use a calculated cost
res.emplace_back( &it, qty, 100 );
item_location loc( p, const_cast<item *>( &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 ) );
}
}

Expand All @@ -417,35 +415,46 @@ static std::list<act_item> 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<act_item> reorder_for_dropping( const player &p, const drop_indexes &drop )
static std::list<act_item> 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<act_item> res = convert_to_items( p, drop,
[&p]( item_location loc ) {
return p.is_wielding( *loc );
} );
std::list<act_item> inv = convert_to_items( p, drop,
[&p]( item_location loc ) {
return !p.is_wielding( *loc ) && !p.is_worn( *loc );
} );
std::list<act_item> 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() ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lines seems to have no effect. It creates an act_item object named act, but that object is never used. It's constructor does not have side effects and the functions called to obtain the parameters also have no side effects.

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
Expand All @@ -454,9 +463,9 @@ static std::list<act_item> 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;
Expand Down Expand Up @@ -492,7 +501,7 @@ static void debug_drop_list( const std::list<act_item> &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 );
}
Expand All @@ -501,21 +510,21 @@ static std::list<item> obtain_activity_items( player_activity &act, player &p )
{
std::list<item> res;

auto items = reorder_for_dropping( p, convert_to_indexes( act ) );
std::list<act_item> 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<item *>( 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<item *>( &*ait.loc ), ait.count ) );
} else {
res.push_back( p.i_rem( ait.it ) );
res.push_back( p.i_rem( &*ait.loc ) );
}

items.pop_front();
Expand All @@ -527,10 +536,11 @@ static std::list<item> 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 );
}
}
Expand Down Expand Up @@ -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<act_item> 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 );

Expand All @@ -638,7 +648,7 @@ void activity_handlers::washing_finish( player_activity *act, player *p )
}

for( const auto &ait : items ) {
item *filthy_item = const_cast<item *>( ait.it );
item *filthy_item = const_cast<item *>( &*ait.loc );
filthy_item->item_tags.erase( "FILTHY" );
p->on_worn_item_washed( *filthy_item );
}
Expand Down Expand Up @@ -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 );
}
}
}
Expand Down
52 changes: 32 additions & 20 deletions src/advanced_inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand 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() ) &&
Expand All @@ -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<aim_entry>( entry++ ) ) {
case ENTRY_START:
Expand Down Expand Up @@ -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
Expand All @@ -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<std::pair<int, int>> dropped;
drop_locations dropped;
// keep a list of favorites separated, only drop non-fav first if they exist
std::list<std::pair<int, int>> 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<item> &stack = g->u.inv.const_stack( index );
const item &it = stack.front();
item_location indexed_item( g->u, const_cast<item *>( &it ) );

if( !spane.is_filtered( it ) ) {
( it.is_favorite ? dropped_favorite : dropped ).emplace_back( static_cast<int>( index ),
it.count_by_charges() ? static_cast<int>( it.charges ) : static_cast<int>( 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() );
}
}
}
}
Expand Down
Loading