Skip to content

Commit

Permalink
Migrate ACT_PULP to the new activity actor system (#76163)
Browse files Browse the repository at this point in the history
* Migrate ACT_PULP to the new activity actor system

* satisfy clang
  • Loading branch information
SurFlurer authored Sep 5, 2024
1 parent 73fbff0 commit 2a5edfa
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 143 deletions.
155 changes: 155 additions & 0 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand All @@ -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" );
Expand Down Expand Up @@ -7968,6 +7974,154 @@ std::unique_ptr<activity_actor> 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<float>( 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( "<npcname> finished pulping the corpse.",
"<npcname> 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<activity_actor> 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
{

Expand Down Expand Up @@ -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 },
Expand Down
35 changes: 35 additions & 0 deletions src/activity_actor_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<tripoint_abs_ms> &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<activity_actor> clone() const override {
return std::make_unique<pulp_activity_actor>( *this );
}

void serialize( JsonOut &jsout ) const override;
static std::unique_ptr<activity_actor> 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<const pulp_activity_actor &>( other );
return actor.pulp_acid == pulp_acid;
}
std::set<tripoint_abs_ms> placement;
int num_corpses;
bool pulp_acid;
};

#endif // CATA_SRC_ACTIVITY_ACTOR_DEFINITIONS_H
122 changes: 0 additions & 122 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand Down Expand Up @@ -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" );
Expand Down Expand Up @@ -260,7 +254,6 @@ const std::map< activity_id, std::function<void( player_activity *, Character *
activity_handlers::do_turn_functions = {
{ ACT_FILL_LIQUID, fill_liquid_do_turn },
{ ACT_PICKAXE, pickaxe_do_turn },
{ ACT_PULP, pulp_do_turn },
{ ACT_GAME, game_do_turn },
{ ACT_GENERIC_GAME, generic_game_do_turn },
{ ACT_START_FIRE, start_fire_do_turn },
Expand Down Expand Up @@ -333,7 +326,6 @@ activity_handlers::finish_functions = {
{ ACT_PLANT_SEED, plant_seed_finish },
{ ACT_VEHICLE, vehicle_finish },
{ ACT_START_ENGINES, start_engines_finish },
{ ACT_PULP, pulp_finish },
{ ACT_REPAIR_ITEM, repair_item_finish },
{ ACT_HEATING, heat_item_finish },
{ ACT_MEND_ITEM, mend_item_finish },
Expand Down Expand Up @@ -1774,120 +1766,6 @@ void activity_handlers::pickaxe_finish( player_activity *act, Character *you )
}
}

void activity_handlers::pulp_do_turn( player_activity *act, Character *you )
{
map &here = get_map();
const tripoint_bub_ms &pos = here.bub_from_abs( act->placement );

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<float>( 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( "<npcname> finished pulping the corpse.",
"<npcname> finished pulping the corpses.", num_corpses ) );
}

void activity_handlers::pulp_finish( player_activity *act, Character *you )
{
if( you->is_npc() ) {
npc *guy = dynamic_cast<npc *>( 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" );
Expand Down
2 changes: 0 additions & 2 deletions src/activity_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down
Loading

0 comments on commit 2a5edfa

Please sign in to comment.