-- DemonHunterHavoc.lua
-- June 2018
local addon , ns = ...
local Hekili = _G [ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
-- Conduits
-- [-] dancing_with_fate
-- [-] relentless_onslaught
-- [-] growing_inferno
-- [x] serrated_glaive
-- Covenant
-- [-] repeat_decree
-- [x] increased_scrutiny
-- [x] brooding_pool
-- [-] unnatural_malice
-- Endurance
-- [x] fel_defender
-- [-] shattered_restoration
-- [-] viscous_ink
-- Finesse
-- [-] demonic_parole
-- [x] felfire_haste
-- [-] lost_in_darkness
-- [-] ravenous_consumption
if UnitClassBase ( " player " ) == " DEMONHUNTER " then
local spec = Hekili : NewSpecialization ( 577 )
spec : RegisterResource ( Enum.PowerType . Fury , {
prepared = {
talent = " momentum " ,
aura = " prepared " ,
last = function ( )
local app = state.buff . prepared.applied
local t = state.query_time
local step = 0.1
return app + floor ( t - app )
end ,
interval = 1 ,
value = 8
} ,
-- Immolation Aura now grants 20 up front, 60 over 12 seconds (5 fps).
immolation_aura = {
talent = " burning_hatred " ,
aura = " immolation_aura " ,
last = function ( )
local app = state.buff . immolation_aura.applied
local t = state.query_time
return app + floor ( t - app )
end ,
interval = 1 ,
value = 5
} ,
eye_beam = {
talent = " blind_fury " ,
aura = " eye_beam " ,
last = function ( )
local app = state.buff . eye_beam.applied
local t = state.query_time
return app + floor ( t - app )
end ,
interval = function ( ) return 1 * state.haste end ,
value = 40 ,
} ,
} )
-- Talents
spec : RegisterTalents ( {
blind_fury = 21854 , -- 203550
demonic_appetite = 22493 , -- 206478
felblade = 22416 , -- 232893
insatiable_hunger = 21857 , -- 258876
burning_hatred = 22765 , -- 320374
demon_blades = 22799 , -- 203555
trail_of_ruin = 22909 , -- 258881
unbound_chaos = 22494 , -- 347461
glaive_tempest = 21862 , -- 342817
soul_rending = 21863 , -- 204909
desperate_instincts = 21864 , -- 205411
netherwalk = 21865 , -- 196555
cycle_of_hatred = 21866 , -- 258887
first_blood = 21867 , -- 206416
essence_break = 21868 , -- 258860
unleashed_power = 21869 , -- 206477
master_of_the_glaive = 21870 , -- 203556
fel_eruption = 22767 , -- 211881
demonic = 21900 , -- 213410
momentum = 21901 , -- 206476
fel_barrage = 22547 , -- 258925
} )
-- PvP Talents
spec : RegisterPvpTalents ( {
blood_moon = 5433 , -- 355995
chaotic_imprint = 809 , -- 356510
cleansed_by_flame = 805 , -- 205625
cover_of_darkness = 1206 , -- 357419
demonic_origins = 810 , -- 235893
detainment = 812 , -- 205596
glimpse = 813 , -- 354489
isolated_prey = 5445 , -- 357300
mortal_dance = 1204 , -- 328725
rain_from_above = 811 , -- 206803
reverse_magic = 806 , -- 205604
unending_hatred = 1218 , -- 213480
} )
-- Auras
spec : RegisterAuras ( {
blade_dance = {
id = 188499 ,
duration = 1 ,
max_stack = 1
} ,
blur = {
id = 212800 ,
duration = 10 ,
max_stack = 1 ,
} ,
chaos_brand = {
id = 1490 ,
duration = 3600 ,
max_stack = 1 ,
} ,
chaos_nova = {
id = 179057 ,
duration = function ( ) return pvptalent.isolated_prey . enabled and active_enemies == 1 and 3 or 2 end ,
type = " Magic " ,
max_stack = 1 ,
} ,
chaotic_blades = {
id = 337567 ,
duration = 8 ,
max_stack = 1 ,
copy = " chaos_theory " -- simc.
} ,
darkness = {
id = 196718 ,
duration = function ( ) return pvptalent.cover_of_darkness . enabled and 10 or 8 end ,
max_stack = 1 ,
} ,
death_sweep = {
id = 210152 ,
duration = 1 ,
max_stack = 1 ,
} ,
demon_blades = {
id = 203555 ,
} ,
demonic_wards = {
id = 278386 ,
} ,
double_jump = {
id = 196055 ,
} ,
essence_break = {
id = 320338 ,
duration = 8 ,
max_stack = 1 ,
copy = " dark_slash " -- Just in case.
} ,
eye_beam = {
id = 198013 ,
duration = function ( ) return ( talent.blind_fury . enabled and 3 or 2 ) * haste end ,
max_stack = 1 ,
generate = function ( t )
if buff.casting . up and buff.casting . v1 == 198013 then
t.applied = buff.casting . applied
t.duration = buff.casting . duration
t.expires = buff.casting . expires
t.stack = 1
t.caster = " player "
forecastResources ( " fury " )
return
end
t.applied = 0
t.duration = class.auras . eye_beam.duration
t.expires = 0
t.stack = 0
t.caster = " nobody "
end ,
} ,
fel_barrage = {
id = 258925 ,
} ,
fel_eruption = {
id = 211881 ,
duration = 4 ,
max_stack = 1 ,
} ,
-- Legendary
fel_bombardment = {
id = 337849 ,
duration = 40 ,
max_stack = 5 ,
} ,
-- Legendary
fel_devastation = {
id = 333105 ,
duration = 2 ,
max_stack = 1 ,
} ,
furious_gaze = {
id = 343312 ,
duration = 12 ,
max_stack = 1 ,
} ,
glide = {
id = 131347 ,
} ,
immolation_aura = {
id = 258920 ,
duration = 12 ,
max_stack = 1 ,
} ,
inner_demon = {
id = 337313 ,
duration = 3600 ,
max_stack = 1 ,
} ,
master_of_the_glaive = {
id = 213405 ,
duration = 6 ,
max_stack = 1 ,
} ,
metamorphosis = {
id = 162264 ,
duration = function ( ) return pvptalent.demonic_origins . enabled and 15 or 30 end ,
max_stack = 1 ,
meta = {
extended_by_demonic = function ( )
return false -- disabled in 8.0: talent.demonic.enabled and ( buff.metamorphosis.up and buff.metamorphosis.duration % 15 > 0 and buff.metamorphosis.duration > ( action.eye_beam.cast + 8 ) )
end ,
} ,
} ,
momentum = {
id = 208628 ,
duration = 6 ,
max_stack = 1 ,
} ,
netherwalk = {
id = 196555 ,
duration = 6 ,
max_stack = 1 ,
} ,
prepared = {
id = 203650 ,
duration = 10 ,
max_stack = 1 ,
} ,
spectral_sight = {
id = 188501 ,
duration = 10 ,
max_stack = 1 ,
} ,
torment = {
id = 185245 ,
duration = 3 ,
max_stack = 1 ,
} ,
trail_of_ruin = {
id = 258883 ,
duration = 4 ,
max_stack = 1 ,
} ,
unbound_chaos = {
id = 347462 ,
duration = 20 ,
max_stack = 1
} ,
unrestrained_fury = {
id = 320770 ,
} ,
vengeful_retreat = {
id = 198793 ,
duration = 3 ,
max_stack = 1 ,
} ,
demon_soul = {
id = 208195 ,
duration = 20 ,
max_stack = 1 ,
} ,
-- PvP Talents
rain_from_above_launch = {
id = 206803 ,
duration = 1 ,
max_stack = 1 ,
} ,
rain_from_above = {
id = 206804 ,
duration = 10 ,
max_stack = 1 ,
} ,
-- Azerite
thirsting_blades = {
id = 278736 ,
duration = 30 ,
max_stack = 40 ,
meta = {
stack = function ( t )
if t.down then return 0 end
local appliedBuffer = ( now - t.applied ) % 1
return min ( 40 , t.count + floor ( offset + delay + appliedBuffer ) )
end ,
}
} ,
-- Conduit
exposed_wound = {
id = 339229 ,
duration = 10 ,
max_stack = 1 ,
} ,
-- PvP Talents
chaotic_imprint_shadow = {
id = 356656 ,
duration = 20 ,
max_stack = 1 ,
} ,
chaotic_imprint_nature = {
id = 356660 ,
duration = 20 ,
max_stack = 1 ,
} ,
chaotic_imprint_arcane = {
id = 356658 ,
duration = 20 ,
max_stack = 1 ,
} ,
chaotic_imprint_fire = {
id = 356661 ,
duration = 20 ,
max_stack = 1 ,
} ,
chaotic_imprint_frost = {
id = 356659 ,
duration = 20 ,
max_stack = 1 ,
} ,
glimpse = {
id = 354610 ,
duration = 8 ,
max_stack = 1 ,
} ,
isolated_prey = {
id = 357305 ,
duration = 6 ,
max_stack = 1 ,
} ,
mortal_dance = {
id = 328725 ,
duration = 5 ,
max_stack = 1 ,
} ,
} )
local last_darkness = 0
local last_metamorphosis = 0
local last_eye_beam = 0
spec : RegisterStateExpr ( " darkness_applied " , function ( )
return max ( class.abilities . darkness.lastCast , last_darkness )
end )
spec : RegisterStateExpr ( " metamorphosis_applied " , function ( )
return max ( class.abilities . darkness.lastCast , last_metamorphosis )
end )
spec : RegisterStateExpr ( " eye_beam_applied " , function ( )
return max ( class.abilities . eye_beam.lastCast , last_eye_beam )
end )
spec : RegisterStateExpr ( " extended_by_demonic " , function ( )
return buff.metamorphosis . up and buff.metamorphosis . extended_by_demonic
end )
spec : RegisterStateExpr ( " meta_cd_multiplier " , function ( )
return 1
end )
spec : RegisterHook ( " reset_precast " , function ( )
last_darkness = 0
last_metamorphosis = 0
last_eye_beam = 0
local rps = 0
if equipped.convergence_of_fates then
rps = rps + ( 3 / ( 60 / 4.35 ) )
end
if equipped.delusions_of_grandeur then
-- From SimC model, 1/13/2018.
local fps = 10.2 + ( talent.demonic . enabled and 1.2 or 0 )
-- SimC uses base haste, we'll use current since we recalc each time.
fps = fps / haste
-- Chaos Strike accounts for most Fury expenditure.
fps = fps + ( ( fps * 0.9 ) * 0.5 * ( 40 / 100 ) )
rps = rps + ( fps / 30 ) * ( 1 )
end
meta_cd_multiplier = 1 / ( 1 + rps )
end )
spec : RegisterHook ( " spend " , function ( amt , resource )
--[[ if level < 116 and equipped.delusions_of_grandeur and resource == "fury" then
-- revisit this if really needed...
cooldown.metamorphosis . expires = cooldown.metamorphosis . expires - ( amt / 30 )
end ] ]
end )
spec : RegisterCycle ( function ( )
if active_enemies == 1 then return end
-- For Nemesis, we want to cast it on the lowest health enemy.
if this_action == " nemesis " and Hekili : GetNumTTDsWithin ( target.time_to_die ) > 1 then return " cycle " end
end )
-- Gear Sets
spec : RegisterGear ( " tier19 " , 138375 , 138376 , 138377 , 138378 , 138379 , 138380 )
spec : RegisterGear ( " tier20 " , 147130 , 147132 , 147128 , 147127 , 147129 , 147131 )
spec : RegisterGear ( " tier21 " , 152121 , 152123 , 152119 , 152118 , 152120 , 152122 )
spec : RegisterAura ( " havoc_t21_4pc " , {
id = 252165 ,
duration = 8
} )
spec : RegisterGear ( " class " , 139715 , 139716 , 139717 , 139718 , 139719 , 139720 , 139721 , 139722 )
spec : RegisterGear ( " convergence_of_fates " , 140806 )
spec : RegisterGear ( " achor_the_eternal_hunger " , 137014 )
spec : RegisterGear ( " anger_of_the_halfgiants " , 137038 )
spec : RegisterGear ( " cinidaria_the_symbiote " , 133976 )
spec : RegisterGear ( " delusions_of_grandeur " , 144279 )
spec : RegisterGear ( " kiljaedens_burning_wish " , 144259 )
spec : RegisterGear ( " loramus_thalipedes_sacrifice " , 137022 )
spec : RegisterGear ( " moarg_bionic_stabilizers " , 137090 )
spec : RegisterGear ( " prydaz_xavarics_magnum_opus " , 132444 )
spec : RegisterGear ( " raddons_cascading_eyes " , 137061 )
spec : RegisterGear ( " sephuzs_secret " , 132452 )
spec : RegisterGear ( " the_sentinels_eternal_refuge " , 146669 )
spec : RegisterGear ( " soul_of_the_slayer " , 151639 )
spec : RegisterGear ( " chaos_theory " , 151798 )
spec : RegisterGear ( " oblivions_embrace " , 151799 )
do
local wasWarned = false
spec : RegisterEvent ( " PLAYER_REGEN_DISABLED " , function ( )
if state.talent . demon_blades.enabled and not state.settings . demon_blades_acknowledged and not wasWarned then
Hekili : Notify ( " |cFFFF0000WARNING!|r Demon Blades cannot be forecasted. \n See /hekili > Havoc for more information. " )
wasWarned = true
end
end )
end
-- SimC documentation reflects that there are still the following expressions, which appear unused:
-- greater_soul_fragments, lesser_soul_fragments, blade_dance_worth_using, death_sweep_worth_using
-- They are not implemented becuase that documentation is from mid-2016.
-- Abilities
spec : RegisterAbilities ( {
annihilation = {
id = 201427 ,
known = 162794 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return 40 - buff.thirsting_blades . stack end ,
spendType = " fury " ,
startsCombat = true ,
texture = 1303275 ,
bind = " chaos_strike " ,
buff = " metamorphosis " ,
handler = function ( )
removeBuff ( " thirsting_blades " )
if azerite.thirsting_blades . enabled then applyBuff ( " thirsting_blades " , nil , 0 ) end
if buff.chaotic_blades . up then gain ( 20 , " fury " ) end -- legendary
end ,
} ,
blade_dance = {
id = 188499 ,
cast = 0 ,
cooldown = 9 ,
hasteCD = true ,
gcd = " spell " ,
spend = function ( ) return 35 - ( talent.first_blood . enabled and 20 or 0 ) end ,
spendType = " fury " ,
startsCombat = true ,
texture = 1305149 ,
bind = " death_sweep " ,
nobuff = " metamorphosis " ,
handler = function ( )
applyBuff ( " blade_dance " )
setCooldown ( " death_sweep " , 9 * haste )
if pvptalent.mortal_dance . enabled then
applyDebuff ( " target " , " mortal_dance " )
end
end ,
} ,
blur = {
id = 198589 ,
cast = 0 ,
cooldown = function ( ) return 60 + ( conduit.fel_defender . mod * 0.001 ) end ,
gcd = " off " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 1305150 ,
handler = function ( )
applyBuff ( " blur " )
end ,
} ,
chaos_nova = {
id = 179057 ,
cast = 0 ,
cooldown = function ( ) return talent.unleashed_power . enabled and 40 or 60 end ,
gcd = " spell " ,
spend = function ( ) return talent.unleashed_power . enabled and 0 or 30 end ,
spendType = " fury " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 135795 ,
handler = function ( )
applyDebuff ( " target " , " chaos_nova " )
end ,
} ,
chaos_strike = {
id = 162794 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return 40 - buff.thirsting_blades . stack end ,
spendType = " fury " ,
startsCombat = true ,
texture = 1305152 ,
bind = " annihilation " ,
nobuff = " metamorphosis " ,
cycle = function ( ) return legendary.burning_wound . enabled and " burning_wound " or nil end ,
handler = function ( )
removeBuff ( " thirsting_blades " )
if azerite.thirsting_blades . enabled then applyBuff ( " thirsting_blades " , nil , 0 ) end
if legendary.burning_wound . enabled then applyDebuff ( " target " , " burning_wound " ) end
if buff.chaotic_blades . up then gain ( 20 , " fury " ) end -- legendary
end ,
auras = {
burning_wound = {
id = 346278 ,
duration = 15 ,
max_stack = 1
}
}
} ,
consume_magic = {
id = 278326 ,
cast = 0 ,
cooldown = 10 ,
gcd = " spell " ,
startsCombat = true ,
texture = 828455 ,
usable = function ( ) return buff.dispellable_magic . up end ,
handler = function ( )
removeBuff ( " dispellable_magic " )
gain ( buff.solitude . up and 22 or 20 , " fury " )
end ,
} ,
darkness = {
id = 196718 ,
cast = 0 ,
cooldown = 180 ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 1305154 ,
handler = function ( )
last_darkness = query_time
applyBuff ( " darkness " )
end ,
} ,
death_sweep = {
id = 210152 ,
known = 188499 ,
cast = 0 ,
cooldown = 9 ,
hasteCD = true ,
gcd = " spell " ,
spend = function ( ) return talent.first_blood . enabled and 15 or 35 end ,
spendType = " fury " ,
startsCombat = true ,
texture = 1309099 ,
bind = " blade_dance " ,
buff = " metamorphosis " ,
handler = function ( )
applyBuff ( " death_sweep " )
setCooldown ( " blade_dance " , 9 * haste )
if pvptalent.mortal_dance . enabled then
applyDebuff ( " target " , " mortal_dance " )
end
end ,
} ,
demons_bite = {
id = 162243 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return talent.insatiable_hunger . enabled and - 25 or - 20 end ,
spendType = " fury " ,
startsCombat = true ,
texture = 135561 ,
notalent = " demon_blades " ,
handler = function ( )
end ,
} ,
disrupt = {
id = 183752 ,
cast = 0 ,
cooldown = 15 ,
gcd = " off " ,
startsCombat = true ,
texture = 1305153 ,
toggle = " interrupts " ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
interrupt ( )
gain ( buff.solitude . up and 33 or 30 , " fury " )
end ,
} ,
essence_break = {
id = 258860 ,
cast = 0 ,
cooldown = 20 ,
gcd = " spell " ,
startsCombat = true ,
texture = 136189 ,
handler = function ( )
applyDebuff ( " target " , " essence_break " )
active_dot.essence_break = max ( 1 , active_enemies )
end ,
copy = " dark_slash "
} ,
eye_beam = {
id = 198013 ,
cast = function ( ) return ( talent.blind_fury . enabled and 3 or 2 ) * haste end ,
cooldown = 30 ,
channeled = true ,
gcd = " spell " ,
spend = 30 ,
spendType = " fury " ,
startsCombat = true ,
texture = 1305156 ,
start = function ( )
last_eye_beam = query_time
applyBuff ( " eye_beam " )
if talent.demonic . enabled then
if buff.metamorphosis . up then
buff.metamorphosis . duration = buff.metamorphosis . remains + 8
buff.metamorphosis . expires = buff.metamorphosis . expires + 8
else
applyBuff ( " metamorphosis " , action.eye_beam . cast + 8 )
buff.metamorphosis . duration = action.eye_beam . cast + 8
stat.haste = stat.haste + 25
end
end
if pvptalent.isolated_prey . enabled and active_enemies == 1 then
applyDebuff ( " target " , " isolated_prey " )
end
-- This is likely repeated per tick but it's not worth the CPU overhead to model each tick.
if legendary.agony_gaze . enabled and debuff.sinful_brand . up then
debuff.sinful . brand.expires = debuff.sinful_brand . expires + 0.75
end
end ,
finish = function ( )
if level > 58 then applyBuff ( " furious_gaze " ) end
end ,
} ,
fel_barrage = {
id = 258925 ,
cast = 2 ,
cooldown = 60 ,
channeled = true ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 2065580 ,
talent = " fel_barrage " ,
start = function ( )
applyBuff ( " fel_barrage " , 2 )
end ,
} ,
fel_eruption = {
id = 211881 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 10 ,
spendType = " fury " ,
startsCombat = true ,
texture = 1118739 ,
talent = " fel_eruption " ,
handler = function ( )
applyDebuff ( " target " , " fel_eruption " )
end ,
} ,
fel_rush = {
id = 195072 ,
cast = 0 ,
charges = 2 ,
cooldown = function ( ) return legendary.erratic_fel_core . enabled and 7 or 10 end ,
recharge = function ( ) return legendary.erratic_fel_core . enabled and 7 or 10 end ,
gcd = " spell " ,
startsCombat = true ,
texture = 1247261 ,
usable = function ( )
if settings.recommend_movement ~= true then return false , " fel_rush movement is disabled " end
return not prev_gcd [ 1 ] . fel_rush
end ,
handler = function ( )
removeBuff ( " unbound_chaos " )
if talent.momentum . enabled then applyBuff ( " momentum " ) end
if cooldown.vengeful_retreat . remains < 1 then setCooldown ( " vengeful_retreat " , 1 ) end
setDistance ( 5 )
setCooldown ( " global_cooldown " , 0.25 )
if conduit.felfire_haste . enabled then applyBuff ( " felfire_haste " ) end
if pvptalent.isolated_prey . enabled and active_enemies == 1 then
gain ( 35 , " fury " )
end
end ,
auras = {
-- Conduit
felfire_haste = {
id = 338804 ,
duration = 8 ,
max_stack = 1
}
}
} ,
felblade = {
id = 232893 , cast = 0 ,
cooldown = 15 ,
hasteCD = true ,
gcd = " spell " ,
spend = - 40 ,
spendType = " fury " ,
startsCombat = true ,
texture = 1344646 ,
-- usable = function () return target.within15 end,
handler = function ( )
setDistance ( 5 )
end ,
} ,
fel_lance = {
id = 206966 ,
cast = 1 ,
cooldown = 0 ,
gcd = " spell " ,
pvptalent = " rain_from_above " ,
buff = " rain_from_above " ,
startsCombat = true ,
} ,
glaive_tempest = {
id = 342817 ,
cast = 0 ,
cooldown = 20 ,
hasteCD = true ,
gcd = " spell " ,
spend = 30 ,
spendType = " fury " ,
startsCombat = true ,
texture = 1455916 ,
handler = function ( )
end ,
} ,
immolation_aura = {
id = 258920 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = - 20 ,
spendType = " fury " ,
startsCombat = true ,
texture = 1344649 ,
handler = function ( )
applyBuff ( " immolation_aura " )
if talent.unbound_chaos . enabled then applyBuff ( " unbound_chaos " ) end
end ,
} ,
imprison = {
id = 217832 ,
cast = 0 ,
cooldown = function ( ) return pvptalent.detainment . enabled and 60 or 45 end ,
gcd = " spell " ,
startsCombat = false ,
texture = 1380368 ,
handler = function ( )
applyDebuff ( " target " , " imprison " )
end ,
auras = {
-- Conduit
demonic_parole = {
id = 339051 ,
duration = 12 ,
max_stack = 1
}
}
} ,
metamorphosis = {
id = 191427 ,
cast = 0 ,
cooldown = function ( ) return ( level > 47 and 240 or 300 ) * ( essence.vision_of_perfection . enabled and 0.87 or 1 ) - ( pvptalent.demonic_origins . up and 120 or 0 ) end ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 1247262 ,
handler = function ( )
applyBuff ( " metamorphosis " )
last_metamorphosis = query_time
setDistance ( 5 )
if IsSpellKnownOrOverridesKnown ( 317009 ) then
applyDebuff ( " target " , " sinful_brand " )
active_dot.sinful_brand = active_enemies
end
if level > 19 then stat.haste = stat.haste + 25 end
if level > 53 or azerite.chaotic_transformation . enabled then
setCooldown ( " eye_beam " , 0 )
setCooldown ( " blade_dance " , 0 )
setCooldown ( " death_sweep " , 0 )
end
end ,
meta = {
adjusted_remains = function ( )
--[[ if level < 116 and ( equipped.delusions_of_grandeur or equipped.convergeance_of_fates ) then
return cooldown.metamorphosis . remains * meta_cd_multiplier
end ] ]
return cooldown.metamorphosis . remains
end
}
} ,
nemesis = {
id = 206491 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 236299 ,
talent = " nemesis " ,
handler = function ( )
applyDebuff ( " target " , " nemesis " )
end ,
} ,
netherwalk = {
id = 196555 ,
cast = 0 ,
cooldown = 180 ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = true ,
texture = 463284 ,
talent = " netherwalk " ,
handler = function ( )
applyBuff ( " netherwalk " )
setCooldown ( " global_cooldown " , 6 )
end ,
} ,
rain_from_above = {
id = 206803 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
pvptalent = " rain_from_above " ,
startsCombat = false ,
texture = 1380371 ,
handler = function ( )
applyBuff ( " rain_from_above " )
end ,
} ,
reverse_magic = {
id = 205604 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
-- toggle = "cooldowns",
pvptalent = " reverse_magic " ,
startsCombat = false ,
texture = 1380372 ,
debuff = " reversible_magic " ,
handler = function ( )
if debuff.reversible_magic . up then removeDebuff ( " player " , " reversible_magic " ) end
end ,
} ,
spectral_sight = {
id = 188501 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 1247266 ,
handler = function ( )
end ,
} ,
throw_glaive = {
id = 185123 ,
cast = 0 ,
charges = function ( ) return talent.master_of_the_glaive . enabled and 2 or nil end ,
cooldown = 9 ,
recharge = 9 ,
hasteCD = true ,
gcd = " spell " ,
startsCombat = true ,
texture = 1305159 ,
handler = function ( )
removeBuff ( " fel_bombardment " ) -- legendary
if talent.master_of_the_glaive . enabled then applyDebuff ( " target " , " master_of_the_glaive " ) end
if conduit.serrated_glaive . enabled then applyDebuff ( " target " , " exposed_wound " ) end
end ,
auras = {
-- Conduit: serrated_glaive
exposed_wound = {
id = 339229 ,
duration = 10 ,
max_stack = 1
}
}
} ,
vengeful_retreat = {
id = 198793 ,
cast = 0 ,
cooldown = function ( ) return talent.momentum . enabled and 20 or 25 end ,
gcd = " spell " ,
startsCombat = true ,
texture = 1348401 ,
usable = function ( )
if settings.recommend_movement ~= true then return false , " vengeful_retreat movement is disabled " end
return true
end ,
handler = function ( )
if target.within8 then
applyDebuff ( " target " , " vengeful_retreat " )
if talent.momentum . enabled then applyBuff ( " prepared " ) end
end
if pvptalent.glimpse . enabled then applyBuff ( " glimpse " ) end
end ,
} ,
-- Demon Hunter - Kyrian - 306830 - elysian_decree (Elysian Decree)
elysian_decree = {
id = 306830 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
startsCombat = true ,
texture = 3565443 ,
handler = function ( )
create_sigil ( " elysian_decree " )
if legendary.blind_faith . enabled then applyBuff ( " blind_faith " ) end
end ,
auras = {
blind_faith = {
id = 355894 ,
duration = 20 ,
max_stack = 1 ,
} ,
}
} ,
-- Demon Hunter - Necrolord - 329554 - fodder_to_the_flame (Fodder to the Flame)
--[[ fodder_to_the_flame = {
id = 329554 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
toggle = " essences " ,
startsCombat = true ,
texture = 3591588 ,
handler = function ( )
applyDebuff ( " player " , " fodder_to_the_flame_chase " )
applyDebuff ( " player " , " fodder_to_the_flame_cooldown " )
end ,
auras = {
-- The buff from standing in the pool.
fodder_to_the_flame = {
id = 330910 ,
duration = function ( ) return 30 + ( conduit.brooding_pool . mod * 0.001 ) end ,
max_stack = 1 ,
} ,
-- The demon is linked to you.
fodder_to_the_flame_chase = {
id = 328605 ,
duration = 3600 ,
max_stack = 1 ,
} ,
-- This is essentially the countdown before the demon despawns (you can Imprison it for a long time).
fodder_to_the_flame_cooldown = {
id = 342357 ,
duration = 120 ,
max_stack = 1 ,
} ,
}
} , ] ]
-- Demon Hunter - Night Fae - 323639 - the_hunt (The Hunt)
the_hunt = {
id = 323639 ,
cast = 1 ,
cooldown = 180 ,
gcd = " spell " ,
toggle = " essences " ,
startsCombat = true ,
texture = 3636838 ,
handler = function ( )
applyDebuff ( " target " , " the_hunt " )
applyDebuff ( " target " , " the_hunt_dot " )
applyDebuff ( " target " , " the_hunt_root " )
setDistance ( 5 )
if legendary.blazing_slaughter . enabled then
applyBuff ( " immolation_aura " )
applyBuff ( " blazing_slaughter " )
end
end ,
auras = {
the_hunt_root = {
id = 323996 ,
duration = 1.5 ,
max_stack = 1 ,
} ,
the_hunt_dot = {
id = 345335 ,
duration = 6 ,
max_stack = 1 ,
} ,
the_hunt = {
id = 323802 ,
duration = 30 ,
max_stack = 1 ,
} ,
blazing_slaughter = {
id = 355892 ,
duration = 12 ,
max_stack = 20 ,
}
}
} ,
-- Demon Hunter - Venthyr - 317009 - sinful_brand (Sinful Brand)
sinful_brand = {
id = 317009 ,
cast = 0 ,
cooldown = function ( ) return 60 + ( conduit.sinful_brand . mod * 0.001 ) end ,
gcd = " spell " ,
toggle = " essences " ,
startsCombat = true ,
texture = 3565717 ,
handler = function ( )
applyDebuff ( " target " , " sinful_brand " )
end ,
auras = {
sinful_brand = {
id = 317009 ,
duration = 8 ,
max_stack = 1 ,
}
}
}
} )
spec : RegisterOptions ( {
enabled = true ,
aoe = 2 ,
nameplates = true ,
nameplateRange = 7 ,
damage = true ,
damageExpiration = 8 ,
potion = " phantom_fire " ,
package = " Havoc " ,
} )
spec : RegisterSetting ( " recommend_movement " , true , {
name = " Recommend Movement " ,
desc = " If checked, the addon will recommend |T1247261:0|t Fel Rush / |T1348401:0|t Vengeful Retreat when it is a potential DPS gain. \n \n " ..
" These abilities are critical for DPS when using the Momentum or Unbound Chaos talents. \n \n " ..
" If not using Momentum or Unbound Chaos, you may want to disable this to avoid unnecessary movement in combat. " ,
type = " toggle " ,
width = " full "
} )
spec : RegisterSetting ( " demon_blades_head " , nil , {
name = " Demon Blades " ,
type = " header " ,
} )
spec : RegisterSetting ( " demon_blades_text " , nil , {
name = " |cFFFF0000WARNING!|r If using the |T237507:0|t Demon Blades talent, the addon will not be able to predict Fury gains from your auto-attacks. This will result " ..
" in recommendations that jump forward in your display(s). " ,
type = " description " ,
width = " full "
} )
spec : RegisterSetting ( " demon_blades_acknowledged " , false , {
name = " I understand that Demon Blades is unpredictable; don't warn me. " ,
desc = " If checked, the addon will not provide a warning about Demon Blades when entering combat. " ,
type = " toggle " ,
width = " full "
} )
spec : RegisterPack ( " Havoc " , 20210628 , [ [ dafEtbqievlsQsvEerv1LKQuPnjv6tcuJcrCke0QikqVsqmluQUfcq7IKFbadtQIJjOwgI0ZaqMgcORru02KQu ( MGKghrvPZruvyDiqnpbPUhrSpeL ) HaihuqISqIkpebYejQIlkiHnIaWhjQkAKevP6KefWkbOzsuOBkvPI2Pa5NiaQHkirzPevjpfjtLO0vLQuvFLOGgRuLSxs9xPmyvDyklwPESsMmQUm0MrQpJqJMiDAfRwQsfEnkLzt42aTBQ ( TkdxahNOkLLd65cnDrxhfBhqFxQy8aOoVuvRxqIQ5Js2VK1H1YQP4wI6GiThsd3tVrQ8vrka1tOsAOQPY ( bqnvaBXMre1uUbIAk5Dd4T0ubS ( IZ4Az1uXJbUqnf1aYiSCoNGGgDQP2mJiLbC9wtXTe1brApKgUNEJu5RIuaQNqLuzQPIbWLoizgQHQMs6W5OR3AkogxAk5bbpVE5Dgpry9Y7gWBvaciJJ1tQ8L96jThsdxawasqsnNigj4cqcy99oX0apyaPxCI1BoV ( qzxoNxpt0iI137Tr6dI1tpeLM1Jop27vV4ioR6nEVdMyI86ZRElqar ) 6 px0V ( 8 QFFXy90drPzuPPcap6rGAk5x ( RxEqWZRxENXtewV8Ub8wfGYV8xpGmowpPYx2RN0EinCbybO8l ) 1 tqsnNigj4cq5x ( RNawFVtmnWdgq6fNy9MZRpu2LZ51ZenIy99EBK ( Gy90drPz9OZJ9E1loIZQEJ37GjMiV ( 8 Q3ceq0V ( Zf9RpV63xmwp9quAgvfGfG2kNZJQaqCDGBlLSVmfiVrlS ( iVZ4eB5bWJxaARCopQcaX1bUTmejaaObhBlq2DdeLKWXzdZwSVVArXLSd0emOKWSp0ss44SHPkSsQfBmrSTzOP7sc5jCC2WurQsQfBmrSTzOPzXkHJZgMQWQ1Dc ( 1 XvCgOLZ5KjjHJZgMksvR7e8RJR4mqlNZjSa0w5CEufaIRdCBzisaaqdo2wGS7gikjHJZgMTyFF1IIlzhOjyqjKY ( qljHJZgMksvsTyJjITndnDxsipHJZgMQWkPwSXeX2MHMMfReooByQivTUtWVoUIZaTCoNSeooByQcRw3j4xhxXzGwoNtybO8xFVFeRpu0hRxo0aR3Y6fxN6jayG9RVZKsRxoX486jayG9RFDG7XrE9DMuA94Ksry9YJbzJOWGy9hSE5bbpVE5eghJfG2kNZJQaqCDGBldrcaaAWX2cKD3arjmrSH9X2gnWgndSFBDoFY5C2bAcgusAc0t1wmoVrZa7Rq32cK3LeiJJ0hKiQ4gKnIcdInqKBcXColwPjqpvCe882wyCmQq32cKtybybybO8l ) 1 hkayCXKiVEeic7xFoGy9PuSEBLhS ( jwVb0gHTfOQa0w5CEucFIqMazbOTY58yisaW68idi2anIZQau ( L ) 6 LHy98ZdoRNF1NsNy9PbjIz9XowGaJtS ( 8 Q3ceq0VE5yG ( 4 eRxgEmoVau ( L ) 6 TvoNhdrcaGyAqIy2mM8AwM2In2fJJTfxsy2tdseZ2qlbCCcMJBgAA1Mb6JtS15yCUcIG24r2hAjqghPpiruTzG ( 4 eBDogN3nnb6PIJGN32cJJrf62wG8cq5VEz4KspMSEcsQDX6LvkEW ( 1 FW6LhdYgrHbr2RxoHXX6LhZxy9DMuA9eadmM1lN4oE9hSElRhGcPEsinK67mP06LfAJO ( JUE5fZ4ewFAqIyglaTvoNhdrcaaAWX2cKD3arjBHXXg38fY ( qlHCiJJ0hKiQwsTl2sP4b73LCiJJ0hKiQ4gKnIcdInqKBcXCo7anbdkjnb6PIEGXSTf3XvOBBbYzXkgafIwAqIygvBHXXg38fgMmjKaqeW0eONQeAJOD0niZ4k0TTa5ewak ) 1 ldNuA9eKu7I1lRu8G9zVE5eghRxEmFH13rk61NsX63m001pX65xhN967mP06jagymRxoXD86TSEsdPEschs9DMuA9YcTru ) rxV8IzCcR ) G13zsP1hkIr0xy9YbrJT6TSEcmK6jbGcP ( otkTEzH2iQ ) ORxEXmoH1NgKiMXcqBLZ5XqKaaGgCSTaz3nquYwyCSXnFHSp0sGmosFqIOAj1UylLIhSp7anbdkzZqtRwsTl2sP4b7R4xhNfR0eONk6bgZ2wChxHUTfiVBmakeT0GeXmQ2cJJnU5lmmzsiHucyAc0tvcTr0o6gKzCf62wGCczXI80eONQv ) LaBhDtQLqKRq32cK3ngafIwAqIygvBHXXg38fgMmjKqGeW0eONQeAJOD0niZ4k0TTa5ewak ) 1 ldNuA9YJbzJOWGi71lNW4y9YJ5lSElR3piOjQpnirmRFDmEwFhPOx ) MHMg51V7xVvFexNZny ) 6 rAACLSx ) bR3eDS ( X6TSEcu2qQN ( G17NtaLhe88zvaARCopgIeaa0GJTfi7UbIs2cJJnU5lK9HwcKXr6dsevCdYgrHbXgiYnHyoNDGMGbLKMa9urpWy22I74k0TTa5SyrYMHMwbIPbEWasV4evmbyXknb6PkH2iAhDdYmUcDBlqolwCCZqtRWye9f22q0ytXeGWUXaOq0sdseZOAlmo24MVWWKjHeaIaMMa9uLqBeTJUbzgxHUTfiNqwSipnb6PIJGNplf62wG8UXaOq0sdseZOAlmo24MVWWKjHalaL ) 679 Jy9HIye9fwVCq0yR ( nsFqSE5eghRxEmFH1p01pz9tSEdOncBlW6nNx ) rtx ) 6 ob ) 64 fG2kNZJHibaan4yBbYUBGOKTW4yJB ( cz ) cibIrmzFOLKMa9uHXi6lSTHOXMcDBlqE31Dc ( 1 XvymI ( cBBiASPGOX7xaARCopgIeaa0GJTfi7UbIscCNyCIn6d2aX0yhOjyqjKNMa9uXrWZNLcDBlqE31Dc ( 1 XvGyAGhmG0lorfebTXJHU36sZa7R4i9SMKmaQNcqBLZ5XqKaaGgCSTaz3nqusG7eJtSrFW2wyCSXnFHSd0emOeGgCSTavBHXXg38f2LeAgy ) qhQYKaMMa9urpWy22I74k0TTa5YGK2dHfG2kNZJHibaan4yBbYUBGOKa3jgNyJ ( GnSp22ObYoqtWGsstGEQ4i45ZsHUTfiVl5PjqpvBX48gndSVcDBlqE31Dc ( 1 XvyFSTrdubrqB8yOjH4IRanawgKuc7sZa7R4i9SMKms7Pa0w5CEmejaaObhBlq2DdeL0XMCCIn6d2apq0tgq2bAcgusAc0tf4bIEYaQq32cK3L8ndnTc8arpzavmbkaTvoNhdrcawMq0SvoN3etmz3nquY6ob ) 64 fG2kNZJHibaPu41PruydqK9HwYMHMwrJI2 ( a3gKdIEQIPTytIm7sYMHMwnGGNWY58MXanftawSiFZqtRaX0apyaPxCIkMaewaARCopgIeaaz8MTY58MyIj7UbIs4i45ZI9ycNvkjm7dTK0eONkocE ( SuOBBbYlaTvoNhdrcaGmEZw5CEtmXKD3arj ( bbnrbybOTY58OADNGFDCjGyAGhmG0lor2hAjKNMa9uXrWZNLcDBlqE31Dc ( 1 XvyFSTrdubrqB8izK2txsiFDar38ube9uAFOcDBlqolwKZVufhNMr02qZ5QCwSnorczXIEiknBqe0gpgAsLzbOTY58OADNGFD8qKaaqmnWdgq6fNi7dTK0eONkocE ( SuOBBbY7sY6ob ) 64 kSp22ObQGiOnEKms7PljKd0GJTfOAlmo24MVqwSw3j4xhxTfghBCZxOcIG24rYiU4kqdGjKWUKq ( 6 aIU5Pci6P0 ( qf62wGCwSiNFPkoonJOTHMZv5SyBCIeYIf9quA2GiOnEm0KkZcqBLZ5r16ob ) 64 HibabUCoN9HwYMHMwbIPbEWasV4evqe0gpsgPYKfR9fJDPhIsZgebTXJHU36Pau ( RxEqAJrK1ZeX6NebRxCeNvbOTY58OADNGFD8qKaaMi2MebJShfxgLKWXzdZWSp0saAWX2cuLWXzdZwSVVArXLsc3LKndnTcetd8GbKEXjQycWIfjKNMa9uXrWZNLcDBlqE31Dc ( 1 XvGyAGhmG0lorfebTXJKrc9quA2GiOnEKmcqjCC2WufwTUt
end