Skip to content

Commit

Permalink
[Magiclysm] Attunements - Rock Blast spell (#44682)
Browse files Browse the repository at this point in the history
  • Loading branch information
KorGgenT authored Oct 8, 2020
1 parent 779d552 commit 9b2fd9b
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 21 deletions.
51 changes: 51 additions & 0 deletions data/mods/Magiclysm/Spells/attunements/Earth_Elemental.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,56 @@
"max_aoe": 35,
"aoe_increment": 1,
"max_level": 35
},
{
"id": "rock_blast",
"type": "SPELL",
"description": "Fire three large rocks at an enemy, causing blunt damage and knocking it back.",
"valid_targets": [ "hostile" ],
"flags": [ "SOMATIC", "NO_LEGS" ],
"effect": "attack",
"shape": "blast",
"max_level": 35,
"min_damage": 20,
"max_damage": 180,
"damage_increment": 4.6,
"min_range": 8,
"max_range": 15,
"range_increment": 0.2,
"sound_id": "earth_spell",
"sound_variant": "strong",
"energy_source": "STAMINA",
"spell_class": "EARTH_ELEMENTAL",
"damage_type": "bash",
"base_energy_cost": 5000,
"base_casting_time": 200,
"extra_effects": [ { "id": "single_rock_blast" }, { "id": "single_rock_blast" }, { "id": "rock_blast_push" } ]
},
{
"id": "single_rock_blast",
"type": "SPELL",
"description": "A single portion of the rock blast spell",
"valid_targets": [ "hostile" ],
"effect": "attack",
"shape": "blast",
"max_level": 35,
"min_damage": 20,
"max_damage": 180,
"damage_increment": 4.6,
"damage_type": "bash",
"sound_id": "earth_spell",
"sound_variant": "strong"
},
{
"id": "rock_blast_push",
"type": "SPELL",
"description": "The push portion of the rock blast spell",
"valid_targets": [ "hostile" ],
"effect": "directed_push",
"shape": "blast",
"max_level": 35,
"min_damage": 1,
"max_damage": 3,
"damage_increment": 0.1
}
]
32 changes: 32 additions & 0 deletions data/mods/Magiclysm/Spells/debug.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,38 @@
"//7": "Learn spells by adding map of 'spell_id': 'level' ",
"learn_spells": { "create_atomic_light": 1, "megablast": 2 }
},
{
"type": "SPELL",
"id": "debug_push_basic",
"name": "debug push no aoe",
"description": "pushes all types of objects with an aoe of 0",
"valid_targets": [ "ally", "self", "hostile", "field", "item", "ground" ],
"effect": "directed_push",
"shape": "blast",
"min_damage": 0,
"max_damage": 10,
"damage_increment": 1,
"min_range": 20,
"max_range": 20,
"max_level": 10
},
{
"type": "SPELL",
"id": "debug_push_blast",
"name": "debug push blast",
"description": "pushes all types of objects with an aoe of 3 in a blast pattern",
"valid_targets": [ "ally", "self", "hostile", "field", "item", "ground" ],
"effect": "directed_push",
"shape": "blast",
"min_aoe": 3,
"max_aoe": 3,
"min_damage": 0,
"max_damage": 10,
"damage_increment": 1,
"min_range": 20,
"max_range": 20,
"max_level": 10
},
{
"id": "spawn_debug_monster",
"type": "SPELL",
Expand Down
2 changes: 1 addition & 1 deletion data/mods/Magiclysm/traits/attunements.json
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@
"valid": false,
"description": "Stone is superior to flesh. You have allowed this axiom into your life, and work to correct your own weakness with biomancy. The strength of the Earth rushed up to meet you with open arms.",
"prereqs": [ "BIOMANCER", "EARTHSHAPER" ],
"spells_learned": [ [ "quake", 5 ] ],
"spells_learned": [ [ "quake", 5 ], [ "rock_blast", 5 ] ],
"armor": [
{ "parts": [ "torso", "arm_l", "arm_r", "hand_l", "hand_r", "leg_l", "leg_r", "foot_l", "foot_r", "head" ], "cut": 15 }
],
Expand Down
1 change: 1 addition & 0 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ void spell_type::load( const JsonObject &jo, const std::string & )
{ "translocate", spell_effect::translocate },
{ "area_pull", spell_effect::area_pull },
{ "area_push", spell_effect::area_push },
{ "directed_push", spell_effect::directed_push },
{ "timed_event", spell_effect::timed_event },
{ "ter_transform", spell_effect::transform_blast },
{ "noise", spell_effect::noise },
Expand Down
1 change: 1 addition & 0 deletions src/magic.h
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ void targeted_polymorph( const spell &sp, Creature &caster, const tripoint &targ

void area_pull( const spell &sp, Creature &caster, const tripoint &center );
void area_push( const spell &sp, Creature &caster, const tripoint &center );
void directed_push( const spell &sp, Creature &caster, const tripoint &target );

std::set<tripoint> spell_effect_blast( const override_parameters &params, const tripoint &,
const tripoint &target );
Expand Down
154 changes: 134 additions & 20 deletions src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "monster.h"
#include "monstergenerator.h"
#include "mtype.h"
#include "npc.h"
#include "optional.h"
#include "overmapbuffer.h"
#include "pimpl.h"
Expand Down Expand Up @@ -654,6 +655,30 @@ void area_expander::sort_descending()
} );
}

