From 4bdcc1a3fe0ca9f9e3e7742017290fc735a936bf Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Sat, 11 May 2024 23:05:34 -0400 Subject: [PATCH] Move to an activity actor --- data/json/player_activities.json | 8 ++++ src/activity_actor.cpp | 76 ++++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 26 +++++++++++ src/iuse.cpp | 31 ++----------- 4 files changed, 113 insertions(+), 28 deletions(-) diff --git a/data/json/player_activities.json b/data/json/player_activities.json index f8da0e7a2b8ff..5817c6268919a 100644 --- a/data/json/player_activities.json +++ b/data/json/player_activities.json @@ -730,6 +730,14 @@ "rooted": true, "based_on": "speed" }, + { + "id": "ACT_OUTFIT_SWAP", + "type": "activity_type", + "activity_level": "LIGHT_EXERCISE", + "verb": "changing clothes", + "rooted": true, + "based_on": "speed" + }, { "id": "ACT_WASH", "type": "activity_type", diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index a28b78c73dfc5..f0faf3986b8c1 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -5568,6 +5568,82 @@ std::unique_ptr reel_cable_activity_actor::deserialize( JsonValu return actor.clone(); } +void outfit_swap_actor::start( player_activity &act, Character &who ) +{ + for( const item *clothing : outfit_item->all_items_top() ) { + auto ret = who.can_wear( *clothing ); + // Note this is checking if we can put something new on, but it might conflict with our current clothing, causing a + // spurious failure. Maybe we should strip the player first? + if( ret.success() ) { + act.moves_total += who.item_wear_cost( *clothing ); + } else { + act.moves_total += who.item_retrieve_cost( *clothing, *outfit_item ); + // Dropping takes no time? So I guess that's all we need + } + } + act.moves_left = act.moves_total; +} + +void outfit_swap_actor::finish( player_activity &act, Character &who ) +{ + map &here = get_map(); + // First, make a new outfit and shove all our existing clothes into it. + item new_outfit( outfit_item->typeId() ); + item_location ground = here.add_item_ret_loc( who.pos(), new_outfit, true ); + if( !ground ) { + debugmsg( "Failed to swap outfits during outfit_swap_actor::finish" ); + act.set_to_null(); + return; + } + // Taken-off items are put in this temporary list, then naturally deleted from the world when the function returns. + std::list it_list; + for( item_location &worn_item : who.get_visible_worn_items() ) { + item outfit_component( *worn_item ); + if( who.takeoff( worn_item, &it_list ) ) { + ground->force_insert_item( outfit_component, pocket_type::CONTAINER ); + } + } + + // Now we have to take clothes out of the one we activated + for( item *component : outfit_item->all_items_top() ) { + auto ret = who.can_wear( *component ); + if( ret.success() ) { + item_location new_clothes( who, component ); + who.wear( new_clothes ); + } else { + // For some reason we couldn't wear this item. Maybe the player mutated in the meanwhile, but + // drop the item instead of deleting it. + here.add_item( who.pos(), *component ); + } + } + + who.i_rem( outfit_item.get_item() ); + + // Now we just did a whole bunch of wearing and taking off at once, but we had already paid that movecost by doing the activity + // So we reset our moves + who.set_moves( 0 ); + // TODO: Granularize this and allow resumable swapping if you were interrupted during the activity + + act.set_to_null(); +} + +void outfit_swap_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + jsout.member( "outfit_item", outfit_item ); + jsout.end_object(); +} + +std::unique_ptr outfit_swap_actor::deserialize( JsonValue &jsin ) +{ + outfit_swap_actor actor( {} ); + + JsonObject data = jsin.get_object(); + + data.read( "outfit_item", actor.outfit_item ); + return actor.clone(); +} + void meditate_activity_actor::start( player_activity &act, Character & ) { act.moves_total = to_moves( 20_minutes ); diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index ef9fb1d6204a5..59c64701caeb5 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -1413,6 +1413,32 @@ class oxytorch_activity_actor : public activity_actor } }; +class outfit_swap_actor : public activity_actor +{ + public: + explicit outfit_swap_actor( const item_location &outfit_item ) : outfit_item( outfit_item ) {}; + activity_id get_type() const override { + return activity_id( "ACT_OUTFIT_SWAP" ); + } + + void start( player_activity &act, Character &who ) 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 & ); + private: + item_location outfit_item; + + bool can_resume_with_internal( const activity_actor &, const Character & ) const override { + return false; + } +}; + class meditate_activity_actor : public activity_actor { public: diff --git a/src/iuse.cpp b/src/iuse.cpp index 8e647dc06bfe8..9b17ab7c51312 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -8793,35 +8793,10 @@ std::optional iuse::change_outfit( Character *p, item *it, const tripoint & return std::nullopt; } - map &here = get_map(); - - // First, make a new outfit and shove all our existing clothes into it. - item new_outfit( it->typeId() ); - item_location ground = here.add_item_ret_loc( there, new_outfit ); - // Taken-off items are put in this temporary list, then naturally deleted from the world when the function returns. - std::list it_list; - for( item_location &worn_item : p->get_visible_worn_items() ) { - item outfit_component( *worn_item ); - if( p->takeoff( worn_item, &it_list ) ) { - ground->force_insert_item( outfit_component, pocket_type::CONTAINER ); - } - } - - // Now we have to take clothes out of the one we activated - for( item *component : it->all_items_top() ) { - auto ret = p->can_wear( *component ); - if( ret.success() ) { - item_location new_clothes( *p, component ); - p->wear( new_clothes ); - } else { - // For some reason we couldn't wear this item. Maybe the player mutated in the meanwhile, but - // drop the item instead of deleting it. - here.add_item( there, *component ); - } - } + p->assign_activity( outfit_swap_actor( item_location{*p, it} ) ); - // Delete the outfit_storage we activated - return 1; + // Deleting the item we activated is handled in outfit_swap_actor::finish + return std::nullopt; } std::optional iuse::electricstorage( Character *p, item *it, const tripoint & )