Skip to content
Draft
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
8 changes: 8 additions & 0 deletions data/json/player_activities.json
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,14 @@
"verb": "mining",
"based_on": "speed"
},
{
"id": "ACT_ASSISTED_PULP",
"type": "activity_type",
"activity_level": "NO_EXERCISE",
"verb": "pulping",
"based_on": "speed",
"can_resume": false
},
{
"id": "ACT_PULP",
"type": "activity_type",
Expand Down
106 changes: 106 additions & 0 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "activity_actor.h"

Check failure on line 1 in src/activity_actor.cpp

View workflow job for this annotation

GitHub Actions / iwyu

add '#include "magic.h"' (for spell, spell_effect::spell_effect_area)

#include <algorithm>
#include <array>
Expand Down Expand Up @@ -109,6 +109,7 @@
#include "vpart_range.h"

static const activity_id ACT_AIM( "ACT_AIM" );
static const activity_id ACT_ASSISTED_PULP( "ASSISTED_PULP" );
static const activity_id ACT_AUTODRIVE( "ACT_AUTODRIVE" );
static const activity_id ACT_BASH( "ACT_BASH" );
static const activity_id ACT_BIKERACK_RACKING( "ACT_BIKERACK_RACKING" );
Expand Down Expand Up @@ -8691,6 +8692,111 @@
return actor.clone();
}

namespace io
{
template<>
std::string enum_to_string<assisted_pulp_type>( assisted_pulp_type type )
{
switch( type ) {
case assisted_pulp_type::SPELL: return "SPELL";
default:
cata_fatal( "Invalid based_on_type in enum_to_string" );
}
}
} // namespace io

bool assisted_pulp_activity_actor::calculate_corpses_in_area( Character &you )
{
map &here = get_map();
corpses = {};
if( assist_type == assisted_pulp_type::SPELL ) {
const std::set<tripoint_bub_ms> area = spell_effect::spell_effect_area( (*sp), target, you );

for( const tripoint_bub_ms &potential_target : area ) {
if( !(*sp).is_valid_target( you, potential_target ) ) {
continue;
}
for( item &potential_corpse : here.i_at( potential_target ) ) {
if( potential_corpse.can_revive() ) {
corpses.insert( potential_corpse );
}
}
}
}
return !corpses.empty();
}

void assisted_pulp_activity_actor::start( player_activity &act, Character &you )
{
// indefinitely long so activity won't end until we pulp all the corpses
// we then end the activity manually
act.moves_total = calendar::INDEFINITELY_LONG;
act.moves_left = calendar::INDEFINITELY_LONG;

if( assist_type == assisted_pulp_type::SPELL) {
if( !calculate_corpses_in_area( you ) ) { // Immediately stop activity if no corpses to pulp
act.set_to_null();
return;
}
} else {
debugmsg("%s tried assisted pulping without a valid assisted pulp type!", you.name );
act.set_to_null();
return;
}
}

void assisted_pulp_activity_actor::do_turn( player_activity &act, Character &you )
{

if( assist_type == assisted_pulp_type::SPELL ) {
you.cast_spell( (*sp), false, target );
}
add_msg("assisted_pulp_activity_actor: spell=%s", (*sp).id().c_str() );

// If nothing to pulp, stop the activity.
// if( !calculate_corpses_in_area( you ) ) {
if( true ) {
act.moves_total = 0;
act.moves_left = 0;
}
}

void assisted_pulp_activity_actor::finish( player_activity &act, Character &you )

Check failure on line 8764 in src/activity_actor.cpp

View workflow job for this annotation

GitHub Actions / iwyu

unused parameter 'you' [-Werror,-Wunused-parameter]
{
act.moves_total = 0;
act.moves_left = 0;

act.set_to_null();
}

void assisted_pulp_activity_actor::serialize( JsonOut &jsout ) const
{
jsout.start_object();

jsout.member( "target", target );
jsout.member( "assist_type", assist_type );
// jsout.member( "corpses", corpses );
// jsout.member( "num_corpses", num_corpses );
// jsout.member( "sp", sp );

jsout.end_object();
}