static void move_items( map &here, const tripoint &from, const tripoint &to )
{
for( const item &it : here.i_at( from ) ) {
here.add_item( to, it );
}
here.i_clear( from );
}

static void move_field( map &here, const tripoint &from, const tripoint &to )
{
field &src_field = here.field_at( from );
std::map<field_type_id, int> moving_fields;
for( const std::pair<const field_type_id, field_entry> &fd : src_field ) {
if( fd.first.is_valid() && !fd.first.id().is_null() ) {
const int intensity = fd.second.get_field_intensity();
moving_fields.emplace( fd.first, intensity );
}
}
for( const std::pair<const field_type_id, int> &fd : moving_fields ) {
here.remove_field( from, fd.first );
here.set_field_intensity( to, fd.first, fd.second );
}
}

// Moving all objects from one point to another by the power of magic.
static void spell_move( const spell &sp, const Creature &caster,
const tripoint &from, const tripoint &to )
Expand Down Expand Up @@ -686,30 +711,12 @@ static void spell_move( const spell &sp, const Creature &caster,

// Moving items
if( sp.is_valid_target( spell_target::item ) ) {
map &here = get_map();
map_stack src_items = here.i_at( from );
map_stack dst_items = here.i_at( to );
for( const item &item : src_items ) {
dst_items.insert( item );
}
src_items.clear();
move_items( get_map(), from, to );
}

// Moving fields.
if( sp.is_valid_target( spell_target::field ) ) {
map &here = get_map();
field &src_field = here.field_at( from );
std::map<field_type_id, int> moving_fields;
for( const std::pair<const field_type_id, field_entry> &fd : src_field ) {
if( fd.first.is_valid() && !fd.first.id().is_null() ) {
const int intensity = fd.second.get_field_intensity();
moving_fields.emplace( fd.first, intensity );
}
}
for( const std::pair<const field_type_id, int> &fd : moving_fields ) {
here.remove_field( from, fd.first );
here.set_field_intensity( to, fd.first, fd.second );
}
move_field( get_map(), from, to );
}
}

Expand Down Expand Up @@ -749,6 +756,113 @@ void spell_effect::area_push( const spell &sp, Creature &caster, const tripoint
sp.make_sound( caster.pos() );
}

