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

Fix AIM needs to be closed multiple times when moving all inventory/worn items to ground #47602

Merged
merged 1 commit into from
Feb 20, 2021
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
84 changes: 39 additions & 45 deletions src/advanced_inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ void advanced_inventory::redraw_pane( side p )
wnoutrefresh( w );
}

bool advanced_inventory::move_all_items( bool nested_call )
bool advanced_inventory::move_all_items()
{
advanced_inventory_pane &spane = panes[src];
advanced_inventory_pane &dpane = panes[dest];
Expand Down Expand Up @@ -744,44 +744,49 @@ bool advanced_inventory::move_all_items( bool nested_call )
return false;
}

// make sure that there are items to be moved
bool done = false;
// copy the current pane, to be restored after the move is queued
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
int &loc = save_state->aim_all_location;
// re-entry nonsense
aim_entry &entry = save_state->re_enter_move_all;
// if we are just starting out, set entry to initial value
entry = entry + 1;
switch( entry ) {
case aim_entry::START:
++entry;
entry = aim_entry::VEHICLE;
/* fallthrough */
case aim_entry::VEHICLE:
if( squares[loc].can_store_in_vehicle() ) {
// either do the inverse of the pane (if it is the one we are transferring to),
// or just transfer the contents (if it is not the one we are transferring to)
spane.set_area( squares[loc], dpane.get_area() == loc ? !dpane.in_vehicle() : true );
spane.set_area( squares[loc], true );
// add items, calculate weights and volumes... the fun stuff
recalc_pane( src );
// then move the items to the destination area
move_all_items( true );
if( !move_all_items() ) {
do_return_entry();
}
} else {
do_return_entry();
}
entry = aim_entry::MAP;
break;
case aim_entry::MAP:
spane.set_area( squares[loc++], false );
recalc_pane( src );
move_all_items( true );
if( !move_all_items() ) {
do_return_entry();
}
entry = aim_entry::RESET;
break;
case aim_entry::RESET:
if( loc > AIM_AROUND_END ) {
loc = AIM_AROUND_BEGIN;
entry = aim_entry::START;
done = true;
if( !get_option<bool>( "CLOSE_ADV_INV" ) ) {
do_return_entry();
}
} else {
entry = aim_entry::VEHICLE;
do_return_entry();
}
break;
default:
Expand All @@ -792,10 +797,6 @@ bool advanced_inventory::move_all_items( bool nested_call )
}
// restore the pane to its former glory
panes[src] = shadow;
// make it auto loop back, if not already doing so
if( !done && !player_character.activity ) {
do_return_entry();
}
return true;
}

Expand All @@ -811,14 +812,16 @@ bool advanced_inventory::move_all_items( bool nested_call )
if( spane.items.empty() || liquid_items == spane.items.size() ) {
return false;
}
bool restore_area = false;
std::unique_ptr<on_out_of_scope> restore_area;
if( dpane.get_area() == AIM_ALL ) {
aim_location loc = dpane.get_area();
// ask where we want to store the item via the menu
if( !query_destination( loc ) ) {
return false;
}
restore_area = true;
restore_area = std::make_unique<on_out_of_scope>( [&]() {
dpane.restore_area();
} );
}
if( !squares[dpane.get_area()].canputitems() ) {
popup( _( "You can't put items there!" ) );
Expand All @@ -836,20 +839,6 @@ bool advanced_inventory::move_all_items( bool nested_call )
return false;
}

if( nested_call || !get_option<bool>( "CLOSE_ADV_INV" ) ) {
// Why is this here? It's because the activity backlog can act
// like a stack instead of a single deferred activity in order to
// accomplish some UI shenanigans. The inventory menu activity is
// added, then an activity to drop is pushed on the stack, then
// the drop activity is repeatedly popped and pushed on the stack
// until all its items are processed. When the drop activity runs out,
// the inventory menu activity is there waiting and seamlessly returns
// the player to the menu. If the activity is interrupted instead of
// completing, both activities are canceled.
// Thanks to kevingranade for the explanation.
do_return_entry();
}

map &here = get_map();
if( spane.get_area() == AIM_INVENTORY || spane.get_area() == AIM_WORN ) {
if( dpane.get_area() == AIM_INVENTORY ) {
Expand All @@ -865,6 +854,13 @@ bool advanced_inventory::move_all_items( bool nested_call )
return false;
}

// Check first if the destination area still have enough room for moving all.
const units::volume &src_volume = spane.in_vehicle() ? sarea.volume_veh : sarea.volume;
if( !is_processing() && src_volume > darea.free_volume( dpane.in_vehicle() ) &&
!query_yn( _( "There isn't enough room, do you really want to move all?" ) ) ) {
return false;
}

drop_locations dropped;
// keep a list of favorites separated, only drop non-fav first if they exist
drop_locations dropped_favorite;
Expand Down Expand Up @@ -910,9 +906,6 @@ bool advanced_inventory::move_all_items( bool nested_call )
dropped = dropped_favorite;
}

// make sure advanced inventory is reopened after activity completion.
do_return_entry();

const tripoint placement = darea.off;
// in case there is vehicle cargo space at dest but the player wants to drop to ground
const bool force_ground = !dpane.in_vehicle();
Expand All @@ -922,14 +915,16 @@ bool advanced_inventory::move_all_items( bool nested_call )
to_drop.emplace_back( it.first, it.second );
}

