You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1412 lines
46 KiB

4 years ago
-- 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 ) / state.haste ) * state.haste
4 years ago
end,
interval = function () return state.haste end,
4 years ago
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( {
4 years ago
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,
4 years ago
duration = function () return 30 + ( pvptalent.demonic_origins.enabled and -15 or 0 ) + ( set_bonus.tier28_4pc > 0 and 6 or 0 ) end,
4 years ago
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,
},
4 years ago
-- 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 )
4 years ago
local furySpent = 0
local FURY = Enum.PowerType.Fury
local lastFury = -1
spec:RegisterUnitEvent( "UNIT_POWER_FREQUENT", "player", nil, function( event, unit, powerType )
if powerType == "FURY" then
local current = UnitPower( "player", FURY )
if current < lastFury then
furySpent = ( furySpent + lastFury - current ) % 60
end
lastFury = current
end
end )
spec:RegisterStateExpr( "fury_spent", function ()
return furySpent
end )
spec:RegisterHook( "spend", function( amt, resource )
if set_bonus.tier28_4pc > 0 and resource == "fury" then
fury_spent = fury_spent + amt
if fury_spent > 60 then
cooldown.metamorphosis.expires = cooldown.metamorphosis.expires - floor( fury_spent / 60 )
fury_spent = fury_spent % 60
end
end
end )
4 years ago
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 )
4 years ago
fury_spent = nil
4 years ago
end )
4 years ago
4 years ago
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 )
4 years ago
-- Tier 28
spec:RegisterGear( "tier28", 188898, 188896, 188894, 188893, 188892 )
spec:RegisterSetBonuses( "tier28_2pc", 364438, "tier28_4pc", 363736 )
4 years ago
-- 2-Set - Deadly Dance - Increases Death Sweep and Annihilation / Blade Dance and Chaos Strike damage by 20%.
-- 4-Set - Deadly Dance - Metamorphosis duration is increased by 6 sec. Every 60 Fury you consume reduces the cooldown of Metamorphosis by 1 sec.
4 years ago
-- 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
4 years ago
} )
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.\nSee /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,
},
4 years ago
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,
3 years ago
copy = "blade_dance1"
4 years ago
},
4 years ago
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,
},
4 years ago
chaos_nova = {
id = 179057,
cast = 0,
cooldown = function () return talent.unleashed_power.enabled and 40 or 60 end,
gcd = "spell",
4 years ago
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,
},
4 years ago
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
}
}
},
4 years ago
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,
},
4 years ago
darkness = {
id = 196718,
cast = 0,
cooldown = 180,
gcd = "spell",
toggle = "defensives",
startsCombat = false,
texture = 1305154,
handler = function ()
last_darkness = query_time
applyBuff( "darkness" )
end,
},
4 years ago
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,
},
4 years ago
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,
},
4 years ago
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,
},
4 years ago
essence_break = {
id = 258860,
cast = 0,
cooldown = 20,
gcd = "spell",
4 years ago
startsCombat = true,
texture = 136189,
4 years ago
handler = function ()
applyDebuff( "target", "essence_break" )
active_dot.essence_break = max( 1, active_enemies )
end,
copy = "dark_slash"
},
4 years ago
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
4 years ago
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,
4 years ago
finish = function ()
if level > 58 then applyBuff( "furious_gaze" ) end
end,
},
4 years ago
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,
},
4 years ago
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,
},
4 years ago
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,
readyTime = function ()
if prev_gcd[1].fel_rush then
return 3600
end
if settings.recommend_movement then return 0 end
if buff.unbound_chaos.up and settings.unbound_movement then return 0 end
return 3600
4 years ago
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
}
}
},
4 years ago
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,
4 years ago
handler = function ()
setDistance( 5 )
end,
},
4 years ago
fel_lance = {
id = 206966,
cast = 1,
cooldown = 0,
gcd = "spell",
pvptalent = "rain_from_above",
buff = "rain_from_above",
startsCombat = true,
},
4 years ago
glaive_tempest = {
id = 342817,
cast = 0,
cooldown = 20,
hasteCD = true,
gcd = "spell",
4 years ago
spend = 30,
spendType = "fury",
4 years ago
startsCombat = true,
texture = 1455916,
4 years ago
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,
},
4 years ago
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
}
}
},
4 years ago
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
4 years ago
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
4 years ago
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
}
},
4 years ago
nemesis = {
id = 206491,
cast = 0,
cooldown = 120,
gcd = "spell",
toggle = "cooldowns",
startsCombat = true,
texture = 236299,
talent = "nemesis",
handler = function ()
applyDebuff( "target", "nemesis" )
end,
},
4 years ago
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,
},
4 years ago
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,
},
4 years ago
spectral_sight = {
id = 188501,
cast = 0,
cooldown = 60,
gcd = "spell",
4 years ago
toggle = "cooldowns",
startsCombat = true,
texture = 1247266,
4 years ago
handler = function ()
end,
},
4 years ago
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
}
}
},
4 years ago
vengeful_retreat = {
id = 198793,
cast = 0,
cooldown = function () return talent.momentum.enabled and 20 or 25 end,
gcd = "spell",
startsCombat = true,
texture = 1348401,
readyTime = function ()
if settings.recommend_movement then return 0 end
return 3600
4 years ago
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,
},
}
},
4 years ago
-- 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,
},
4 years ago
}
}, ]]
-- Demon Hunter - Night Fae - 323639 - the_hunt (The Hunt)
the_hunt = {
id = 323639,
cast = 1,
cooldown = 180,
gcd = "spell",
4 years ago
toggle = "essences",
startsCombat = true,
texture = 3636838,
4 years ago
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( "unbound_movement", false, {
name = "Recommend Movement for Unbound Chaos",
desc = "When Recommend Movement is disabled, you can enable this option to override it and allow |T1247261:0|t Fel Rush to be recommended when Unbound Chaos is active.",
type = "toggle",
width = "full",
disabled = function() return state.settings.recommend_movement end,
} )
4 years ago
spec:RegisterSetting( "demon_blades_head", nil, {
name = "Demon Blades",
type = "header",
4 years ago
} )
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",
arg = function() return false end,
4 years ago
} )
3 years ago
spec:RegisterPack( "Havoc", 20220821, [[Hekili:v31)ZTTTs()w8RZtrk1vvI2YjTJLFttAETntVC38CVj3pjkirilEHIuh)ID8nE0F73UaGGaqaGuY2j5MoJRnbXI974ZUGKz24z)1SRJiL0zFiyuqWOxhmE44xF2pD(RMDD59BPZUElz5Ni3a)skzd8ZFNCB2s8Q3NKrIWzxKvLVeg564nvjKY4S03Mtwvo76fvXjL)r6Sf2xHjWu3sxo7dtEfSyRJJIO87LwalWVs3KLUB(VxLwsZH)pUS7E)VuDtvr5U5bJpf(bqUDVF37F7As6n0IFE37)HDZ)3OLKnz5BxNvexSBojnA38)JmKR2nVQaeKDZ)BlORYYHFzv8nRbIrtJk(B7MNKDt8sygr)3WsqHPvMb)12Tj3VBEwk(t8clYkkeZSyiBf)ZSScks9T7MxCF6Y40BGjSApwP)M4u(aI1nNUHeNcJClqP5L5XPFIcx(T)kmePCnk2LGOTB(gYNhme055zRItan939D7MBx)GJyvhHd0ONW)6lVUsSQFH0xOutwIctXWT50LzBwqkNUiRSmHgfUkHCpn6oyTdlZ(mSq7FVF)0F8wsEmzrc9u03FQyfdrMoSijR80Bjjv0PJpnEv9GdhpCnPiSQGgUOA1QE9pPEGaTbE4HMjSmlljk7U0Hrv5S4NRM2mP9gCWJHvduz1axS6yhSQfU5kpIbWPGf))Sa8EE39WpEdLSb8skr3N72n)FwLd(j3fxUggkjgD(4xIKKHUe8rOXCl7VsY)0nje0vmlx6()MecKUa8LstOOVwvbZB6xUjlfi0Vr(FPDrBHsk9EqAbgmCfWdHlZsJIXPj0BLKeAA5WfiBYUJH0uC(r96NxLIHi3qhgvZIHBOrKKey6GUJpZiKFdxWyx5CpPzUeKJdVbyyh23vGaUEjMyfnHqo3KfaVmCle)vLaSFE12s2ckh62mmBmmwrwYTapyNUK8LKukeeKNZUhEy67(mDzflWMElfTjLXBOy4f8dGkOfGLX4wsCckldLeFAuCbYlYlaRbOnlQ2aQfcM1GTaFeiuuw6lkX)hsyKCLeqvaxP4oivcZqQKw5nv5PSR9XSkWxHrLMLiNYNCiPQmlKuwc7ADkyTOHlJGauXGGMdsQ8Zru0VE4cofdVdj4qr2fu72yw0ULEESLmx9pc(QzvLSmTzG88xRPzOYlt1)9uHxlEP0L0A)8)zCoM0(njzzr8zGbkN99qEWGVV(M(RCqFZZj(VQIHamHkRqvBR7BZyZWiCPqrtXLBjYKHLmEu1v0IBSEuWkKvb5h40AXhC72stscfSZqLvD8vt7F2piMAjkaHzRcZb2VEYdKkpdn3(QQ14ghmVq0cYDcXCoNAxnIQqu71FShviQR5J9UcyJjCDEtoL8j(0phN(zpHwa7gaHgM5xQE9HO0jZIyrZ3ZRIpWVI)Hhorm(Y7xczkGXxtkZPDK6N3zZQBVFuhNMLVHK0e)VeI2kRT2OkbteTa3zaYnqXCZemSIcdSS8ur0sYDK7le2S)cSxRWRMML(dSTkW8ohSb64Ie6ZmIBubZmSAR0gAvx9WdICsuUly4c0deM2a)wGwcSASVrCLqNSRNRSVTrernAqDBymgjwASLGapzggMwdnOB2GSTtZPfu2gDc2xxTuleseh6dd)i6EfNpv0aCM6TO3opk(3z(7NImEwCKebHJ8oOSZ2PctbTfG3gViojUuG3L(5sksEed6VK9UDZVooDvvcQ9WLTtcVMdydQGE2JtfUJ1Kt1q2dxTBH)iRCybJpa1dWgxg4Mr2ckuC7oy1drhyb5D5ej1)6o7IDsV8IEmKsr0vXlJlV6SrDBHv1gEeV(iXV8vt(b3XIVmy0GUTM1O)0dVnL3tCddSXvuqjPwO)nlJgcvK8YGb66JGr29rrFXYs6gadfZRcXWRJGg9XKHu1vQXY3bRdufoCp1yWpTbBmdpbKz0Pc5oca5vOqA88C5rw7By6FnSmE5NaY0Os0gTwTuRvohQ7WHFeM0u4ettPBIPfthBMpSwDF50Z6MGTjBdycRmS01xTXuZtIxFzOwvv8SWEbH8)mmjUOKVknj50HMUf0hHvBdxLtUbj3PyFvMY8TqDlhnjIAxEhfxnQvISjlIonLcBovWsu2x3NneqntlJlPsjsZ3B6ztE4bfyUChAqnTUhhACZfyBcPyJuCWH0Sp8alm8m9aTY15z3fcBDc2oK5y0Cff8bWYoYJqjyybIrF6KE89lJ3SjJ39iacFoHz8pX6oPAReid7Bje6GtlGItxwkQp3AiDRKsan59Sq13sqSLgTPa387ogm(eitpd)catbC4t0cAZPRat1AoyfCoSTqGDTYeDWHT5zYMmCjYGIUAkxRw1pvttWqZ7irvFNPJGSoGjd7NsyDKyWKb7VwG(yVv7ywmWZXw27hEqojLRkNNi5WGUYQBznTs6PzD7ORcaxESJu90P5fJSssSNaq4ZgrgKCY2cCBxAca5mhmsGR6YqyDbnsm6G0kjYXmqafwMLKaeJLpQQScCkK8nlPplgqa7xNtpRlC6sYY1macKL)pvXaeHqaNaPqBDKdr(mfcO61VVrAwOWw(u5zz7bGlJcPytegsIIkggNE1fJmtoFLXSGSg63WLNPy23BFsyVAR2hMnN1WZvKQKsC)oeegiW1TH0Msr0wkwOV0bCVUInDCpxO177k2IXI(r(CvFDr4F4Pjz)9Gb2L7PmfsFpmFqVtS0zowAze5V7z6tJf0Igl4lRgZslhFeASX9oXIPOtASVdBkbMJUynSvDKWnKGG2Y4DOKcbvB3Yl9POe0ra2limhRFyrgIXt2XAKIy2ESAcscVCfyVE(wbrmOCd9gQxyDuvCwSDhCcnRV1opc6o3HNtHCYmmea2HrdgCGO2S7XbjQwdISVDYASj2aXPmSzPlGhcd0rvECwvbt(urXPYh0K7lIjPHr0L5ugEL((ZSbqN2pHOkeivQ7OXTMDNvG408YGcAdjfQmfy(tJrKcyZvdb0s0Oysj7WhKx9MKSfKeTl5BjvpHeHEFQSqix1HEmQMazrAgLV(YXJg0ZPx6EdO6lUhRJQAaHzEvXAfWkvPlWw3gY6PwtgjuvRpeUni8BGqumnaIeueJnaCmgIvqugpY2MHGymWgdfrjLRdlUJs3QLwvbZJTPXbohIWbeO7pcL(4r2iTjYCSzAvXGEg8xa3PiXqDOU2l6zhEEVtQBL1N3MvauK3ED1yVg2r1D7iKrFowQip9CapgDU(QXIkAEf4zAp5ttWGnjYOxowBDHRuNSDc8HNEIUJzTAOEcwCnr4twDnnQ3ILd2rHy2MojnnEDm)(yZ1AI4w8ZH4v2DGeqV80ZT68Q1MpB3aVZ5yzFFI2jUYXgi1k(oMKX(H75OI5NL0mWVveUaGgCkpqq4nZl911Xz57yWU882K9t8j8gXupVYCxYZXK0SQswlYXhdch(1QsOK5IIH69aVLRgpraROducKIBO4Ex5uScSsxuSlCV3dESHa8Mv88Sh(4jp(DQ58NdDJRoXX03BZPBj45sXsZHhg9vJTqxvRxFRBY)Wd(buklIXkWbOgbzuTzEsEvedEYC11eQfey75BOh52KQnoqs2dcBICwh12gYzVpWMwW3FuEQJSPf)Ma4JKBudrFoubt(cG(XMwUdOFS7H3bCankp7WaKJBInPVN0NQv9Bt9Z1h1m0LNnsSbG9t8AYahak8l)MWwEszyxSekbhf3Q676(aX8btTnplRzREwH4yBDAz)LtCTHLJC(ITfWkt8UDU3OJJbsIvU3oH6BJs9CjP2saC4OECMH2JwA213sZlGPx)mfp6NMD9DeMrUy21F8x(xF4p(WV9Z7MZEsI2npEZ2S8sXzK(c(k(c8mz49bF38Im8XBdF2X2qyTGBj)zLD4U3)NXPWqJbI92Suyzzd)IghU)RxWpMw1lvZNVaF0JyplQcQCXJKm7EFlYweVl5hMWD2JKREKubpy639V)NgK78NwYn5PLCVYGCcNvjTQ)7dMqDMV0DSoA)ttUQvpm5dp6H5JfyQWK9HVrNjUuj)A9dueqxtpWY0d2F6M(Mh4Q7A6DC1pAxz
4 years ago
end