Skip to content

Commit be13a8d

Browse files
committed
[DemonHunter] voidfall proc rate is stack-dependent
WCL analysis of ~72k eligible casts shows voidfall building proc chance decreases with current stack count. Data fits rate = base - k*sqrt(stacks) within 0.5pp, but no spell data parameterizes the decay. Per-spec rates from WCL (Devourer procs ~2pp higher than Vengeance at all stack levels): Vengeance (21,942 casts): 38.5% / 32.5% / 30.0% Devourer (50,067 casts): 41.0% / 34.0% / 32.5% Resolved in hero_spec following the wounded_quarry_proc_rate pattern. Defaults exposed as per-spec player options for tuning.
1 parent 12b2c91 commit be13a8d

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

engine/class_modules/sc_demon_hunter.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ class demon_hunter_t : public parse_player_effects_t
916916
const spell_data_t* thrill_of_the_fight_haste_buff;
917917
const spell_data_t* thrill_of_the_fight_damage_buff;
918918
double wounded_quarry_proc_rate;
919+
std::array<double, 3> voidfall_proc_chances;
919920

920921
// Annihilator
921922
const spell_data_t* voidfall_meteor;
@@ -1215,6 +1216,15 @@ class demon_hunter_t : public parse_player_effects_t
12151216
double wounded_quarry_chance_vengeance = 0.30;
12161217
// Proc rate for Wounded Quarry for Havoc
12171218
double wounded_quarry_chance_havoc = 0.10;
1219+
// Voidfall proc rate per building stack count (WCL analysis, ~72k casts).
1220+
// Fits rate = base - k*sqrt(stacks) within 0.5pp, but no spell data
1221+
// parameterizes the decay, so these are likely server-side lookup tables.
1222+
double voidfall_proc_chance_0_stacks_vengeance = 0.385;
1223+
double voidfall_proc_chance_1_stacks_vengeance = 0.325;
1224+
double voidfall_proc_chance_2_stacks_vengeance = 0.30;
1225+
double voidfall_proc_chance_0_stacks_havoc = 0.41;
1226+
double voidfall_proc_chance_1_stacks_havoc = 0.34;
1227+
double voidfall_proc_chance_2_stacks_havoc = 0.325;
12181228
// How many seconds that Vengeful Retreat locks out Felblade
12191229
double felblade_lockout_from_vengeful_retreat = 0.6;
12201230
bool enable_dungeon_slice = false;
@@ -2948,7 +2958,8 @@ struct voidfall_building_trigger_t : public BASE
29482958
if ( !BASE::p()->talent.annihilator.voidfall->ok() )
29492959
return;
29502960

2951-
if ( !BASE::rng().roll( BASE::p()->talent.annihilator.voidfall->effectN( 3 ).percent() ) )
2961+
int stacks = std::min( BASE::p()->buff.voidfall_building->check(), 2 );
2962+
if ( !BASE::rng().roll( BASE::p()->hero_spec.voidfall_proc_chances[ stacks ] ) )
29522963
return;
29532964

29542965
// can't gain building while spending is up
@@ -10113,6 +10124,12 @@ void demon_hunter_t::create_options()
1011310124
opt_float( "soul_fragment_movement_consume_chance", options.soul_fragment_movement_consume_chance, 0, 1 ) );
1011410125
add_option( opt_float( "wounded_quarry_chance_vengeance", options.wounded_quarry_chance_vengeance, 0, 1 ) );
1011510126
add_option( opt_float( "wounded_quarry_chance_havoc", options.wounded_quarry_chance_havoc, 0, 1 ) );
10127+
add_option( opt_float( "voidfall_proc_chance_0_stacks_vengeance", options.voidfall_proc_chance_0_stacks_vengeance, 0, 1 ) );
10128+
add_option( opt_float( "voidfall_proc_chance_1_stacks_vengeance", options.voidfall_proc_chance_1_stacks_vengeance, 0, 1 ) );
10129+
add_option( opt_float( "voidfall_proc_chance_2_stacks_vengeance", options.voidfall_proc_chance_2_stacks_vengeance, 0, 1 ) );
10130+
add_option( opt_float( "voidfall_proc_chance_0_stacks_havoc", options.voidfall_proc_chance_0_stacks_havoc, 0, 1 ) );
10131+
add_option( opt_float( "voidfall_proc_chance_1_stacks_havoc", options.voidfall_proc_chance_1_stacks_havoc, 0, 1 ) );
10132+
add_option( opt_float( "voidfall_proc_chance_2_stacks_havoc", options.voidfall_proc_chance_2_stacks_havoc, 0, 1 ) );
1011610133
add_option(
1011710134
opt_float( "felblade_lockout_from_vengeful_retreat", options.felblade_lockout_from_vengeful_retreat, 0, 1 ) );
1011810135
add_option( opt_bool( "enable_dungeon_slice", options.enable_dungeon_slice ) );
@@ -10981,20 +10998,27 @@ void demon_hunter_t::init_spells()
1098110998
hero_spec.meteor_shower_driver = talent_spell_lookup( talent.annihilator.dark_matter, 1264126 );
1098210999
hero_spec.meteor_shower_damage = hero_spec.meteor_shower_driver->effectN( 1 ).trigger();
1098311000
hero_spec.world_killer = talent_spell_lookup( talent.annihilator.world_killer, 1256618 );
11001+
hero_spec.voidfall_proc_chances = { options.voidfall_proc_chance_0_stacks_havoc,
11002+
options.voidfall_proc_chance_1_stacks_havoc,
11003+
options.voidfall_proc_chance_2_stacks_havoc };
1098411004
break;
1098511005
case DEMON_HUNTER_VENGEANCE:
1098611006
hero_spec.voidfall_meteor = talent_spell_lookup( talent.annihilator.voidfall, 1256303 );
1098711007
hero_spec.catastrophe_dot = talent_spell_lookup( talent.annihilator.catastrophe, 1256667 );
1098811008
hero_spec.meteor_shower_driver = talent_spell_lookup( talent.annihilator.dark_matter, 1264128 );
1098911009
hero_spec.meteor_shower_damage = hero_spec.meteor_shower_driver->effectN( 1 ).trigger();
1099011010
hero_spec.world_killer = talent_spell_lookup( talent.annihilator.world_killer, 1256616 );
11011+
hero_spec.voidfall_proc_chances = { options.voidfall_proc_chance_0_stacks_vengeance,
11012+
options.voidfall_proc_chance_1_stacks_vengeance,
11013+
options.voidfall_proc_chance_2_stacks_vengeance };
1099111014
break;
1099211015
default:
1099311016
hero_spec.voidfall_meteor = spell_data_t::not_found();
1099411017
hero_spec.catastrophe_dot = spell_data_t::not_found();
1099511018
hero_spec.meteor_shower_driver = spell_data_t::not_found();
1099611019
hero_spec.meteor_shower_damage = spell_data_t::not_found();
1099711020
hero_spec.world_killer = spell_data_t::not_found();
11021+
hero_spec.voidfall_proc_chances = { 0, 0, 0 };
1099811022
break;
1099911023
}
1100011024

0 commit comments

Comments
 (0)