do_return_entry();

player_character.assign_activity( player_activity( drop_activity_actor(
to_drop, placement, force_ground
) ) );

// exit so that the activity can be carried out
exit = true;
} else {
if( dpane.get_area() == AIM_INVENTORY || dpane.get_area() == AIM_WORN ) {
if( dpane.get_area() == AIM_WORN ) {
popup( _( "You look at the items, then your clothes, and scratch your head…" ) );
return false;
} else if( dpane.get_area() == AIM_INVENTORY ) {
player_character.activity.coords.push_back( player_character.pos() );
std::vector<item_location> target_items;
std::vector<item_location> target_items_favorites;
Expand All @@ -947,8 +942,7 @@ bool advanced_inventory::move_all_items( bool nested_call )

// If moving to inventory or worn, silently filter buckets
// Moving them would cause tons of annoying prompts or spills
const bool filter_buckets = dpane.get_area() == AIM_INVENTORY ||
dpane.get_area() == AIM_WORN;
const bool filter_buckets = dpane.get_area() == AIM_INVENTORY;
bool filtered_any_bucket = false;
// Push item_locations and item counts for all items at placement
for( item_stack::iterator it = stack_begin; it != stack_end; ++it ) {
Expand Down Expand Up @@ -985,6 +979,8 @@ bool advanced_inventory::move_all_items( bool nested_call )
target_items = target_items_favorites;
}

do_return_entry();

player_character.assign_activity( player_activity( pickup_activity_actor(
target_items,
quantities,
Expand Down Expand Up @@ -1059,6 +1055,8 @@ bool advanced_inventory::move_all_items( bool nested_call )
target_items = target_items_favorites;
}

do_return_entry();

player_character.assign_activity( player_activity( move_items_activity_actor(
target_items,
quantities,
Expand All @@ -1068,10 +1066,6 @@ bool advanced_inventory::move_all_items( bool nested_call )
}

}
// if dest was AIM_ALL then we used query_destination and should undo that
if( restore_area ) {
dpane.restore_area();
}
return true;
}

Expand Down
8 changes: 6 additions & 2 deletions src/advanced_inv.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,18 @@ class advanced_inventory
// store/load settings (such as index, filter, etc)
void save_settings( bool only_panes );
void load_settings();
// used to return back to AIM when other activities queued are finished
// Adds an auto-resumed activity that reopens AIM. If this is called
// before assigning an item-moving activity, AIM is reopened when the
// item-moving activity finishes. This function should only be called
// when AIM is going to be automatically closed due to pending item-moving
// activity, otherwise the player will need to close AIM multiple times.
void do_return_entry();
// returns true if currently processing a routine
// (such as `MOVE_ALL_ITEMS' with `AIM_ALL' source)
bool is_processing() const;

static std::string get_sortname( advanced_inv_sortby sortby );
bool move_all_items( bool nested_call = false );
bool move_all_items();
void print_items( const advanced_inventory_pane &pane, bool active );
void recalc_pane( side p );
void redraw_pane( side p );
Expand Down
11 changes: 8 additions & 3 deletions src/advanced_inv_pane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@ void advanced_inventory_pane::load_settings( int saved_area_idx,
!square.veh->get_items( square.vstor ).empty() : false;
bool has_map_items = !get_map().i_at( square.pos ).empty();
// determine based on map items and settings to show cargo
bool show_vehicle = is_re_enter ?
save_state->in_vehicle : has_veh_items ? true :
has_map_items ? false : square.can_store_in_vehicle();
bool show_vehicle = false;
if( is_re_enter ) {
show_vehicle = save_state->in_vehicle;
} else if( has_veh_items == has_map_items ) {
show_vehicle = save_state->in_vehicle && square.can_store_in_vehicle();
} else {
show_vehicle = has_veh_items;
}
set_area( square, show_vehicle );
sortby = static_cast<advanced_inv_sortby>( save_state->sort_idx );
index = save_state->selected_idx;
Expand Down
10 changes: 10 additions & 0 deletions src/cata_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,11 @@ class on_out_of_scope
explicit on_out_of_scope( const std::function<void()> &func ) : func( func ) {
}

on_out_of_scope( const on_out_of_scope & ) = delete;
on_out_of_scope( on_out_of_scope && ) = delete;
on_out_of_scope &operator=( const on_out_of_scope & ) = delete;
on_out_of_scope &operator=( on_out_of_scope && ) = delete;

~on_out_of_scope() {
if( func ) {
func();
Expand Down Expand Up @@ -541,6 +546,11 @@ class restore_on_out_of_scope
impl( [this]() { t = std::move( orig_t ); } ) {
}
// *INDENT-ON*

restore_on_out_of_scope( const restore_on_out_of_scope<T> & ) = delete;
restore_on_out_of_scope( restore_on_out_of_scope<T> && ) = delete;
restore_on_out_of_scope &operator=( const restore_on_out_of_scope<T> & ) = delete;
restore_on_out_of_scope &operator=( restore_on_out_of_scope<T> && ) = delete;
};

#endif // CATA_SRC_CATA_UTILITY_H