std::unique_ptr<activity_actor> assisted_pulp_activity_actor::deserialize( JsonValue &jsin )
{
assisted_pulp_activity_actor actor;

JsonObject data = jsin.get_object();

data.read( "target", actor.target );
data.read( "assist_type", actor.assist_type );
// data.read( "corpses", actor.corpses );
// data.read( "num_corpses", actor.num_corpses );
// data.read( "sp", actor.sp );

return actor.clone();
}

void pulp_activity_actor::start( player_activity &act, Character &you )
{
// indefinitely long so activity won't end until we pulp all the corpses
Expand Down
47 changes: 47 additions & 0 deletions src/activity_actor_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2450,6 +2450,53 @@
tripoint_abs_ms placement;
};

enum class assisted_pulp_type : int { SPELL };
template<>
struct enum_traits<assisted_pulp_type> {
static constexpr assisted_pulp_type last = assisted_pulp_type::SPELL;
};

namespace io
{
template<>
std::string enum_to_string<assisted_pulp_type>( assisted_pulp_type type );
} // namespace io

class assisted_pulp_activity_actor : public activity_actor
{
public:

assisted_pulp_activity_actor() {};
assisted_pulp_activity_actor( const tripoint_bub_ms &target, spell *sp ) : assist_type( assisted_pulp_type::SPELL ), target( target ), sp( sp ) {}

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]

Check failure on line 2470 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / Basic Build and Test (Clang oldest supported, Ubuntu, Curses)

field 'assist_type' will be initialized after field 'target' [-Werror,-Wreorder-ctor]
const activity_id &get_type() const override {
static const activity_id ACT_ASSISTED_PULP( "ACT_ASSISTED_PULP" );
return ACT_ASSISTED_PULP;
}

void start( player_activity &act, Character &you ) 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<assisted_pulp_activity_actor>( *this );
}

void serialize( JsonOut &jsout ) const override;
static std::unique_ptr<activity_actor> deserialize( JsonValue &jsin );

private:
// recalculates the corpses set. Returns if there are any pulpable corpses left.
bool calculate_corpses_in_area( Character &you );

tripoint_bub_ms target;
assisted_pulp_type assist_type;
std::set<item> corpses;
int num_corpses = 0;

Check failure on line 2494 in src/activity_actor_definitions.h

View workflow job for this annotation

GitHub Actions / iwyu

private field 'num_corpses' is not used [-Werror,-Wunused-private-field]

// spell pulping
spell *sp;
};

class pulp_activity_actor : public activity_actor
{
public:
Expand Down
2 changes: 2 additions & 0 deletions src/magic.h
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,8 @@ struct override_parameters {
ignore_walls = sp.has_flag( spell_flag::IGNORE_WALLS );
}
};
std::set<tripoint_bub_ms> spell_effect_area( const spell &sp, const tripoint_bub_ms &target,
const Creature &caster );

void short_range_teleport( const spell &sp, Creature &caster, const tripoint_bub_ms &target );
void pain_split( const spell &, Creature &, const tripoint_bub_ms & );
Expand Down
82 changes: 63 additions & 19 deletions src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <utility>
#include <vector>

#include "activity_actor_definitions.h"
#include "avatar.h"
#include "bodypart.h"
#include "calendar.h"
Expand Down Expand Up @@ -473,7 +474,7 @@ std::set<tripoint_bub_ms> calculate_spell_effect_area( const spell &sp,
return targets;
}

