Skip to content

Commit 0bd6473

Browse files
committed
[DemonHunter] voidfall proc rate is stack-dependent for vengeance
WCL analysis (55,865 eligible casts) shows voidfall building proc chance decreases with current stack count, rather than being a flat rate from spell data (effectN(3) = 35%): 0 stacks: 39.8% [95% CI: 39.2-40.4%] (p<0.0001 vs 35%) 1 stack: 32.1% [95% CI: 31.4-32.7%] (p<0.0001 vs 35%) 2 stacks: 27.5% [95% CI: 26.8-28.3%] (p<0.0001 vs 35%) Vengeance only — Devourer retains the flat spell data rate pending separate WCL analysis. Defaults exposed as player options for tuning. Local sim impact on Vengeance Annihilator build: -1.14% DPS (66,349 -> 65,591), driven by fewer voidfall meteor procs (37.6 -> 36.5 per fight).
1 parent 12b2c91 commit 0bd6473

File tree

1 file changed

+24
-1
lines changed

1 file changed

+24
-1
lines changed

engine/class_modules/sc_demon_hunter.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,10 @@ class demon_hunter_t : public parse_player_effects_t
12151215
double wounded_quarry_chance_vengeance = 0.30;
12161216
// Proc rate for Wounded Quarry for Havoc
12171217
double wounded_quarry_chance_havoc = 0.10;
1218+
// Proc rate for Voidfall per current building stack count (from WCL analysis)
1219+
double voidfall_proc_chance_0_stacks = 0.40;
1220+
double voidfall_proc_chance_1_stacks = 0.32;
1221+
double voidfall_proc_chance_2_stacks = 0.275;
12181222
// How many seconds that Vengeful Retreat locks out Felblade
12191223
double felblade_lockout_from_vengeful_retreat = 0.6;
12201224
bool enable_dungeon_slice = false;
@@ -2935,10 +2939,25 @@ struct voidfall_building_trigger_t : public BASE
29352939
{
29362940
using base_t = voidfall_building_trigger_t<BASE>;
29372941

2942+
// Proc chance per current building stack count, cached at construction.
2943+
// Vengeance uses per-stack rates from WCL analysis; Devourer uses flat spell data rate.
2944+
std::array<double, 3> voidfall_proc_chances;
2945+
29382946
voidfall_building_trigger_t( util::string_view n, demon_hunter_t* p, const spell_data_t* s = spell_data_t::nil(),
29392947
util::string_view o = {} )
29402948
: BASE( n, p, s, o )
29412949
{
2950+
if ( p->specialization() == DEMON_HUNTER_VENGEANCE )
2951+
{
2952+
voidfall_proc_chances = { p->options.voidfall_proc_chance_0_stacks,
2953+
p->options.voidfall_proc_chance_1_stacks,
2954+
p->options.voidfall_proc_chance_2_stacks };
2955+
}
2956+
else
2957+
{
2958+
double flat = p->talent.annihilator.voidfall->effectN( 3 ).percent();
2959+
voidfall_proc_chances = { flat, flat, flat };
2960+
}
29422961
}
29432962

29442963
void execute() override
@@ -2948,7 +2967,8 @@ struct voidfall_building_trigger_t : public BASE
29482967
if ( !BASE::p()->talent.annihilator.voidfall->ok() )
29492968
return;
29502969

2951-
if ( !BASE::rng().roll( BASE::p()->talent.annihilator.voidfall->effectN( 3 ).percent() ) )
2970+
int stacks = BASE::p()->buff.voidfall_building->check();
2971+
if ( !BASE::rng().roll( voidfall_proc_chances[ std::min( stacks, 2 ) ] ) )
29522972
return;
29532973

29542974
// can't gain building while spending is up
@@ -10113,6 +10133,9 @@ void demon_hunter_t::create_options()
1011310133
opt_float( "soul_fragment_movement_consume_chance", options.soul_fragment_movement_consume_chance, 0, 1 ) );
1011410134
add_option( opt_float( "wounded_quarry_chance_vengeance", options.wounded_quarry_chance_vengeance, 0, 1 ) );
1011510135
add_option( opt_float( "wounded_quarry_chance_havoc", options.wounded_quarry_chance_havoc, 0, 1 ) );
10136+
add_option( opt_float( "voidfall_proc_chance_0_stacks", options.voidfall_proc_chance_0_stacks, 0, 1 ) );
10137+
add_option( opt_float( "voidfall_proc_chance_1_stacks", options.voidfall_proc_chance_1_stacks, 0, 1 ) );
10138+
add_option( opt_float( "voidfall_proc_chance_2_stacks", options.voidfall_proc_chance_2_stacks, 0, 1 ) );
1011610139
add_option(
1011710140
opt_float( "felblade_lockout_from_vengeful_retreat", options.felblade_lockout_from_vengeful_retreat, 0, 1 ) );
1011810141
add_option( opt_bool( "enable_dungeon_slice", options.enable_dungeon_slice ) );

0 commit comments

Comments
 (0)