From 2a5edfa2916db84829a78109cb5405ee1c04a2db Mon Sep 17 00:00:00 2001 From: SurFlurer <22912139+SurFlurer@users.noreply.github.com> Date: Thu, 5 Sep 2024 00:50:17 +0000 Subject: [PATCH] Migrate ACT_PULP to the new activity actor system (#76163) * Migrate ACT_PULP to the new activity actor system * satisfy clang --- src/activity_actor.cpp | 155 +++++++++++++++++++++++++++++++ src/activity_actor_definitions.h | 35 +++++++ src/activity_handlers.cpp | 122 ------------------------ src/activity_handlers.h | 2 - src/game.cpp | 28 +++--- src/handle_action.cpp | 5 +- src/npcmove.cpp | 5 +- 7 files changed, 209 insertions(+), 143 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index fd0d68eccbcba..ab9f2c1eec86d 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -159,6 +159,7 @@ static const activity_id ACT_PICKUP( "ACT_PICKUP" ); static const activity_id ACT_PICKUP_MENU( "ACT_PICKUP_MENU" ); 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_PULP( "ACT_PULP" ); static const activity_id ACT_READ( "ACT_READ" ); static const activity_id ACT_REEL_CABLE( "ACT_REEL_CABLE" ); static const activity_id ACT_RELOAD( "ACT_RELOAD" ); @@ -182,6 +183,11 @@ static const activity_id ACT_WORKOUT_MODERATE( "ACT_WORKOUT_MODERATE" ); static const ammotype ammo_plutonium( "plutonium" ); +static const damage_type_id damage_acid( "acid" ); +static const damage_type_id damage_bash( "bash" ); +static const damage_type_id damage_cut( "cut" ); +static const damage_type_id damage_stab( "stab" ); + static const efftype_id effect_docile( "docile" ); static const efftype_id effect_downed( "downed" ); static const efftype_id effect_gliding( "gliding" ); @@ -7968,6 +7974,154 @@ std::unique_ptr wash_activity_actor::deserialize( JsonValue &jsi return actor.clone(); } +void pulp_activity_actor::start( player_activity &act, Character & ) +{ + act.moves_total = calendar::INDEFINITELY_LONG; + act.moves_left = calendar::INDEFINITELY_LONG; +} + +void pulp_activity_actor::do_turn( player_activity &act, Character &you ) +{ + map &here = get_map(); + + const item_location weapon = you.get_wielded_item(); + int weap_cut = 0; + int weap_stab = 0; + int weap_bash = 0; + int mess_radius = 1; + + if( weapon ) { + // FIXME: Hardcoded damage types + weap_cut = weapon->damage_melee( damage_cut ); + weap_stab = weapon->damage_melee( damage_stab ); + weap_bash = weapon->damage_melee( damage_bash ); + if( weapon->has_flag( flag_MESSY ) ) { + mess_radius = 2; + } + } + + // Stabbing weapons are a lot less effective at pulping + const int cut_power = std::max( weap_cut, weap_stab / 2 ); + + ///\EFFECT_STR increases pulping power, with diminishing returns + float pulp_power = std::sqrt( ( you.get_arm_str() + weap_bash ) * ( cut_power + 1.0f ) ); + float pulp_effort = you.str_cur + weap_bash; + + // Multiplier to get the chance right + some bonus for survival skill + pulp_power *= 40 + you.get_skill_level( skill_survival ) * 5; + + int moves = 0; + for( auto pos_iter = placement.cbegin(); pos_iter != placement.end();/*left - out*/ ) { + const tripoint &pos = here.getlocal( *pos_iter ); + map_stack corpse_pile = here.i_at( pos ); + for( item &corpse : corpse_pile ) { + if( !corpse.is_corpse() || !corpse.can_revive() ) { + // Don't smash non-rezing corpses + continue; + } + + const mtype *corpse_mtype = corpse.get_mtype(); + const bool acid_immune = you.is_immune_damage( damage_acid ) || + you.is_immune_field( fd_acid ); + if( corpse_mtype->bloodType().obj().has_acid && ( !acid_immune || !pulp_acid ) ) { + //don't smash acid zombies when auto pulping unprotected + continue; + } + while( corpse.damage() < corpse.max_damage() ) { + // Increase damage as we keep smashing ensuring we eventually smash the target. + if( x_in_y( pulp_power, corpse.volume() / units::legacy_volume_factor ) ) { + corpse.inc_damage(); + if( corpse.damage() == corpse.max_damage() ) { + num_corpses++; + } + } + + if( x_in_y( pulp_power, corpse.volume() / units::legacy_volume_factor ) ) { + // Splatter some blood around + // Splatter a bit more randomly, so that it looks cooler + const int radius = mess_radius + x_in_y( pulp_power, 500 ) + x_in_y( pulp_power, 1000 ); + const tripoint dest( pos + point( rng( -radius, radius ), rng( -radius, radius ) ) ); + const field_type_id type_blood = ( mess_radius > 1 && x_in_y( pulp_power, 10000 ) ) ? + corpse.get_mtype()->gibType() : + corpse.get_mtype()->bloodType(); + here.add_splatter_trail( type_blood, pos, dest ); + } + + // mixture of isaac clarke stomps and swinging your weapon + you.burn_energy_all( -pulp_effort ); + you.recoil = MAX_RECOIL; + + if( one_in( 4 ) ) { + // Smashing may not be butchery, but it involves some zombie anatomy + you.practice( skill_survival, 2, 2 ); + } + + float stamina_ratio = static_cast( you.get_stamina() ) / you.get_stamina_max(); + moves += 100 / std::max( 0.25f, + stamina_ratio ) * you.exertion_adjusted_move_multiplier( act.exertion_level() ); + if( stamina_ratio < 0.33 || you.is_npc() ) { + you.set_moves( std::min( 0, you.get_moves() - moves ) ); + return; + } + if( moves >= you.get_moves() ) { + // Enough for this turn; + you.set_moves( you.get_moves() - moves ); + return; + } + } + corpse.set_flag( flag_PULPED ); + } + //Upon reach here, we have cleared one maptile + pos_iter = placement.erase( pos_iter ); + } + + // If we reach this, all corpses have been pulped, finish the activity + act.moves_left = 0; + if( num_corpses == 0 ) { + you.add_msg_if_player( m_bad, _( "The corpse moved before you could finish smashing it!" ) ); + return; + } + // TODO: Factor in how long it took to do the smashing. + you.add_msg_player_or_npc( n_gettext( "The corpse is thoroughly pulped.", + "The corpses are thoroughly pulped.", num_corpses ), + n_gettext( " finished pulping the corpse.", + " finished pulping the corpses.", num_corpses ) ); +} + +void pulp_activity_actor::finish( player_activity &act, Character &you ) +{ + if( you.is_npc() ) { + you.as_npc()->revert_after_activity(); + you.as_npc()->pulp_location.reset(); + } else { + act.set_to_null(); + } +} + +void pulp_activity_actor::serialize( JsonOut &jsout ) const +{ + jsout.start_object(); + + jsout.member( "num_corpses", num_corpses ); + jsout.member( "placement", placement ); + jsout.member( "pulp_acid", pulp_acid ); + + jsout.end_object(); +} + +std::unique_ptr pulp_activity_actor::deserialize( JsonValue &jsin ) +{ + pulp_activity_actor actor; + + JsonObject data = jsin.get_object(); + + data.read( "num_corpses", actor.num_corpses ); + data.read( "placement", actor.placement ); + data.read( "pulp_acid", actor.pulp_acid ); + + return actor.clone(); +} + namespace activity_actors { @@ -8020,6 +8174,7 @@ deserialize_functions = { { ACT_PICKUP_MENU, &pickup_menu_activity_actor::deserialize }, { ACT_PLAY_WITH_PET, &play_with_pet_activity_actor::deserialize }, { ACT_PRYING, &prying_activity_actor::deserialize }, + { ACT_PULP, &pulp_activity_actor::deserialize }, { ACT_READ, &read_activity_actor::deserialize }, { ACT_REEL_CABLE, &reel_cable_activity_actor::deserialize }, { ACT_RELOAD, &reload_activity_actor::deserialize }, diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index 936158c5a09f2..6a49c793c7861 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -2185,4 +2185,39 @@ class unload_loot_activity_actor : public activity_actor tripoint placement; }; +class pulp_activity_actor : public activity_actor +{ + public: + pulp_activity_actor() = default; + explicit pulp_activity_actor( const tripoint_abs_ms placement, + const bool pulp_acid = false ) : placement( { placement } ), + num_corpses( 0 ), pulp_acid( pulp_acid ) {} + explicit pulp_activity_actor( const std::set &placement, + const bool pulp_acid = false ) : placement( placement ), num_corpses( 0 ), pulp_acid( pulp_acid ) {} + activity_id get_type() const override { + return activity_id( "ACT_PULP" ); + } + + void start( player_activity &act, Character &who ) override; + void do_turn( player_activity &act, Character &you ) 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( JsonValue &jsin ); + + private: + bool can_resume_with_internal( const activity_actor &other, + const Character &/*who*/ ) const override { + const pulp_activity_actor &actor = static_cast( other ); + return actor.pulp_acid == pulp_acid; + } + std::set placement; + int num_corpses; + bool pulp_acid; +}; + #endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 989825905925d..ed48fa854e717 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -149,7 +149,6 @@ static const activity_id ACT_OPERATION( "ACT_OPERATION" ); static const activity_id ACT_PICKAXE( "ACT_PICKAXE" ); static const activity_id ACT_PLANT_SEED( "ACT_PLANT_SEED" ); static const activity_id ACT_PULL_CREATURE( "ACT_PULL_CREATURE" ); -static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_QUARTER( "ACT_QUARTER" ); static const activity_id ACT_REPAIR_ITEM( "ACT_REPAIR_ITEM" ); static const activity_id ACT_ROBOT_CONTROL( "ACT_ROBOT_CONTROL" ); @@ -179,11 +178,6 @@ static const ammotype ammo_battery( "battery" ); static const bionic_id bio_painkiller( "bio_painkiller" ); -static const damage_type_id damage_acid( "acid" ); -static const damage_type_id damage_bash( "bash" ); -static const damage_type_id damage_cut( "cut" ); -static const damage_type_id damage_stab( "stab" ); - static const efftype_id effect_asocial_dissatisfied( "asocial_dissatisfied" ); static const efftype_id effect_bleed( "bleed" ); static const efftype_id effect_blind( "blind" ); @@ -260,7 +254,6 @@ const std::map< activity_id, std::functionplacement ); - - const item_location weapon = you->get_wielded_item(); - int weap_cut = 0; - int weap_stab = 0; - int weap_bash = 0; - int mess_radius = 1; - - if( weapon ) { - // FIXME: Hardcoded damage types - weap_cut = weapon->damage_melee( damage_cut ); - weap_stab = weapon->damage_melee( damage_stab ); - weap_bash = weapon->damage_melee( damage_bash ); - if( weapon->has_flag( flag_MESSY ) ) { - mess_radius = 2; - } - } - - // Stabbing weapons are a lot less effective at pulping - const int cut_power = std::max( weap_cut, weap_stab / 2 ); - - ///\EFFECT_STR increases pulping power, with diminishing returns - float pulp_power = std::sqrt( ( you->get_arm_str() + weap_bash ) * ( cut_power + 1.0f ) ); - float pulp_effort = you->str_cur + weap_bash; - - // Multiplier to get the chance right + some bonus for survival skill - pulp_power *= 40 + you->get_skill_level( skill_survival ) * 5; - - int moves = 0; - // use this to collect how many corpse are pulped - int &num_corpses = act->index; - map_stack corpse_pile = here.i_at( pos ); - for( item &corpse : corpse_pile ) { - const mtype *corpse_mtype = corpse.get_mtype(); - const bool acid_immune = you->is_immune_damage( damage_acid ) || - you->is_immune_field( fd_acid ); - if( !corpse.is_corpse() || !corpse.can_revive() || - ( ( std::find( act->str_values.begin(), act->str_values.end(), "auto_pulp_no_acid" ) != - act->str_values.end() && corpse_mtype->bloodType().obj().has_acid ) && !acid_immune ) ) { - // Don't smash non-rezing corpses //don't smash acid zombies when auto pulping unprotected - continue; - } - - while( corpse.damage() < corpse.max_damage() ) { - // Increase damage as we keep smashing ensuring we eventually smash the target. - if( x_in_y( pulp_power, corpse.volume() / units::legacy_volume_factor ) ) { - corpse.inc_damage(); - if( corpse.damage() == corpse.max_damage() ) { - num_corpses++; - } - } - - if( x_in_y( pulp_power, corpse.volume() / units::legacy_volume_factor ) ) { - // Splatter some blood around - // Splatter a bit more randomly, so that it looks cooler - const int radius = mess_radius + x_in_y( pulp_power, 500 ) + x_in_y( pulp_power, 1000 ); - const tripoint_bub_ms dest( pos + point( rng( -radius, radius ), rng( -radius, radius ) ) ); - const field_type_id type_blood = ( mess_radius > 1 && x_in_y( pulp_power, 10000 ) ) ? - corpse.get_mtype()->gibType() : - corpse.get_mtype()->bloodType(); - here.add_splatter_trail( type_blood, pos.raw(), dest.raw() ); - } - - // mixture of isaac clarke stomps and swinging your weapon - you->burn_energy_all( -pulp_effort ); - you->recoil = MAX_RECOIL; - - if( one_in( 4 ) ) { - // Smashing may not be butchery, but it involves some zombie anatomy - you->practice( skill_survival, 2, 2 ); - } - - float stamina_ratio = static_cast( you->get_stamina() ) / you->get_stamina_max(); - moves += 100 / std::max( 0.25f, - stamina_ratio ) * you->exertion_adjusted_move_multiplier( act->exertion_level() ); - if( stamina_ratio < 0.33 || you->is_npc() ) { - you->set_moves( std::min( 0, you->get_moves() - moves ) ); - return; - } - if( moves >= you->get_moves() ) { - // Enough for this turn; - you->mod_moves( -moves ); - return; - } - } - corpse.set_flag( flag_PULPED ); - } - // If we reach this, all corpses have been pulped, finish the activity - act->moves_left = 0; - if( num_corpses == 0 ) { - you->add_msg_if_player( m_bad, _( "The corpse moved before you could finish smashing it!" ) ); - return; - } - // TODO: Factor in how long it took to do the smashing. - you->add_msg_player_or_npc( n_gettext( "The corpse is thoroughly pulped.", - "The corpses are thoroughly pulped.", num_corpses ), - n_gettext( " finished pulping the corpse.", - " finished pulping the corpses.", num_corpses ) ); -} - -void activity_handlers::pulp_finish( player_activity *act, Character *you ) -{ - if( you->is_npc() ) { - npc *guy = dynamic_cast( you ); - guy->revert_after_activity(); - guy->pulp_location.reset(); - } else { - act->set_to_null(); - } -} - void activity_handlers::start_fire_finish( player_activity *act, Character *you ) { static const std::string iuse_name_string( "firestarter" ); diff --git a/src/activity_handlers.h b/src/activity_handlers.h index cf33d8244e219..f44aca6a45a2d 100644 --- a/src/activity_handlers.h +++ b/src/activity_handlers.h @@ -231,7 +231,6 @@ void multiple_mine_do_turn( player_activity *act, Character *you ); void multiple_mop_do_turn( player_activity *act, Character *you ); void operation_do_turn( player_activity *act, Character *you ); void pickaxe_do_turn( player_activity *act, Character *you ); -void pulp_do_turn( player_activity *act, Character *you ); void repair_item_do_turn( player_activity *act, Character *you ); void robot_control_do_turn( player_activity *act, Character *you ); void start_fire_do_turn( player_activity *act, Character *you ); @@ -263,7 +262,6 @@ void operation_finish( player_activity *act, Character *you ); void pickaxe_finish( player_activity *act, Character *you ); void plant_seed_finish( player_activity *act, Character *you ); void pull_creature_finish( player_activity *act, Character *you ); -void pulp_finish( player_activity *act, Character *you ); void repair_item_finish( player_activity *act, Character *you ); void robot_control_finish( player_activity *act, Character *you ); void socialize_finish( player_activity *act, Character *you ); diff --git a/src/game.cpp b/src/game.cpp index 95c12cce52389..a680828e8cb16 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -229,7 +229,6 @@ static const activity_id ACT_BUTCHER_FULL( "ACT_BUTCHER_FULL" ); static const activity_id ACT_DISMEMBER( "ACT_DISMEMBER" ); static const activity_id ACT_DISSECT( "ACT_DISSECT" ); static const activity_id ACT_FIELD_DRESS( "ACT_FIELD_DRESS" ); -static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_QUARTER( "ACT_QUARTER" ); static const activity_id ACT_SKIN( "ACT_SKIN" ); static const activity_id ACT_TRAIN( "ACT_TRAIN" ); @@ -10918,32 +10917,37 @@ point game::place_player( const tripoint &dest_loc, bool quick ) } else if( pulp_butcher == "pulp" || pulp_butcher == "pulp_adjacent" || pulp_butcher == "pulp_zombie_only" || pulp_butcher == "pulp_adjacent_zombie_only" ) { const bool acid_immune = u.is_immune_damage( damage_acid ) || u.is_immune_field( fd_acid ); - const auto pulp = [&]( const tripoint_bub_ms & pos ) { + const auto corpse_available = [&]( const tripoint_bub_ms & pos ) { for( const item &maybe_corpse : m.i_at( pos ) ) { if( maybe_corpse.is_corpse() && maybe_corpse.can_revive() && ( !maybe_corpse.get_mtype()->bloodType().obj().has_acid || acid_immune ) ) { - if( pulp_butcher == "pulp_zombie_only" || pulp_butcher == "pulp_adjacent_zombie_only" ) { if( !maybe_corpse.get_mtype()->has_flag( mon_flag_REVIVES ) ) { continue; + } else { + return true; } + } else { + return true; } - - u.assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); - u.activity.placement = m.getglobal( pos ); - u.activity.auto_resume = true; - u.activity.str_values.emplace_back( "auto_pulp_no_acid" ); - return; } } + return false; }; - if( pulp_butcher == "pulp_adjacent" || pulp_butcher == "pulp_adjacent_zombie_only" ) { + std::set places; for( const direction &elem : adjacentDir ) { - pulp( u.pos_bub() + displace_XY( elem ) ); + if( corpse_available( u.pos_bub() + displace_XY( elem ) ) ) { + places.emplace( m.getglobal( u.pos_bub() + displace_XY( elem ) ) ); + } + } + if( !places.empty() ) { + u.assign_activity( pulp_activity_actor( places, true ) ); } } else { - pulp( u.pos_bub() ); + if( corpse_available( u.pos_bub() ) ) { + u.assign_activity( pulp_activity_actor( m.getglobal( u.pos_bub() ), true ) ); + } } } } diff --git a/src/handle_action.cpp b/src/handle_action.cpp index 270fd74b2219b..e29a54e183a11 100644 --- a/src/handle_action.cpp +++ b/src/handle_action.cpp @@ -115,7 +115,6 @@ static const activity_id ACT_MULTIPLE_DIS( "ACT_MULTIPLE_DIS" ); static const activity_id ACT_MULTIPLE_FARM( "ACT_MULTIPLE_FARM" ); static const activity_id ACT_MULTIPLE_MINE( "ACT_MULTIPLE_MINE" ); static const activity_id ACT_MULTIPLE_MOP( "ACT_MULTIPLE_MOP" ); -static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_SPELLCASTING( "ACT_SPELLCASTING" ); static const activity_id ACT_VEHICLE_DECONSTRUCTION( "ACT_VEHICLE_DECONSTRUCTION" ); static const activity_id ACT_VEHICLE_REPAIR( "ACT_VEHICLE_REPAIR" ); @@ -975,9 +974,7 @@ static void smash() } if( should_pulp ) { - // do activity forever. ACT_PULP stops itself - player_character.assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); - player_character.activity.placement = here.getglobal( smashp ); + player_character.assign_activity( pulp_activity_actor( here.getglobal( smashp ) ) ); return; // don't smash terrain if we've smashed a corpse } diff --git a/src/npcmove.cpp b/src/npcmove.cpp index d6a1454150182..d5f7f32c40c0a 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -13,6 +13,7 @@ #include "active_item_cache.h" #include "activity_handlers.h" +#include "activity_actor_definitions.h" #include "ammo.h" #include "avatar.h" #include "basecamp.h" @@ -87,7 +88,6 @@ static const activity_id ACT_CRAFT( "ACT_CRAFT" ); static const activity_id ACT_FIRSTAID( "ACT_FIRSTAID" ); static const activity_id ACT_MOVE_LOOT( "ACT_MOVE_LOOT" ); static const activity_id ACT_OPERATION( "ACT_OPERATION" ); -static const activity_id ACT_PULP( "ACT_PULP" ); static const activity_id ACT_SPELLCASTING( "ACT_SPELLCASTING" ); static const activity_id ACT_TIDY_UP( "ACT_TIDY_UP" ); @@ -2517,8 +2517,7 @@ npc_action npc::address_needs( float danger ) if( can_do_pulp() ) { if( !activity ) { - assign_activity( ACT_PULP, calendar::INDEFINITELY_LONG, 0 ); - activity.placement = *pulp_location; + assign_activity( pulp_activity_actor( *pulp_location ) ); } return npc_player_activity; } else if( find_corpse_to_pulp() ) {