static void character_push_effects( Creature *caster, Character &guy, tripoint &push_dest,
const int push_distance, const std::vector<tripoint> &push_vec )
{
int dist_left = std::abs( push_distance );
for( const tripoint &pushed_point : push_vec ) {
if( get_map().impassable( pushed_point ) ) {
guy.hurtall( dist_left * 4, caster );
push_dest = pushed_point;
break;
} else {
dist_left--;
}
}
guy.setpos( push_dest );
}

void spell_effect::directed_push( const spell &sp, Creature &caster, const tripoint &target )
{
std::set<tripoint> area = spell_effect_area( sp, target, caster );
// this group of variables is for deferring movement of the avatar
int pushed_distance;
tripoint push_to;
std::vector<tripoint> pushed_vec;
bool player_pushed = false;

::map &here = get_map();

// whether it's push or pull, so how the multimap is sorted
// -1 is push and 1 is pull
const int sign = sp.damage() > 0 ? -1 : 1;

std::multimap<int, tripoint> targets_ordered_by_range;
for( const tripoint &pt : area ) {
targets_ordered_by_range.emplace( sign * rl_dist( pt, caster.pos() ), pt );
}

for( const std::pair<int, tripoint> &pair : targets_ordered_by_range ) {
const tripoint &push_point = pair.second;
const int angle = coord_to_angle( caster.pos(), target );
// positive is push, negative is pull
int push_distance = sp.damage();
const int prev_distance = rl_dist( caster.pos(), target );
if( push_distance < 0 ) {
push_distance = std::max( -std::abs( push_distance ), -std::abs( prev_distance ) );
}
if( push_distance == 0 ) {
continue;
}

tripoint push_dest;
calc_ray_end( angle, push_distance, push_point, push_dest );
const std::vector<tripoint> push_vec = line_to( push_point, push_dest );

const Creature *critter = g->critter_at<Creature>( push_point );
if( critter != nullptr ) {
const Creature::Attitude attitude_to_target =
caster.attitude_to( *g->critter_at<Creature>( push_point ) );

monster *mon = g->critter_at<monster>( push_point );
npc *guy = g->critter_at<npc>( push_point );

if( ( sp.is_valid_target( spell_target::self ) && push_point == caster.pos() ) ||
( attitude_to_target == Creature::Attitude::FRIENDLY &&
sp.is_valid_target( spell_target::ally ) ) ||
( ( attitude_to_target == Creature::Attitude::HOSTILE ||
attitude_to_target == Creature::Attitude::NEUTRAL ) &&
sp.is_valid_target( spell_target::hostile ) ) ) {
if( g->critter_at<avatar>( push_point ) ) {
// defer this because this absolutely must be done last in order not to mess up our calculations
player_pushed = true;
pushed_distance = push_distance;
push_to = push_dest;
pushed_vec = push_vec;
} else if( mon ) {
int dist_left = std::abs( push_distance );
for( const tripoint &pushed_push_point : push_vec ) {
if( get_map().impassable( pushed_push_point ) ) {
mon->apply_damage( &caster, bodypart_id(), dist_left * 10 );
push_dest = pushed_push_point;
break;
} else {
dist_left--;
}
}
mon->setpos( push_dest );
} else if( guy ) {
character_push_effects( &caster, *guy, push_dest, push_distance, push_vec );
}
}
}

if( sp.is_valid_target( spell_target::item ) && here.has_items( push_point ) ) {
move_items( here, push_point, push_dest );
}


if( sp.is_valid_target( spell_target::field ) ) {
move_field( here, push_point, push_dest );
}
}

// deferred avatar pushing
if( player_pushed ) {
character_push_effects( &caster, get_avatar(), push_to, pushed_distance, pushed_vec );
}
}

void spell_effect::spawn_ethereal_item( const spell &sp, Creature &caster, const tripoint & )
{
item granted( sp.effect_data(), calendar::turn );
Expand Down

0 comments on commit 9b2fd9b

Please sign in to comment.