static std::set<tripoint_bub_ms> spell_effect_area( const spell &sp, const tripoint_bub_ms &target,
std::set<tripoint_bub_ms> spell_effect::spell_effect_area( const spell &sp, const tripoint_bub_ms &target,
const Creature &caster )
{
// calculate spell's effect area
Expand Down Expand Up @@ -660,6 +661,65 @@ static void damage_targets( const spell &sp, Creature &caster,
}
}

// Attempts to pulp a corpse with a spell. Returns if, after processing, the corpse is still pulpable.
static bool pulp_corpse( item &corpse, int spell_bash_damage, tripoint_bub_ms pos, map &here )
{
if( spell_bash_damage <= 0 || !corpse.can_revive() ) {
return false;
}

const mtype *corpse_mtype = corpse.get_mtype();
if( corpse_mtype == nullptr ) {
debugmsg( string_format( "Tried to pulp not-a-corpse (id %s)", corpse.typeId().c_str() ) );
return false;
}
int m_health = corpse_mtype->hp;
float proportion_to_damage = static_cast<float>( spell_bash_damage ) / static_cast<float>( m_health );
// Item max HP is 4000. Not sure of a good non-magic number source for this.
int corpse_damage = proportion_to_damage * 4000;
add_msg("pulp_corpse: spell_damage=%d, corpse_damage=%d", spell_bash_damage, corpse_damage);
corpse.mod_damage( corpse_damage );

const int radius = 1 + std::min(2.0f, proportion_to_damage / 2);
const field_type_id type_blood = proportion_to_damage > 1 ?
corpse.get_mtype()->gibType() :
corpse.get_mtype()->bloodType();
here.add_splash( type_blood, pos, radius, 2 );


return corpse.can_revive();
}

static void spell_bash_area( const spell &sp, Creature &caster, const std::set<tripoint_bub_ms> area, const tripoint_bub_ms &epicenter, double damage_modifier = 1.0 )
{
::map &here = get_map();
for( const tripoint_bub_ms &potential_target : area ) {
if( !sp.is_valid_target( caster, potential_target ) ) {
continue;
}
int spell_bash_damage = sp.damage( caster ) * damage_modifier;
// the bash already makes noise, so no need for spell::make_sound()
here.bash( potential_target, spell_bash_damage,
sp.has_flag( spell_flag::SILENT ) );

bool unpulped_corpses_remaining = false;
for( item &potential_corpse : here.i_at( potential_target ) ) {
if( potential_corpse.can_revive() && pulp_corpse( potential_corpse, spell_bash_damage, potential_target, here )) {
add_msg("spell_bash_area: unpulped_corpses_remaining = true");
unpulped_corpses_remaining = true;
}
}
// Add query here before starting activity
avatar *av = caster.as_avatar();
if( av != nullptr && unpulped_corpses_remaining ) {
add_msg("spell_bash_area: starting activity");
spell non_const_spell = av->magic->get_spell( sp.id() );
add_msg("spell=%s", non_const_spell.id().c_str() );
av->assign_activity( assisted_pulp_activity_actor( epicenter, &non_const_spell ) );
}
}
}

void spell_effect::attack( const spell &sp, Creature &caster, const tripoint_bub_ms &epicenter )
{
const std::set<tripoint_bub_ms> area = spell_effect_area( sp, epicenter, caster );
Expand All @@ -669,15 +729,7 @@ void spell_effect::attack( const spell &sp, Creature &caster, const tripoint_bub
}
const double bash_scaling = sp.bash_scaling( caster );
if( bash_scaling > 0 ) {
::map &here = get_map();
for( const tripoint_bub_ms &potential_target : area ) {
if( !sp.is_valid_target( caster, potential_target ) ) {
continue;
}
// the bash already makes noise, so no need for spell::make_sound()
here.bash( potential_target, sp.damage( caster ) * bash_scaling,
sp.has_flag( spell_flag::SILENT ) );
}
spell_bash_area( sp, caster, area, epicenter, bash_scaling );
}
}

Expand Down Expand Up @@ -1762,15 +1814,7 @@ void spell_effect::mutate( const spell &sp, Creature &caster, const tripoint_bub

void spell_effect::bash( const spell &sp, Creature &caster, const tripoint_bub_ms &target )
{
::map &here = get_map();
const std::set<tripoint_bub_ms> area = spell_effect_area( sp, target, caster );
for( const tripoint_bub_ms &potential_target : area ) {
if( !sp.is_valid_target( caster, potential_target ) ) {
continue;
}
// the bash already makes noise, so no need for spell::make_sound()
here.bash( potential_target, sp.damage( caster ), sp.has_flag( spell_flag::SILENT ) );
}
spell_bash_area( sp, caster, spell_effect_area( sp, target, caster ), target, 1.0 );
}

void spell_effect::dash( const spell &sp, Creature &caster, const tripoint_bub_ms &target )
Expand Down
Loading