diff --git a/engine/class_modules/warlock/sc_warlock.hpp b/engine/class_modules/warlock/sc_warlock.hpp index c71cfb4f89a..e5a9dbe2860 100644 --- a/engine/class_modules/warlock/sc_warlock.hpp +++ b/engine/class_modules/warlock/sc_warlock.hpp @@ -1208,6 +1208,24 @@ struct warlock_t : public parse_player_effects_t return td; } + template + bool dot_or_debuff_active( T d, warlock_td_t* t ) + { + if constexpr ( std::is_invocable_v ) + { + return std::invoke( d, t->debuffs )->check() > 0; + } + else if constexpr ( std::is_invocable_v ) + { + return std::invoke( d, t->dots )->is_ticking(); + } + else + { + sim->error( SEVERE, "%s dot_or_debuff_active: Unsupported type passed.\n", name() ); + return false; + } + } + action_t* create_action_warlock( util::string_view, util::string_view ); action_t* create_action_affliction( util::string_view, util::string_view ); diff --git a/engine/class_modules/warlock/sc_warlock_actions.cpp b/engine/class_modules/warlock/sc_warlock_actions.cpp index bda6ff13189..5d6ac282b57 100644 --- a/engine/class_modules/warlock/sc_warlock_actions.cpp +++ b/engine/class_modules/warlock/sc_warlock_actions.cpp @@ -93,6 +93,43 @@ using namespace helpers; const warlock_td_t* td( player_t* t ) const { return p()->get_target_data( t ); } + template + target_filter_callback_t dot_or_debuff_only( T d ) + { + return [ this, d ]( const action_t*, player_t* t ) { + return p()->dot_or_debuff_active( d, p()->get_target_data( t ) ); + }; + } + + target_filter_callback_t primary_target_or( target_filter_callback_t secondary_filter ) + { + return [ secondary_filter = std::move( secondary_filter ) ]( const action_t* a, player_t* t ) { + return t == a->target || secondary_filter( a, t ); + }; + } + + target_filter_callback_t immolate_or_wither_only() + { + return [ this ]( const action_t*, player_t* t ) { + return td( t )->dots.immolate->is_ticking() || td( t )->dots.wither->is_ticking(); + }; + } + + target_filter_callback_t corruption_or_wither_only() + { + return [ this ]( const action_t*, player_t* t ) { + return td( t )->dots.corruption->is_ticking() || td( t )->dots.wither->is_ticking(); + }; + } + + target_filter_callback_t affliction_core_dots_only() + { + return [ this ]( const action_t*, player_t* t ) { + return td( t )->dots.corruption->is_ticking() || td( t )->dots.wither->is_ticking() + || td( t )->dots.agony->is_ticking() || td( t )->dots.unstable_affliction->is_ticking(); + }; + } + void reset() override { action_base_t::reset(); } @@ -2342,24 +2379,9 @@ using namespace helpers; { channeled = true; - add_child( dark_harvest_dmg ); - } - - std::vector& target_list() const override - { - target_cache.list = warlock_spell_t::target_list(); - - size_t i = target_cache.list.size(); - while ( i > 0 ) - { - i--; - - if ( !td( target_cache.list[ i ] )->dots.corruption->is_ticking() && !td( target_cache.list[ i ] )->dots.wither->is_ticking() - && !td( target_cache.list[ i ] )->dots.agony->is_ticking() && !td( target_cache.list[ i ] )->dots.unstable_affliction->is_ticking() ) - target_cache.list.erase( target_cache.list.begin() + i ); - } + target_filter_callback = affliction_core_dots_only(); - return target_cache.list; + add_child( dark_harvest_dmg ); } bool ready() override @@ -2368,11 +2390,13 @@ using namespace helpers; return false; target_cache.is_valid = false; - return target_list().size() > 0; + return !target_list().empty(); } void tick( dot_t* d ) override { + target_cache.is_valid = false; + warlock_spell_t::tick( d ); const auto& tl = target_list(); @@ -2398,6 +2422,7 @@ using namespace helpers; void execute() override { target_cache.is_valid = false; + warlock_spell_t::execute(); } }; @@ -2422,9 +2447,18 @@ using namespace helpers; struct shadow_of_nathreza_dmg_t : public warlock_spell_t { shadow_of_nathreza_dmg_t( warlock_t* p ) - : warlock_spell_t( "shadow_of_nathreza", p, p->talents.shadow_of_nathreza_dot ) + : warlock_spell_t( "Shadow of Nathreza", p, p->talents.shadow_of_nathreza_dot ) { background = dual = true; + + target_filter_callback = primary_target_or( corruption_or_wither_only() ); + } + + void execute() override + { + target_cache.is_valid = false; + + warlock_spell_t::execute(); } }; @@ -3591,9 +3625,10 @@ using namespace helpers; add_child( fnb_action ); } + // Custom init() to combine Havoc+FnB coefficients instead of using the generic warlock_spell_t::init() Havoc multiplier void init() override { - spell_t::init(); + action_base_t::init(); if ( affected_by.havoc ) { @@ -4584,6 +4619,8 @@ using namespace helpers; may_crit = false; cooldown->hasted = true; + target_filter_callback = immolate_or_wither_only(); + if ( !p->talents.demonfire_infusion.ok() || p->talents.channel_demonfire.ok() ) add_child( channel_demonfire_tick ); @@ -4594,22 +4631,6 @@ using namespace helpers; } } - std::vector& target_list() const override - { - target_cache.list = warlock_spell_t::target_list(); - - size_t i = target_cache.list.size(); - while ( i > 0 ) - { - i--; - - if ( !td( target_cache.list[ i ] )->dots.immolate->is_ticking() && !td( target_cache.list[ i ] )->dots.wither->is_ticking() ) - target_cache.list.erase( target_cache.list.begin() + i ); - } - - return target_cache.list; - } - void tick( dot_t* d ) override { target_cache.is_valid = false; @@ -4627,10 +4648,11 @@ using namespace helpers; bool ready() override { - if ( p()->get_active_dots( td( target )->dots.immolate ) == 0 && p()->get_active_dots( td( target )->dots.wither ) == 0 ) + if ( !warlock_spell_t::ready() ) return false; - return warlock_spell_t::ready(); + target_cache.is_valid = false; + return !target_list().empty(); } };