Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate ACT_PULP to the new activity actor system #76163

Merged
merged 2 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,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 @@ -181,6 +182,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 @@ -7915,6 +7921,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 @@ -7967,6 +8121,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 @@ -2184,4 +2184,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 @@ -225,7 +225,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 @@ -257,7 +256,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
Loading