diff --git a/data/json/player_activities.json b/data/json/player_activities.json index bb131af919029..4301ab3d826e7 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -1077,5 +1077,13 @@ "interruptable": false, "suspendable": false, "interruptable_with_kb": false + }, + { + "id": "ACT_RUMMAGE_POCKET", + "type": "activity_type", + "activity_level": "NO_EXERCISE", + "verb": "rummaging pocket", + "based_on": "speed", + "no_resume": true } ] diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 7c34bc7225369..3972129154a55 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -29,6 +29,7 @@ #include "creature_tracker.h" #include "debug.h" #include "enums.h" +#include "enum_conversions.h" #include "event.h" #include "event_bus.h" #include "field_type.h" @@ -116,6 +117,7 @@ static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" ); static const activity_id ACT_PRYING( "ACT_PRYING" ); static const activity_id ACT_READ( "ACT_READ" ); static const activity_id ACT_RELOAD( "ACT_RELOAD" ); +static const activity_id ACT_RUMMAGE_POCKET( "ACT_RUMMAGE_POCKET" ); static const activity_id ACT_SHAVE( "ACT_SHAVE" ); static const activity_id ACT_SHEARING( "ACT_SHEARING" ); static const activity_id ACT_STASH( "ACT_STASH" ); @@ -5194,6 +5196,140 @@ std::unique_ptr haircut_activity_actor::deserialize( JsonValue & return haircut_activity_actor().clone(); } +void rummage_activity_actor::start( player_activity &act, Character &who ) +{ + int moves = 0; + if( kind == action::drop ) { + for( const drop_location &i_loc : item_loc ) { + //Only add the move cost for items inside a container + if( i_loc.first.where() == item_location::type::container ) { + moves += i_loc.first.obtain_cost( who ); + } + } + } else { + moves += item_loc.front().first.obtain_cost( who ); + } + act.moves_total = moves; + act.moves_left = moves; +} + +void rummage_activity_actor::do_turn( player_activity &/*act*/, Character & /*who*/ ) +{ +} + +void rummage_activity_actor::finish( player_activity &act, Character &who ) +{ + who.add_msg_if_player( m_good, _( "You rummaged your pockets to find the item" ) ); + // some function calls in the switch block spawn activities e.g. + // avatar::read spawns an ACT_READ activity, so we need to set + // this one to null before calling them + act.set_to_null(); + + switch( kind ) { + case action::activate: { + avatar &player_character = get_avatar(); + avatar_action::use_item( player_character, item_loc.front().first ); + return; + } + case action::drop: { + who.drop( item_loc, m_pnt ); + return; + } + case action::eat: { + avatar &player_character = get_avatar(); + avatar_action::eat( player_character, item_loc.front().first ); + return; + } + case action::read: { + avatar &player_character = get_avatar(); + item_location i_loc = item_loc.front().first; + + if( i_loc->type->can_use( "learn_spell" ) ) { + item spell_book = *i_loc.get_item(); + spell_book.get_use( "learn_spell" )->call( + player_character, spell_book, spell_book.active, player_character.pos() ); + } else { + player_character.read( i_loc ); + } + return; + } + case action::wear: { + avatar &player_character = get_avatar(); + player_character.wear( item_loc.front().first ); + return; + } + case action::wield: { + avatar &player_character = get_avatar(); + player_character.wield( item_loc.front().first ); + return; + } + default: + debugmsg( "Unexpected action kind in rummage_pocket_activity_actor::finish" ); + return; + } +} + +void rummage_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "item_loc", item_loc ); + jsout.member_as_string( "action", kind ); + jsout.member( "m_pnt", m_pnt ); + + jsout.end_object(); +} + +std::unique_ptr rummage_activity_actor::deserialize( JsonValue &jsin ) +{ + rummage_activity_actor actor( drop_locations{}, action::none, tripoint_zero ); + + JsonObject data = jsin.get_object(); + + data.read( "item_loc", actor.item_loc ); + const action k = data.get_enum_value( "action" ); + actor.kind = k; + data.read( "m_pnt", actor.m_pnt ); + + return actor.clone(); +} + +namespace io +{ +template<> +std::string enum_to_string( + const rummage_activity_actor::action kind ) +{ + switch( kind ) { + case rummage_activity_actor::action::activate: + return "activate"; + case rummage_activity_actor::action::drop: + return "drop"; + case rummage_activity_actor::action::eat: + return "eat"; + case rummage_activity_actor::action::none: + return "none"; + case rummage_activity_actor::action::read: + return "read"; + case rummage_activity_actor::action::wear: + return "wear"; + case rummage_activity_actor::action::wield: + return "wield"; + case rummage_activity_actor::action::last: + break; + } + debugmsg( "Invalid rummage_activity_actor::action" ); + cata_fatal( "Invalid rummage_activity_actor::action" ); +} +} //namespace io + +template<> +struct enum_traits { + static constexpr rummage_activity_actor::action last = + rummage_activity_actor::action::last; +}; + + namespace activity_actors { @@ -5234,6 +5370,7 @@ deserialize_functions = { { ACT_PLAY_WITH_PET, &play_with_pet_activity_actor::deserialize }, { ACT_READ, &read_activity_actor::deserialize }, { ACT_RELOAD, &reload_activity_actor::deserialize }, + { ACT_RUMMAGE_POCKET, &rummage_activity_actor::deserialize }, { ACT_SHAVE, &shave_activity_actor::deserialize }, { ACT_SHEARING, &shearing_activity_actor::deserialize }, { ACT_STASH, &stash_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 45b12d33392ac..ac1cf9f49b674 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -1571,4 +1571,48 @@ class haircut_activity_actor : public activity_actor static std::unique_ptr deserialize( JsonValue & ); }; +class rummage_activity_actor : public activity_actor +{ + + public: + enum class action : int { + activate, + drop, + eat, + none, + read, + wear, + wield, + last + }; + using item_locations = drop_locations; + + private: + item_locations item_loc; + action kind; + tripoint m_pnt; + + public: + rummage_activity_actor() = default; + rummage_activity_actor( const item_location &i_loc, action act_kind, + const tripoint &pnt = tripoint_zero ) + : item_loc( { std::make_pair( i_loc, i_loc->count() ) } ), kind( act_kind ), m_pnt( pnt ) {} + rummage_activity_actor( const drop_locations &drop_loc, action act_kind, + const tripoint &pnt = tripoint_zero ) + : item_loc( drop_loc ), kind( act_kind ), m_pnt( pnt ) {} + activity_id get_type() const override { + return activity_id( "ACT_RUMMAGE_POCKET" ); + } + + void start( player_activity &act, Character & ) override; + void do_turn( player_activity &, Character & ) override; + void finish( player_activity &act, Character &who ) override; + + std::unique_ptr clone() const override { + return std::make_unique( *this ); + } + void serialize( JsonOut & ) const override; + static std::unique_ptr deserialize( JsonValue & ); +}; + #endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index fac065c63d43d..510f160316864 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -1080,8 +1080,13 @@ static void update_lum( item_location loc, bool add ) void avatar_action::use_item( avatar &you ) { - item_location loc; - avatar_action::use_item( you, loc ); + item_location loc = game_menus::inv::use( you ); + if( loc.where() == item_location::type::container ) { + you.assign_activity( player_activity( rummage_activity_actor( loc, + rummage_activity_actor::action::activate ) ) ); + } else { + avatar_action::use_item( you, loc ); + } } void avatar_action::use_item( avatar &you, item_location &loc ) diff --git a/src/game.cpp b/src/game.cpp index 1af6c631cf1d3..d3879a0d9ad9f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1886,7 +1886,13 @@ int game::inventory_item_menu( item_location locThisItem, if( locThisItem.get_item()->type->has_use() && !locThisItem.get_item()->item_has_uses_recursive( true ) ) { // Item has uses and none of its contents (if any) has uses. - avatar_action::use_item( u, locThisItem ); + + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::activate ) ) ); + } else { + avatar_action::use_item( u, locThisItem ); + } } else if( locThisItem.get_item()->item_has_uses_recursive() ) { game::item_action_menu( locThisItem ); } else { @@ -1898,7 +1904,13 @@ int game::inventory_item_menu( item_location locThisItem, } case 'E': if( !locThisItem.get_item()->is_container() ) { - avatar_action::eat( u, locThisItem ); + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::eat ) ) ) + ; + } else { + avatar_action::eat( u, locThisItem ); + } } else { avatar_action::eat( u, game_menus::inv::consume( u, locThisItem ) ); } @@ -1906,7 +1918,12 @@ int game::inventory_item_menu( item_location locThisItem, case 'W': { contents_change_handler handler; handler.unseal_pocket_containing( locThisItem ); - u.wear( locThisItem ); + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::wear ) ) ); + } else { + u.wear( locThisItem ); + } handler.handle_by( u ); break; } @@ -1914,7 +1931,12 @@ int game::inventory_item_menu( item_location locThisItem, if( u.can_wield( *locThisItem ).success() ) { contents_change_handler handler; handler.unseal_pocket_containing( locThisItem ); - wield( locThisItem ); + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::wield ) ) ); + } else { + wield( locThisItem ); + } handler.handle_by( u ); } else { add_msg( m_info, "%s", u.can_wield( *locThisItem ).c_str() ); @@ -1933,9 +1955,15 @@ int game::inventory_item_menu( item_location locThisItem, case 'T': u.takeoff( locThisItem ); break; - case 'd': - u.drop( locThisItem, u.pos() ); + case 'd': { + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::drop, u.pos() ) ) ); + } else { + u.drop( locThisItem, u.pos() ); + } break; + } case 'U': u.unload( locThisItem ); break; @@ -1948,9 +1976,15 @@ int game::inventory_item_menu( item_location locThisItem, case 'm': avatar_action::mend( u, locThisItem ); break; - case 'R': - u.read( locThisItem ); + case 'R': { + if( locThisItem.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( locThisItem, + rummage_activity_actor::action::read ) ) ); + } else { + u.read( locThisItem ); + } break; + } case 'D': u.disassemble( locThisItem, false ); break; @@ -7892,7 +7926,15 @@ void game::unload_container() void game::drop_in_direction( const tripoint &pnt ) { - u.drop( game_menus::inv::multidrop( u ), pnt ); + drop_locations drop_loc = game_menus::inv::multidrop( u ); + for( const drop_location &d_loc : drop_loc ) { + if( d_loc.first.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( drop_loc, + rummage_activity_actor::action::drop, pnt ) ) ); + return; + } + } + u.drop( drop_loc, pnt ); } // Used to set up the first Hotkey in the display set @@ -8738,7 +8780,12 @@ void game::wield() item_location loc = game_menus::inv::wield( u ); if( loc ) { - wield( loc ); + if( loc.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( loc, + rummage_activity_actor::action::wield ) ) ); + } else { + wield( loc ); + } } else { add_msg( _( "Never mind." ) ); } diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 6563a9743b1bc..623f5f7566a17 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -1313,7 +1313,12 @@ static void wear() item_location loc = game_menus::inv::wear( player_character ); if( loc ) { - player_character.wear( loc ); + if( loc.where() == item_location::type::container ) { + player_character.assign_activity( player_activity( rummage_activity_actor( loc, + rummage_activity_actor::action::wear ) ) ); + } else { + player_character.wear( loc ); + } } else { add_msg( _( "Never mind." ) ); } @@ -1338,13 +1343,19 @@ static void read() item_location loc = game_menus::inv::read( player_character ); if( loc ) { - if( loc->type->can_use( "learn_spell" ) ) { - item spell_book = *loc.get_item(); - spell_book.get_use( "learn_spell" )->call( player_character, spell_book, - spell_book.active, player_character.pos() ); + if( loc.where() == item_location::type::container ) { + player_character.assign_activity( player_activity( rummage_activity_actor( + loc, rummage_activity_actor::action::read + ) ) ); } else { - loc = loc.obtain( player_character ); - player_character.read( loc ); + if( loc->type->can_use( "learn_spell" ) ) { + item spell_book = *loc.get_item(); + spell_book.get_use( "learn_spell" )->call( player_character, spell_book, spell_book.active, + player_character.pos() ); + } else { + loc = loc.obtain( player_character ); + player_character.read( loc ); + } } } else { add_msg( _( "Never mind." ) ); @@ -2111,7 +2122,13 @@ bool game::do_regular_action( action_id &act, avatar &player_character, case ACTION_EAT: if( !avatar_action::eat_here( player_character ) ) { - avatar_action::eat( player_character, game_menus::inv::consume( player_character ) ); + item_location loc = game_menus::inv::consume( player_character ); + if( loc.where() == item_location::type::container ) { + u.assign_activity( player_activity( rummage_activity_actor( loc, + rummage_activity_actor::action::eat ) ) ); + } else { + avatar_action::eat( player_character, loc ); + } } break;