Skip to content

Commit

Permalink
Move to an activity actor
Browse files Browse the repository at this point in the history
  • Loading branch information
RenechCDDA committed May 12, 2024
1 parent e70fb26 commit 6eed95d
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 29 deletions.
8 changes: 8 additions & 0 deletions data/json/player_activities.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
81 changes: 81 additions & 0 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5568,6 +5568,87 @@ std::unique_ptr<activity_actor> reel_cable_activity_actor::deserialize( JsonValu
return actor.clone();
}

void outfit_swap_actor::start( player_activity &act, Character &who )
{
item fake_storage( outfit_item->typeId() );
for( const item_location &worn_item : who.get_visible_worn_items() ) {
act.moves_total += who.item_handling_cost( *worn_item ); // Cost of taking it off
act.moves_total += who.item_store_cost( *worn_item, fake_storage ); // And putting it away
}
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<item> 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<activity_actor> 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<int>( 20_minutes );
Expand Down
26 changes: 26 additions & 0 deletions src/activity_actor_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<activity_actor> clone() const override {
return std::make_unique<outfit_swap_actor>( *this );
}

void serialize( JsonOut & ) const override;
static std::unique_ptr<activity_actor> 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:
Expand Down
33 changes: 4 additions & 29 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8786,42 +8786,17 @@ std::optional<int> iuse::measure_resonance( Character *p, item *it, const tripoi
return 0;
}

std::optional<int> iuse::change_outfit( Character *p, item *it, const tripoint &there )
std::optional<int> iuse::change_outfit( Character *p, item *it, const tripoint & )
{
if( !p->is_avatar() ) {
debugmsg( "NPC %s tried to swap outfit", p->get_name() );
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<item> 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<int> iuse::electricstorage( Character *p, item *it, const tripoint & )
Expand Down

0 comments on commit 6eed95d

Please sign in to comment.