diff --git a/engine/class_modules/sc_demon_hunter.cpp b/engine/class_modules/sc_demon_hunter.cpp index 53ee97a8820..97edb7cc89a 100644 --- a/engine/class_modules/sc_demon_hunter.cpp +++ b/engine/class_modules/sc_demon_hunter.cpp @@ -262,6 +262,8 @@ class demon_hunter_t : public parse_player_effects_t event_t* exit_melee_event; // Event to disable melee abilities mid-VR. + event_t* winning_streak_conversion_event; + // Buffs struct buffs_t { @@ -1107,6 +1109,37 @@ class demon_hunter_t : public parse_player_effects_t target_specific_t _target_data; }; +struct winning_streak_conversion_event_t : public event_t +{ + demon_hunter_t& dh; + winning_streak_conversion_event_t( demon_hunter_t* p, timespan_t delay ) : event_t( *p->sim, delay ), dh( *p ) + { + } + const char* name() const override + { + return "winning_streak_conversion"; + } + + void execute() override + { + int residual_stacks = dh.buff.winning_streak_residual->stack(); + int new_stacks = dh.buff.winning_streak->stack(); + dh.buff.winning_streak->expire(); + dh.proc.winning_streak_drop_from_tww2_havoc_2pc->occur(); + + if ( new_stacks >= residual_stacks ) + { + dh.buff.winning_streak_residual->expire(); + dh.buff.winning_streak_residual->trigger( new_stacks + residual_stacks ); + } + else + { + dh.proc.winning_streak_drop_wasted_from_tww2_havoc_2pc->occur(); + } + dh.winning_streak_conversion_event = nullptr; + } +}; + // Delayed Execute Event ==================================================== struct delayed_execute_event_t : public event_t @@ -1571,7 +1604,7 @@ class demon_hunter_action_t : public parse_action_effects_t struct { // General - + // Havoc affect_flags a_fire_inside; affect_flags demonic_presence; @@ -2368,22 +2401,9 @@ struct winning_streak_removal_trigger_t : public BASE // 2025-04-13 -- Winning Streak! removal seems to only happen after the triggering spell has finished dealing all // damage - make_event( *BASE::p()->sim, winning_streak_removal_delay, [ this ] { - int residual_stacks = BASE::p()->buff.winning_streak_residual->stack(); - int new_stacks = BASE::p()->buff.winning_streak->stack(); - BASE::p()->buff.winning_streak->expire(); - BASE::p()->proc.winning_streak_drop_from_tww2_havoc_2pc->occur(); - - if ( new_stacks >= residual_stacks ) - { - BASE::p()->buff.winning_streak_residual->expire(); - BASE::p()->buff.winning_streak_residual->trigger( new_stacks + residual_stacks ); - } - else - { - BASE::p()->proc.winning_streak_drop_wasted_from_tww2_havoc_2pc->occur(); - } - } ); + event_t::cancel( BASE::p()->winning_streak_conversion_event ); + BASE::p()->winning_streak_conversion_event = + make_event( *BASE::sim, BASE::p(), winning_streak_removal_delay ); } } }; @@ -4897,7 +4917,8 @@ struct auto_attack_damage_t : public burning_blades_trigger_tdebuffs.reavers_mark->up() ) { + if ( target_data->debuffs.reavers_mark->up() ) + { m *= 1.0 + target_data->debuffs.reavers_mark->check_stack_value(); } @@ -5269,6 +5290,7 @@ struct blade_dance_t : public blade_dance_base_t blade_dance_t( demon_hunter_t* p, util::string_view options_str ) : blade_dance_base_t( "blade_dance", p, p->spec.blade_dance, options_str, nullptr ) { + winning_streak_removal_delay = timespan_t::from_millis( data().effectN( 5 ).misc_value1() + 1 ); if ( attacks.empty() ) { attacks.push_back( p->get_background_action( "blade_dance_1", data().effectN( 2 ) ) ); @@ -5319,7 +5341,8 @@ struct death_sweep_t : public blade_dance_base_t death_sweep_t( demon_hunter_t* p, util::string_view options_str ) : blade_dance_base_t( "death_sweep", p, p->spec.death_sweep, options_str, nullptr ) { - thrill_delay = timespan_t::from_millis( data().effectN( 5 ).misc_value1() + 1 ); + thrill_delay = timespan_t::from_millis( data().effectN( 5 ).misc_value1() + 1 ); + winning_streak_removal_delay = timespan_t::from_millis( data().effectN( 5 ).misc_value1() + 1 ); if ( attacks.empty() ) { @@ -5577,6 +5600,7 @@ struct chaos_strike_t : public chaos_strike_base_t chaos_strike_t( util::string_view name, demon_hunter_t* p, util::string_view options_str = {} ) : chaos_strike_base_t( name, p, p->spec.chaos_strike, options_str ) { + winning_streak_removal_delay = timespan_t::from_millis( data().effectN( 3 ).misc_value1() + 1 ); if ( attacks.empty() ) { attacks.push_back( p->get_background_action( fmt::format( "{}_damage_1", name ), @@ -5614,6 +5638,7 @@ struct annihilation_t : public demonsurge_trigger_tspec.annihilation, options_str ) { + winning_streak_removal_delay = timespan_t::from_millis( data().effectN( 3 ).misc_value1() + 1 ); if ( attacks.empty() ) { attacks.push_back( p->get_background_action( fmt::format( "{}_damage_1", name ), @@ -7127,6 +7152,7 @@ struct metamorphosis_buff_t : public demon_hunter_buff_t if ( p()->set_bonuses.tww2_havoc_4pc->ok() && ( p()->buff.winning_streak->up() || p()->buff.winning_streak_residual->up() ) ) { + event_t::cancel( p()->winning_streak_conversion_event ); // 2025-02-08 -- Necessary Sacrifice will not be triggered if the number of stacks on Winning Streak! is less than // the number of stacks on Necessary Sacrifice @@ -9513,15 +9539,16 @@ void demon_hunter_t::reset() { base_t::reset(); - soul_fragment_pick_up = nullptr; - frailty_driver = nullptr; - exit_melee_event = nullptr; - next_fragment_spawn = 0; - metamorphosis_health = 0; - frailty_accumulator = 0.0; - shattered_destiny_accumulator = 0.0; - wounded_quarry_accumulator = 0.0; - last_reavers_mark_applied = nullptr; + soul_fragment_pick_up = nullptr; + frailty_driver = nullptr; + exit_melee_event = nullptr; + winning_streak_conversion_event = nullptr; + next_fragment_spawn = 0; + metamorphosis_health = 0; + frailty_accumulator = 0.0; + shattered_destiny_accumulator = 0.0; + wounded_quarry_accumulator = 0.0; + last_reavers_mark_applied = nullptr; for ( size_t i = 0; i < soul_fragments.size(); i++ ) {