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

feat(content, port): Port Directed push from DDA #5566

Merged
merged 4 commits into from
Oct 14, 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
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 @@ -209,6 +209,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 @@ -157,7 +157,7 @@
num_limbs++;
total_hp += elem.second.get_hp_cur();
}
const int hp_each = total_hp / num_limbs;

Check warning on line 160 in src/magic_spell_effect.cpp

View workflow job for this annotation

GitHub Actions / build

Division by zero [clang-analyzer-core.DivideZero]
p->set_all_parts_hp_cur( hp_each );
}

Expand Down Expand Up @@ -658,6 +658,33 @@
} );
}

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 @@
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 @@
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 Expand Up @@ -1028,7 +1154,7 @@
for( const tripoint &potential_target : area ) {
player *player_target;
if( !( sp.is_valid_target( caster, potential_target ) &&
( player_target = g->critter_at<player>( potential_target ) ) ) ) {

Check warning on line 1157 in src/magic_spell_effect.cpp

View workflow job for this annotation

GitHub Actions / build

an assignment within an 'if' condition is bug-prone [bugprone-assignment-in-if-condition]
continue;
}
player_target->add_morale( morale_type( sp.effect_data() ), sp.damage(), 0, sp.duration_turns(),
Expand Down
Loading