From de16cb54467a832b9b66f1b32f35f0073ad23744 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 6 Apr 2020 01:22:55 +0200 Subject: [PATCH] Migrate ACT_PICKUP to the activity actor system --- src/activity_actor.cpp | 66 +++++++++++++++++++++ src/activity_actor.h | 37 ++++++++++++ src/activity_handlers.cpp | 7 --- src/activity_handlers.h | 2 - src/activity_item_handling.cpp | 51 ----------------- src/advanced_inv.cpp | 102 ++++++++++++--------------------- src/iexamine.cpp | 11 ++-- src/pickup.cpp | 37 +++++++----- tests/invlet_test.cpp | 5 +- 9 files changed, 167 insertions(+), 151 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index dc67593ac32ee..309accf37b170 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -4,6 +4,7 @@ #include #include "activity_handlers.h" // put_into_vehicle_or_drop and drop_on_map +#include "advanced_inv.h" #include "avatar.h" #include "character.h" #include "computer_session.h" @@ -281,6 +282,70 @@ std::unique_ptr move_items_activity_actor::deserialize( JsonIn & return actor.clone(); } +void pickup_activity_actor::do_turn( player_activity &, Character &who ) +{ + // If we don't have target items bail out + if( target_items.empty() ) { + who.cancel_activity(); + return; + } + + // If the player moves while picking up (i.e.: in a moving vehicle) cancel + // the activity, only populate starting_pos when grabbing from the ground + if( starting_pos && *starting_pos != who.pos() ) { + who.cancel_activity(); + who.add_msg_if_player( _( "Moving canceled auto-pickup." ) ); + return; + } + + // Auto_resume implies autopickup. + const bool autopickup = who.activity.auto_resume; + + // False indicates that the player canceled pickup when met with some prompt + const bool keep_going = Pickup::do_pickup( target_items, quantities, autopickup ); + + // If there are items left we ran out of moves, so continue the activity + // Otherwise, we are done. + if( !keep_going || target_items.empty() ) { + who.cancel_activity(); + + if( who.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { + who.set_value( "THIEF_MODE", "THIF_ASK" ); + } + + if( !keep_going ) { + // The user canceled the activity, so we're done + // AIM might have more pickup activities pending, also cancel them. + // TODO: Move this to advanced inventory instead of hacking it in here + cancel_aim_processing(); + } + } +} + +void pickup_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "target_items", target_items ); + jsout.member( "quantities", quantities ); + jsout.member( "starting_pos", starting_pos ); + + jsout.end_object(); +} + +std::unique_ptr pickup_activity_actor::deserialize( JsonIn &jsin ) +{ + pickup_activity_actor actor( {}, {}, cata::nullopt ); + + JsonObject data = jsin.get_object(); + + data.read( "target_items", actor.target_items ); + data.read( "quantities", actor.quantities ); + data.read( "starting_pos", actor.starting_pos ); + + return actor.clone(); +} + void migration_cancel_activity_actor::do_turn( player_activity &act, Character &who ) { // Stop the activity @@ -318,6 +383,7 @@ deserialize_functions = { { activity_id( "ACT_HACKING" ), &hacking_activity_actor::deserialize }, { activity_id( "ACT_MIGRATION_CANCEL" ), &migration_cancel_activity_actor::deserialize }, { activity_id( "ACT_MOVE_ITEMS" ), &move_items_activity_actor::deserialize }, + { activity_id( "ACT_PICKUP" ), &pickup_activity_actor::deserialize }, }; } // namespace activity_actors diff --git a/src/activity_actor.h b/src/activity_actor.h index 2f102f762c05d..03fcc266db84c 100644 --- a/src/activity_actor.h +++ b/src/activity_actor.h @@ -118,6 +118,43 @@ class move_items_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonIn &jsin ); }; +class pickup_activity_actor : public activity_actor +{ + private: + /** Target items and the quantities thereof */ + std::vector target_items; + std::vector quantities; + + /** + * Position of the character when the activity is started. This is + * stored so that we can cancel the activity if the player moves + * (e.g. if the player is in a moving vehicle). This should be null + * if not grabbing from the ground. + */ + cata::optional starting_pos; + + public: + pickup_activity_actor( const std::vector &target_items, + const std::vector &quantities, + const cata::optional &starting_pos ) : target_items( target_items ), + quantities( quantities ), starting_pos( starting_pos ) {} + + activity_id get_type() const override { + return activity_id( "ACT_PICKUP" ); + } + + void start( player_activity &, Character & ) override {}; + void do_turn( player_activity &act, Character &who ) override; + void finish( player_activity &, Character & ) override {}; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + + void serialize( JsonOut &jsout ) const override; + static std::unique_ptr deserialize( JsonIn &jsin ); +}; + class migration_cancel_activity_actor : public activity_actor { public: diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index dd9d909bf0de5..b87717d030d8a 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -170,7 +170,6 @@ static const activity_id ACT_OPEN_GATE( "ACT_OPEN_GATE" ); static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_OXYTORCH( "ACT_OXYTORCH" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); -static const activity_id ACT_PICKUP( "ACT_PICKUP" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); static const activity_id ACT_PRY_NAILS( "ACT_PRY_NAILS" ); @@ -299,7 +298,6 @@ activity_handlers::do_turn_functions = { { ACT_HAND_CRANK, hand_crank_do_turn }, { ACT_OXYTORCH, oxytorch_do_turn }, { ACT_AIM, aim_do_turn }, - { ACT_PICKUP, pickup_do_turn }, { ACT_WEAR, wear_do_turn }, { ACT_MULTIPLE_FISH, multiple_fish_do_turn }, { ACT_MULTIPLE_CONSTRUCTION, multiple_construction_do_turn }, @@ -3059,11 +3057,6 @@ void activity_handlers::aim_do_turn( player_activity *act, player * ) } } -void activity_handlers::pickup_do_turn( player_activity *, player * ) -{ - activity_on_turn_pickup(); -} - void activity_handlers::wear_do_turn( player_activity *act, player *p ) { activity_on_turn_wear( *act, *p ); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index 059fe8b9010a3..3643965983960 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -101,7 +101,6 @@ void activity_on_turn_move_loot( player_activity &act, player &p ); //return true if there is an activity that can be done potentially, return false if no work can be found. bool generic_multi_activity_handler( player_activity &act, player &p, bool check_only = false ); void activity_on_turn_fetch( player_activity &, player *p ); -void activity_on_turn_pickup(); void activity_on_turn_wear( player_activity &act, player &p ); bool find_auto_consume( player &p, bool food ); void try_fuel_fire( player_activity &act, player &p, bool starting_fire = false ); @@ -140,7 +139,6 @@ void hand_crank_do_turn( player_activity *act, player *p ); void multiple_chop_planks_do_turn( player_activity *act, player *p ); void oxytorch_do_turn( player_activity *act, player *p ); void aim_do_turn( player_activity *act, player *p ); -void pickup_do_turn( player_activity *act, player *p ); void wear_do_turn( player_activity *act, player *p ); void eat_menu_do_turn( player_activity *act, player *p ); void consume_food_menu_do_turn( player_activity *act, player *p ); diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 769f81af0e6b7..0f4e0d97cec72 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -741,57 +741,6 @@ void activity_handlers::stash_do_turn( player_activity *act, player *p ) } } -void activity_on_turn_pickup() -{ - // ACT_PICKUP has item_locations of target items and quantities of the same. - - // If we don't have target items bail out - if( g->u.activity.targets.empty() ) { - g->u.cancel_activity(); - return; - } - - // If the player moves while picking up (i.e.: in a moving vehicle) cancel the activity, only populate coords when grabbing from the ground - if( !g->u.activity.coords.empty() && g->u.activity.coords.at( 0 ) != g->u.pos() ) { - g->u.cancel_activity(); - if( g->u.is_player() ) { - g->u.add_msg_if_player( _( "Moving canceled auto-pickup." ) ); - } - return; - } - - // Auto_resume implies autopickup. - const bool autopickup = g->u.activity.auto_resume; - - // False indicates that the player canceled pickup when met with some prompt - const bool keep_going = Pickup::do_pickup( g->u.activity.targets, g->u.activity.values, - autopickup ); - - // If there are items left we ran out of moves, so continue the activity - // Otherwise, we are done. - if( !keep_going || g->u.activity.targets.empty() ) { - g->u.cancel_activity(); - if( g->u.get_value( "THIEF_MODE_KEEP" ) != "YES" ) { - g->u.set_value( "THIEF_MODE", "THIEF_ASK" ); - } - } - - // TODO: Move this to advanced inventory instead of hacking it in here - - if( !keep_going ) { - // The user canceled the activity, so we're done - g->u.cancel_activity(); - // AIM might have more pickup activities pending, also cancel them. - // TODO: Move this to advanced inventory instead of hacking it in here - cancel_aim_processing(); - } else if( g->u.activity.targets.empty() ) { - // The user did not cancel, but there's no item left - g->u.cancel_activity(); - // But do not cancel AIM processing as it might have more pickup activities - // pending for other locations. - } -} - static double get_capacity_fraction( int capacity, int volume ) { // fraction of capacity the item would occupy diff --git a/src/advanced_inv.cpp b/src/advanced_inv.cpp index ad92a4cfbd93c..c13bb397ff54f 100644 --- a/src/advanced_inv.cpp +++ b/src/advanced_inv.cpp @@ -59,7 +59,6 @@ static const activity_id ACT_ADV_INVENTORY( "ACT_ADV_INVENTORY" ); static const activity_id ACT_DROP( "ACT_DROP" ); -static const activity_id ACT_PICKUP( "ACT_PICKUP" ); static const activity_id ACT_WEAR( "ACT_WEAR" ); static const trait_id trait_DEBUG_STORAGE( "DEBUG_STORAGE" ); @@ -919,48 +918,9 @@ bool advanced_inventory::move_all_items( bool nested_call ) g->u.drop( dropped, g->u.pos() + darea.off ); } else { - if( dpane.get_area() == AIM_INVENTORY || dpane.get_area() == AIM_WORN ) { - g->u.assign_activity( ACT_PICKUP ); - g->u.activity.coords.push_back( g->u.pos() ); - - item_stack::iterator stack_begin, stack_end; - if( panes[src].in_vehicle() ) { - vehicle_stack targets = sarea.veh->get_items( sarea.vstor ); - stack_begin = targets.begin(); - stack_end = targets.end(); - } else { - map_stack targets = g->m.i_at( sarea.pos ); - stack_begin = targets.begin(); - stack_end = targets.end(); - } - - // 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; - 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 ) { - if( spane.is_filtered( *it ) ) { - continue; - } - if( filter_buckets && it->is_bucket_nonempty() ) { - filtered_any_bucket = true; - continue; - } - if( spane.in_vehicle() ) { - g->u.activity.targets.emplace_back( vehicle_cursor( *sarea.veh, sarea.vstor ), &*it ); - } else { - g->u.activity.targets.emplace_back( map_cursor( sarea.pos ), &*it ); - } - // quantity of 0 means move all - g->u.activity.values.push_back( 0 ); - } - - if( filtered_any_bucket ) { - add_msg( m_info, _( "Skipping filled buckets to avoid spilling their contents." ) ); - } - + if( dpane.get_area() == AIM_WORN ) { + // TODO: Start ACT_WEAR in this case + debugmsg( "Wearing clothes using move all is not yet implemented" ); } else { // Vehicle and map destinations are handled the same. // Check first if the destination area still have enough room for moving all. @@ -1013,12 +973,20 @@ bool advanced_inventory::move_all_items( bool nested_call ) add_msg( m_info, _( "Skipping filled buckets to avoid spilling their contents." ) ); } - g->u.assign_activity( player_activity( move_items_activity_actor( - target_items, - quantities, - dpane.in_vehicle(), - relative_destination - ) ) ); + if( dpane.get_area() == AIM_INVENTORY ) { + g->u.assign_activity( player_activity( pickup_activity_actor( + target_items, + quantities, + panes[src].in_vehicle() ? cata::nullopt : cata::optional( g->u.pos() ) + ) ) ); + } else { + g->u.assign_activity( player_activity( move_items_activity_actor( + target_items, + quantities, + dpane.in_vehicle(), + relative_destination + ) ) ); + } } } @@ -1187,13 +1155,8 @@ void advanced_inventory::start_activity( const aim_location destarea, const aim_ const bool by_charges = sitem->items.front()->count_by_charges(); - if( destarea == AIM_INVENTORY || destarea == AIM_WORN ) { - if( destarea == AIM_INVENTORY ) { - g->u.assign_activity( ACT_PICKUP ); - g->u.activity.coords.push_back( g->u.pos() ); - } else { - g->u.assign_activity( ACT_WEAR ); - } + if( destarea == AIM_WORN ) { + g->u.assign_activity( ACT_WEAR ); if( by_charges ) { if( from_vehicle ) { @@ -1217,10 +1180,6 @@ void advanced_inventory::start_activity( const aim_location destarea, const aim_ } } } else { - // Vehicle and map destinations are handled similarly. - // Stash the destination - const tripoint relative_destination = squares[destarea].off; - // Find target items and quantities thereof for the new activity std::vector target_items; std::vector quantities; @@ -1246,12 +1205,23 @@ void advanced_inventory::start_activity( const aim_location destarea, const aim_ } } - g->u.assign_activity( player_activity( move_items_activity_actor( - target_items, - quantities, - to_vehicle, - relative_destination - ) ) ); + if( destarea == AIM_INVENTORY ) { + g->u.assign_activity( player_activity( pickup_activity_actor( + target_items, + quantities, + from_vehicle ? cata::nullopt : cata::optional( g->u.pos() ) + ) ) ); + } else { + // Stash the destination + const tripoint relative_destination = squares[destarea].off; + + g->u.assign_activity( player_activity( move_items_activity_actor( + target_items, + quantities, + to_vehicle, + relative_destination + ) ) ); + } } } diff --git a/src/iexamine.cpp b/src/iexamine.cpp index a5b59cf751613..7087a6d4a539a 100644 --- a/src/iexamine.cpp +++ b/src/iexamine.cpp @@ -98,7 +98,6 @@ static const activity_id ACT_BUILD( "ACT_BUILD" ); static const activity_id ACT_CLEAR_RUBBLE( "ACT_CLEAR_RUBBLE" ); static const activity_id ACT_CRACKING( "ACT_CRACKING" ); static const activity_id ACT_FORAGE( "ACT_FORAGE" ); -static const activity_id ACT_PICKUP( "ACT_PICKUP" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); static const efftype_id effect_earphones( "earphones" ); @@ -3371,9 +3370,8 @@ void iexamine::tree_maple_tapped( player &p, const tripoint &examp ) } case REMOVE_CONTAINER: { - g->u.assign_activity( ACT_PICKUP ); - g->u.activity.targets.emplace_back( map_cursor( examp ), container ); - g->u.activity.values.push_back( 0 ); + g->u.assign_activity( player_activity( pickup_activity_actor( + { item_location( map_cursor( examp ), container ) }, { 0 }, g->u.pos() ) ) ); return; } @@ -3659,9 +3657,8 @@ void iexamine::reload_furniture( player &p, const tripoint &examp ) auto items = g->m.i_at( examp ); for( auto &itm : items ) { if( itm.type == ammo ) { - p.assign_activity( ACT_PICKUP ); - p.activity.targets.emplace_back( map_cursor( examp ), &itm ); - p.activity.values.push_back( 0 ); + g->u.assign_activity( player_activity( pickup_activity_actor( + { item_location( map_cursor( examp ), &itm ) }, { 0 }, g->u.pos() ) ) ); return; } } diff --git a/src/pickup.cpp b/src/pickup.cpp index 6070bc05b2d5f..f9eb9015a6bc6 100644 --- a/src/pickup.cpp +++ b/src/pickup.cpp @@ -501,15 +501,19 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) // Not many items, just grab them if( static_cast( here.size() ) <= min && min != -1 ) { - g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); if( from_vehicle ) { - g->u.activity.targets.emplace_back( vehicle_cursor( *veh, cargo_part ), &*here.front() ); + g->u.assign_activity( player_activity( pickup_activity_actor( + { item_location( vehicle_cursor( *veh, cargo_part ), &*here.front() ) }, + { 0 }, + cata::nullopt + ) ) ); } else { - g->u.activity.targets.emplace_back( map_cursor( p ), &*here.front() ); - g->u.activity.coords.push_back( g->u.pos() ); + g->u.assign_activity( player_activity( pickup_activity_actor( + {item_location( map_cursor( p ), &*here.front() ) }, + { 0 }, + g->u.pos() + ) ) ); } - // auto-pickup means pick up all. - g->u.activity.values.push_back( 0 ); return; } @@ -976,12 +980,6 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) } // At this point we've selected our items, register an activity to pick them up. - g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); - g->u.activity.coords.push_back( g->u.pos() ); - if( min == -1 ) { - // Auto pickup will need to auto resume since there can be several of them on the stack. - g->u.activity.auto_resume = true; - } std::vector> pick_values; for( size_t i = 0; i < stacked_here.size(); i++ ) { const pickup_count &selection = getitem[i]; @@ -1010,13 +1008,22 @@ void Pickup::pick_up( const tripoint &p, int min, from_where get_items_from ) } } + std::vector target_items; + std::vector quantities; for( std::pair &iter_qty : pick_values ) { if( from_vehicle ) { - g->u.activity.targets.emplace_back( vehicle_cursor( *veh, cargo_part ), &*iter_qty.first ); + target_items.emplace_back( vehicle_cursor( *veh, cargo_part ), &*iter_qty.first ); } else { - g->u.activity.targets.emplace_back( map_cursor( p ), &*iter_qty.first ); + target_items.emplace_back( map_cursor( p ), &*iter_qty.first ); } - g->u.activity.values.push_back( iter_qty.second ); + quantities.push_back( iter_qty.second ); + } + + g->u.assign_activity( player_activity( pickup_activity_actor( target_items, quantities, + g->u.pos() ) ) ); + if( min == -1 ) { + // Auto pickup will need to auto resume since there can be several of them on the stack. + g->u.activity.auto_resume = true; } g->reenter_fullscreen(); diff --git a/tests/invlet_test.cpp b/tests/invlet_test.cpp index 6d18baff04926..c599c63966d46 100644 --- a/tests/invlet_test.cpp +++ b/tests/invlet_test.cpp @@ -261,9 +261,8 @@ static void pick_up_from_feet( player &p, int id ) REQUIRE( found ); p.moves = 100; - p.assign_activity( activity_id( "ACT_PICKUP" ) ); - p.activity.targets.emplace_back( map_cursor( p.pos() ), found ); - p.activity.values.push_back( 0 ); + p.assign_activity( player_activity( pickup_activity_actor( { item_location( map_cursor( p.pos() ), found ) }, { 0 }, + p.pos() ) ) ); p.activity.do_turn( p ); REQUIRE( items.size() == size_before - 1 );