Skip to content
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
7 changes: 4 additions & 3 deletions engine/action/action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@ action_t::action_t( action_e ty, util::string_view token, player_t* p, const spe
internal_id( p->get_action_id( name_str ) ),
resource_current( RESOURCE_NONE ),
aoe(),
secondary_targets_only(),
dual(),
callbacks( true ),
caster_callbacks( true ),
Expand Down Expand Up @@ -1703,12 +1702,14 @@ int action_t::num_targets() const
size_t action_t::available_targets( std::vector<player_t*>& tl ) const
{
tl.clear();
if ( !secondary_targets_only && !target->is_sleeping() && target->is_enemy() )

const auto& cb = target_filter_callback;
if ( !target->is_sleeping() && target->is_enemy() && ( !cb || cb( this, target ) ) )
tl.push_back( target );

for ( auto* t : sim->target_non_sleeping_list )
{
if ( t->is_enemy() && ( t != target ) )
if ( t->is_enemy() && ( t != target ) && ( !cb || cb( this, t ) ) )
{
tl.push_back( t );
}
Expand Down
10 changes: 8 additions & 2 deletions engine/action/action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <string>
#include <vector>

struct action_t;
struct action_priority_t;
struct action_priority_list_t;
struct action_state_t;
Expand Down Expand Up @@ -51,6 +52,8 @@ namespace report {
template <typename T>
struct parsed_value_t;

using target_filter_callback_t = std::function<bool( const action_t*, player_t* )>;

// Action ===================================================================

struct action_t : private noncopyable
Expand Down Expand Up @@ -104,8 +107,8 @@ struct action_t : private noncopyable
/// The amount of targets that an ability impacts on. -1 will hit all targets.
int aoe;

/// Whether the action hits all targets or only the secondary ones.
bool secondary_targets_only;
/// Which targets to include in the list of available targets.
target_filter_callback_t target_filter_callback;

/// If set to true, this action will not be counted toward total amount of executes in reporting. Useful for abilities with parent/children attacks.
bool dual;
Expand Down Expand Up @@ -1143,6 +1146,9 @@ struct action_t : private noncopyable
static bool has_direct_damage_effect( const spell_data_t& );
static bool has_periodic_damage_effect( const spell_data_t& );

static target_filter_callback_t secondary_targets_only()
{ return [] ( const action_t* a, player_t* t ) { return t != a->target; }; }

friend void sc_format_to( const action_t&, fmt::format_context::iterator );
};

Expand Down
40 changes: 10 additions & 30 deletions engine/class_modules/paladin/sc_paladin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1829,20 +1829,13 @@ struct hammer_of_light_t : public holy_power_consumer_t<paladin_melee_attack_t>
affected_by.divine_purpose = false; // We handle this manually
base_execute_time = timespan_t::from_millis( 600 ); // Still has a 600ms execute time, for whatever reasons. Not in spell data anymore.
dual = true;
}

size_t available_targets( std::vector<player_t*>& tl ) const override
{
holy_power_consumer_t::available_targets( tl );
target_filter_callback = secondary_targets_only();

// Does not hit the main target
auto it = range::find( tl, target );
if ( it != tl.end() )
{
tl.erase( it );
}

return tl.size();
if ( p->sets->has_set_bonus( HERO_TEMPLAR, TWW3, B4 ) )
// Both effect 2 and 4 adjust AoE. This is probably a tuning knob for Blizzard. Also maybe Ret is 2, Prot 4, who knows.
aoe += as<int>( p->sets->set( HERO_TEMPLAR, TWW3, B4 )
->effectN( p->specialization() == PALADIN_RETRIBUTION ? 4 : 2 )
.base_value() );
}

action_state_t* new_state() override
Expand Down Expand Up @@ -2029,30 +2022,17 @@ struct empyrean_hammer_wd_t : public paladin_spell_t
empyrean_hammer_wd_t( paladin_t* p )
: paladin_spell_t( "empyrean_hammer_wrathful_descent", p, p->spells.templar.empyrean_hammer_wd )
{
background = true;
may_crit = false;
aoe = -1;
background = true;
may_crit = false;
aoe = -1;
target_filter_callback = secondary_targets_only();

// ToDo (Fluttershy)
// This spell currently deals full damage to all targets, even above 20.
// SimC automatically reduces AoE damage above 20 targets, so may need custom execute, if this behaviour stays
reduced_aoe_targets = -1;
}

size_t available_targets( std::vector<player_t*>& tl ) const override
{
paladin_spell_t::available_targets( tl );

// Does not hit the main target
auto it = range::find( tl, target );
if ( it != tl.end() )
{
tl.erase( it );
}

return tl.size();
}

void impact(action_state_t* s) override
{
paladin_spell_t::impact( s );
Expand Down
27 changes: 23 additions & 4 deletions engine/class_modules/sc_mage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ struct mage_t final : public player_t
bool fof_requires_freezing = true;
bool il_requires_freezing = true;
bool il_sort_by_freezing = false;
bool randomize_si_target = false;
} options;

// Pets
Expand Down Expand Up @@ -1799,6 +1800,19 @@ struct mage_spell_t : public spell_t
return c;
}

size_t available_targets( std::vector<player_t*>& tl ) const override
{
spell_t::available_targets( tl );

if ( tl.size() > 2 && p()->options.randomize_si_target
&& data().affected_by( p()->talents.splitting_ice->effectN( 1 ) ) )
{
std::swap( tl[ 1 ], tl[ rng().range<size_t>( 1, tl.size() ) ] );
}

return tl.size();
}

void execute() override
{
spell_t::execute();
Expand Down Expand Up @@ -4622,7 +4636,8 @@ struct splintering_ray_t final : public spell_t
spell_t( n, p, p->find_spell( 418735 ) ),
freezing_source( p->get_proc( "Freezing applied (Splintering Ray)" ) )
{
background = proc = secondary_targets_only = true;
background = proc = true;
target_filter_callback = secondary_targets_only();
base_dd_min = base_dd_max = 1.0;
// TODO: Seems to hit 1 fewer target
aoe--;
Expand Down Expand Up @@ -4921,7 +4936,8 @@ struct frostfire_empowerment_t final : public spell_t
spell_t( n, p, p->find_spell( 431186 ) ),
freezing_source( p->get_proc( "Freezing applied (Frostfire Empowerment)" ) )
{
background = proc = secondary_targets_only = true;
background = proc = true;
target_filter_callback = secondary_targets_only();
aoe = -1;
base_dd_min = base_dd_max = 1.0;
// TODO: Check how it behaves wrt the excluded main target
Expand All @@ -4946,7 +4962,8 @@ struct flash_freezeburn_t final : public spell_t
spell_t( n, p, p->find_spell( 1278079 ) ),
freezing_source( p->get_proc( "Freezing applied (Flash Freezeburn)" ) )
{
background = proc = secondary_targets_only = true;
background = proc = true;
target_filter_callback = secondary_targets_only();
base_dd_min = base_dd_max = 1.0;
// TODO: Usually hits one fewer target
// It's possible it picks 5 random targets and if one of them happens to be
Expand All @@ -4968,7 +4985,8 @@ struct controlled_instincts_t final : public spell_t
controlled_instincts_t( std::string_view n, mage_t* p ) :
spell_t( n, p, p->find_spell( p->specialization() == MAGE_FROST ? 444487 : 444720 ) )
{
background = proc = secondary_targets_only = true;
background = proc = true;
target_filter_callback = secondary_targets_only();
// Only hits 5 targets despite max_targets being 6
aoe -= 1;
// TODO: The tooltip still mentions this, but it's untestable at the moment since it can't hit 6 or more targets
Expand Down Expand Up @@ -5624,6 +5642,7 @@ void mage_t::create_options()
add_option( opt_bool( "mage.fof_requires_freezing", options.fof_requires_freezing ) );
add_option( opt_bool( "mage.il_requires_freezing", options.il_requires_freezing ) );
add_option( opt_bool( "mage.il_sort_by_freezing", options.il_sort_by_freezing ) );
add_option( opt_bool( "mage.randomize_si_target", options.randomize_si_target ) );
player_t::create_options();
}

Expand Down