Skip to content

Commit

Permalink
feat(content, port): Port Directed push from DDA (#5566)
Browse files Browse the repository at this point in the history
* Port Directed push from DDA

When the push is directed

Co-Authored-By: Curtis Merrill <30208401+KorGgenT@users.noreply.github.com>

* style(autofix.ci): automated formatting

* Documentation, fix debug dash real quick

Oops!

---------

Co-authored-by: Curtis Merrill <30208401+KorGgenT@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 14, 2024
1 parent 9988909 commit d0d1c96
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 16 deletions.
36 changes: 36 additions & 0 deletions data/mods/Magiclysm/Spells/debug.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,5 +247,41 @@
"base_energy_cost": 350,
"max_level": 1,
"energy_source": "MANA"
},
{
"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", "ground", "item" ],
"effect": "directed_push",
"min_damage": 0,
"max_damage": 10,
"damage_increment": 1,
"min_range": 20,
"max_range": 20,
"max_level": 10,
"base_casting_time": 100,
"energy_source": "MANA",
"base_energy_cost": 100
},
{
"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", "ground", "item" ],
"effect": "directed_push",
"min_aoe": 3,
"max_aoe": 3,
"min_damage": 0,
"max_damage": 10,
"damage_increment": 1,
"min_range": 20,
"max_range": 20,
"max_level": 10,
"base_casting_time": 100,
"energy_source": "MANA",
"base_energy_cost": 100
}
]
4 changes: 4 additions & 0 deletions doc/src/content/docs/en/mod/json/reference/creatures/magic.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ experience you need to get to a level is below:

- `dash` - moves the player to the target tile, can leave behind fields.

- `area_push` - pushes things outwards from a single point

- `directed_push` pushes things in a single direction away from you.

- `WONDER` - Unlike the above, this is not an "effect" but a "flag". This alters the behavior of the
parent spell drastically: The spell itself doesn't cast, but its damage and range information is
used in order to cast the extra_effects. N of the extra_effects will be chosen at random to be
Expand Down
1 change: 1 addition & 0 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,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 @@ -534,6 +534,7 @@ void line_attack( const spell &sp, Creature &caster,

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 spell &, const tripoint &, const tripoint &target,
int aoe_radius, bool ignore_walls );
Expand Down
158 changes: 142 additions & 16 deletions src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,33 @@ void area_expander::sort_descending()
} );
}

static void move_items( map &here, const tripoint &from, const tripoint &to )
{
auto src_items = here.i_at( from );
auto dst_items = here.i_at( to );

for( detached_ptr<item> &it : src_items.clear() ) {
dst_items.insert( std::move( it ) );
}
src_items.clear();
}

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 @@ -695,22 +722,8 @@ static void spell_move( const spell &sp, const Creature &caster,
src_items.clear();
}

// Helper function to move particular field type if corresponding target flag is enabled.
auto move_field = [&sp, &here, from, to]( valid_target target, field_type_id fid ) {
if( !sp.is_valid_effect_target( target ) ) {
return;
}
auto &src_field = here.field_at( from );
if( field_entry *entry = src_field.find_field( fid ) ) {
int intensity = entry->get_field_intensity();
here.remove_field( from, fid );
here.set_field_intensity( to, fid, intensity );
}
};
// Moving fields.
move_field( target_fd_fire, fd_fire );
move_field( target_fd_blood, fd_blood );
move_field( target_fd_blood, fd_gibs_flesh );
// Helper function to move fields
move_field( get_map(), from, to );
}

void spell_effect::area_pull( const spell &sp, Creature &caster, const tripoint &center )
Expand Down Expand Up @@ -749,6 +762,119 @@ 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, spell_effect_blast, 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 ) {

Check warning on line 801 in src/magic_spell_effect.cpp

View workflow job for this annotation

GitHub Actions / GCC 12, Ubuntu, Curses

loop variable ‘pair’ of type ‘const std::pair<int, tripoint>&’ binds to a temporary constructed from type ‘std::pair<const int, tripoint>’ [-Wrange-loop-construct]

Check warning on line 801 in src/magic_spell_effect.cpp

View workflow job for this annotation

GitHub Actions / GCC 12, Ubuntu, Tiles, Sound, Lua, CMake, Languages

loop variable ‘pair’ of type ‘const std::pair<int, tripoint>&’ binds to a temporary constructed from type ‘std::pair<const int, tripoint>’ [-Wrange-loop-construct]

Check warning on line 801 in src/magic_spell_effect.cpp

View workflow job for this annotation

GitHub Actions / GCC 12, Ubuntu, Tiles, Sound, Lua

loop variable ‘pair’ of type ‘const std::pair<int, tripoint>&’ binds to a temporary constructed from type ‘std::pair<const int, tripoint>’ [-Wrange-loop-construct]
const tripoint &push_point = pair.second;
const units::angle start_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( start_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 Attitude attitude_to_target =
caster.attitude_to( *g->critter_at<Creature>( push_point ) );

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

if( ( sp.is_valid_target( target_self ) && push_point == caster.pos() ) ||
( attitude_to_target == Attitude::A_FRIENDLY &&
sp.is_valid_target( target_ally ) ) ||
( ( attitude_to_target == Attitude::A_HOSTILE ||
attitude_to_target == Attitude::A_NEUTRAL ) &&
sp.is_valid_target( 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( target_item ) && here.has_items( push_point ) ) {
move_items( here, push_point, push_dest );
}


if( sp.is_valid_target( target_fd_blood ) ) {
move_field( here, push_point, push_dest );
}

if( sp.is_valid_target( target_fd_fire ) ) {
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 & )
{
detached_ptr<item> granted = item::spawn( sp.effect_data(), calendar::turn );
Expand Down

0 comments on commit d0d1c96

Please sign in to comment.