Skip to content

Commit

Permalink
bugfix_line_spell: prevent narrow line spells from being stopped early (
Browse files Browse the repository at this point in the history
#40242)

* bugfix_line_spell: prevent narrow line spells from being stopped early

Line attack spells with narrow AOE (0 or 1) were being prevented from
actually working as intended. The exception added to the condition
prevents exiting early if the spell is a line attack.

* bugfix_line_spell: Split `spell_effect_area` for testability

Splits spell effect area calculation out of `spell_effect_area` to
allow independent testing without calling the drawing function
`explosion_handler::draw_custom_explosion`

* bugfix_line_spell: Generate test to ensure narrow beam spell consistency
  • Loading branch information
OrenAudeles authored May 12, 2020
1 parent c9a7081 commit 4dfa4f0
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "item.h"
#include "line.h"
#include "magic.h"
#include "magic_spell_effect_helpers.h"
#include "magic_teleporter_list.h"
#include "magic_ter_furn_transform.h"
#include "map.h"
Expand Down Expand Up @@ -351,12 +352,12 @@ std::set<tripoint> spell_effect::spell_effect_line( const spell &, const tripoin

// spells do not reduce in damage the further away from the epicenter the targets are
// rather they do their full damage in the entire area of effect
static std::set<tripoint> spell_effect_area( const spell &sp, const tripoint &target,
std::set<tripoint> calculate_spell_effect_area( const spell &sp, const tripoint &target,
std::function<std::set<tripoint>( const spell &, const tripoint &, const tripoint &, int, bool )>
aoe_func, const Creature &caster, bool ignore_walls = false )
aoe_func, const Creature &caster, bool ignore_walls )
{
std::set<tripoint> targets = { target }; // initialize with epicenter
if( sp.aoe() <= 1 ) {
if( sp.aoe() <= 1 && sp.effect() != "line_attack" ) {
return targets;
}

Expand All @@ -371,6 +372,17 @@ static std::set<tripoint> spell_effect_area( const spell &sp, const tripoint &ta
}
}

return targets;
}

static std::set<tripoint> spell_effect_area( const spell &sp, const tripoint &target,
std::function<std::set<tripoint>( const spell &, const tripoint &, const tripoint &, int, bool )>
aoe_func, const Creature &caster, bool ignore_walls = false )
{
// calculate spell's effect area
std::set<tripoint> targets = calculate_spell_effect_area( sp, target, aoe_func, caster,
ignore_walls );

// Draw the explosion
std::map<tripoint, nc_color> explosion_colors;
for( auto &pt : targets ) {
Expand Down
18 changes: 18 additions & 0 deletions src/magic_spell_effect_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#ifndef CATA_SRC_MAGIC_SPELL_EFFECT_HELPERS_H
#define CATA_SRC_MAGIC_SPELL_EFFECT_HELPERS_H

#include <functional>
#include <set>

class Creature;
class spell;
struct tripoint;

// spells do not reduce in damage the further away from the epicenter the targets are
// rather they do their full damage in the entire area of effect
std::set<tripoint> calculate_spell_effect_area( const spell &sp, const tripoint &target,
std::function<std::set<tripoint>( const spell &, const tripoint &, const tripoint &, int, bool )>
aoe_func, const Creature &caster, bool ignore_walls = false );

#endif // CATA_SRC_MAGIC_SPELL_EFFECT_HELPERS_H
49 changes: 49 additions & 0 deletions tests/magic_spell_effect_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <sstream>

#include "catch/catch.hpp"
#include "json.h"
#include "magic.h"
#include "magic_spell_effect_helpers.h"
#include "npc.h"

TEST_CASE( "line_attack", "[magic]" )
{
// manually construct a testable spell
std::istringstream str(
" {\n"
" \"id\": \"test_line_spell\",\n"
" \"name\": { \"str\": \"Test Line Spell\" },\n"
" \"description\": \"Spews a line of magic\",\n"
" \"valid_targets\": [ \"ground\" ],\n"
" \"damage_type\": \"none\",\n"
" \"min_range\": 5,\n"
" \"max_range\": 5,\n"
" \"effect\": \"line_attack\",\n"
" \"min_aoe\": 0,\n"
" \"max_aoe\": 0,\n"
" \"flags\": [ \"VERBAL\", \"NO_HANDS\", \"NO_LEGS\" ]\n"
" }\n" );

JsonIn in( str );
JsonObject obj( in );
spell_type::load_spell( obj, "" );

spell sp( spell_id( "test_line_spell" ) );

// set up Character to test with, only need position
npc c;
c.setpos( tripoint_zero );

// target point 5 tiles east of zero
tripoint target = tripoint_east * 5;

// Ensure that AOE=0 spell covers the 5 tiles along vector towards target
SECTION( "aoe=0" ) {
const std::set<tripoint> reference( { tripoint_east * 1, tripoint_east * 2, tripoint_east * 3, tripoint_east * 4, tripoint_east * 5 } );

std::set<tripoint> targets = calculate_spell_effect_area( sp, target,
spell_effect::spell_effect_line, c, true );

CHECK( reference == targets );
}
}

0 comments on commit 4dfa4f0

Please sign in to comment.