-- ShamanElemental.lua
-- 09.2020
local addon , ns = ...
local Hekili = _G [ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
-- Conduits
-- [x] Call of Flame
-- [-] High Voltage
-- [-] Pyroclastic Shock
-- [-] Shake the Foundations
-- Covenants
-- [-] Elysian Dirge
-- [-] Lavish Harvest
-- [-] Tumbling Waves
-- [x] Essential Extraction
-- Endurance
-- [-] Astral Protection
-- [-] Refreshing Waters
-- [x] Vital Accretion
-- Finesse
-- [x] Crippling Hex
-- [x] Spiritual Resonance
-- [x] Thunderous Paws
-- [x] Totemic Surge
if UnitClassBase ( " player " ) == " SHAMAN " then
local spec = Hekili : NewSpecialization ( 262 , true )
spec : RegisterResource ( Enum.PowerType . Maelstrom )
spec : RegisterResource ( Enum.PowerType . Mana )
-- Talents
spec : RegisterTalents ( {
earthen_rage = 22356 , -- 170374
echo_of_the_elements = 22357 , -- 333919
static_discharge = 22358 , -- 342243
aftershock = 23108 , -- 273221
echoing_shock = 23460 , -- 320125
elemental_blast = 23190 , -- 117014
spirit_wolf = 23162 , -- 260878
earth_shield = 23163 , -- 974
static_charge = 23164 , -- 265046
master_of_the_elements = 19271 , -- 16166
storm_elemental = 19272 , -- 192249
liquid_magma_totem = 19273 , -- 192222
natures_guardian = 22144 , -- 30884
ancestral_guidance = 22172 , -- 108281
wind_rush_totem = 21966 , -- 192077
surge_of_power = 22145 , -- 262303
primal_elementalist = 19266 , -- 117013
icefury = 23111 , -- 210714
unlimited_power = 21198 , -- 260895
stormkeeper = 22153 , -- 191634
ascendance = 21675 , -- 114050
} )
-- PvP Talents
spec : RegisterPvpTalents ( {
control_of_lava = 728 , -- 204393
counterstrike_totem = 3490 , -- 204331
grounding_totem = 3620 , -- 204336
lightning_lasso = 731 , -- 305483
seasoned_winds = 5415 , -- 355630
skyfury_totem = 3488 , -- 204330
spectral_recovery = 3062 , -- 204261
static_field_totem = 727 , -- 355580
swelling_waves = 3621 , -- 204264
traveling_storms = 730 , -- 204403
unleash_shield = 3491 , -- 356736
} )
-- Auras
spec : RegisterAuras ( {
ancestral_guidance = {
id = 108281 ,
duration = 10 ,
max_stack = 1 ,
} ,
ascendance = {
id = 114050 ,
duration = 15 ,
max_stack = 1 ,
} ,
astral_shift = {
id = 108271 ,
duration = function ( ) return level > 53 and 12 or 8 end ,
max_stack = 1 ,
} ,
celestial_guidance = {
id = 324748 ,
duration = 10 ,
max_stack = 1 ,
} ,
earth_shield = {
id = 974 ,
duration = 600 ,
type = " Magic " ,
max_stack = 9 ,
} ,
earthbind = {
id = 3600 ,
duration = 5 ,
type = " Magic " ,
max_stack = 1 ,
} ,
-- might be the debuff on targets
earthquake = {
id = 61882 ,
duration = 3600 ,
max_stack = 1 ,
} ,
echoing_shock = {
id = 320125 ,
duration = 8 ,
max_stack = 1 ,
} ,
elemental_blast = {
duration = 10 ,
type = " Magic " ,
max_stack = 3 ,
generate = function ( )
local eb = buff.elemental_blast
local count = ( buff.elemental_blast_critical_strike . up and 1 or 0 ) +
( buff.elemental_blast_haste . up and 1 or 0 ) +
( buff.elemental_blast_mastery . up and 1 or 0 )
local applied = max ( buff.elemental_blast_critical_strike . applied ,
buff.elemental_blast_haste . applied ,
buff.elemental_blast_mastery . applied )
eb.name = class.abilities . elemental_blast.name or " Elemental Blast "
eb.count = count
eb.applied = applied
eb.expires = applied + 15
eb.caster = count > 0 and " player " or " nobody "
end
} ,
elemental_blast_critical_strike = {
id = 118522 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
elemental_blast_haste = {
id = 173183 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
elemental_blast_mastery = {
id = 173184 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
elemental_fury = {
id = 60188 ,
} ,
far_sight = {
id = 6196 ,
duration = 60 ,
max_stack = 1 ,
} ,
flame_shock = {
id = 188389 ,
duration = function ( ) return level > 58 and ( fire_elemental.up or storm_elemental.up ) and 36 or 18 end ,
tick_time = function ( ) return 3 * haste end ,
type = " Magic " ,
max_stack = 1 ,
} ,
fleshcraft = {
id = 324631 ,
duration = 120 ,
max_stack = 1 ,
} ,
frost_shock = {
id = 196840 ,
duration = 6 ,
type = " Magic " ,
max_stack = 1 ,
} ,
ghost_wolf = {
id = 2645 ,
duration = 3600 ,
type = " Magic " ,
max_stack = 1 ,
} ,
icefury = {
id = 210714 ,
duration = 15 ,
max_stack = 4 ,
} ,
lava_surge = {
id = 77762 ,
duration = 10 ,
max_stack = 1 ,
} ,
lightning_lasso = {
id = 305484 ,
duration = 5 ,
max_stack = 1
} ,
lightning_shield = {
id = 192106 ,
duration = 1800 ,
type = " Magic " ,
max_stack = 1 ,
} ,
master_of_the_elements = {
id = 260734 ,
duration = 15 ,
type = " Magic " ,
max_stack = 1 ,
} ,
primordial_wave = {
id = 327164 ,
duration = 15 ,
max_stack = 1 ,
} ,
reincarnation = {
id = 20608 ,
} ,
spirit_wolf = {
id = 260881 ,
duration = 3600 ,
max_stack = 4 ,
} ,
spiritwalkers_grace = {
id = 79206 ,
duration = 15 ,
type = " Magic " ,
max_stack = 1 ,
} ,
static_discharge = {
id = 342243 ,
duration = 3 ,
max_stack = 1 ,
} ,
stormkeeper = {
id = 191634 ,
duration = 15 ,
max_stack = 2 ,
} ,
surge_of_power = {
id = 285514 ,
duration = 15 ,
max_stack = 1 ,
} ,
surge_of_power_debuff = {
id = 285515 ,
duration = 6 ,
max_stack = 1 ,
} ,
thunderstorm = {
id = 51490 ,
duration = 5 ,
max_stack = 1 ,
} ,
unlimited_power = {
id = 272737 ,
duration = 10 ,
max_stack = 20 , -- good luck reaching this...
} ,
water_walking = {
id = 546 ,
duration = 600 ,
max_stack = 1 ,
} ,
wind_rush = {
id = 192082 ,
duration = 5 ,
max_stack = 1 ,
} ,
wind_gust = {
id = 263806 ,
duration = 30 ,
max_stack = 20
} ,
-- Pet aura.
call_lightning = {
duration = 15 ,
generate = function ( t , db )
if storm_elemental.up then
local name , _ , count , _ , duration , expires = FindUnitBuffByID ( " pet " , 157348 )
if name then
t.count = count
t.expires = expires
t.applied = expires - duration
t.caster = " pet "
return
end
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = " nobody "
end ,
} ,
-- Legendaries
-- TODO: Implement like Bloodtalons, but APL doesn't really require it mechanically.
elemental_equilibrium = {
id = 347348 ,
duration = 10 ,
max_stack = 1
} ,
elemental_equilibrium_debuff = {
id = 347349 ,
duration = 30 ,
max_stack = 1
}
} )
-- Pets
spec : RegisterPet ( " primal_storm_elemental " , 77942 , " storm_elemental " , 30 )
spec : RegisterTotem ( " greater_storm_elemental " , 1020304 ) -- Texture ID
spec : RegisterPet ( " primal_fire_elemental " , 61029 , " fire_elemental " , 30 )
spec : RegisterTotem ( " greater_fire_elemental " , 135790 ) -- Texture ID
spec : RegisterPet ( " primal_earth_elemental " , 61056 , " earth_elemental " , 60 )
spec : RegisterTotem ( " greater_earth_elemental " , 136024 ) -- Texture ID
spec : RegisterTotem ( " liquid_magma_totem " , 971079 )
spec : RegisterTotem ( " tremor_totem " , 136108 )
spec : RegisterTotem ( " vesper_totem " , 3565451 )
spec : RegisterTotem ( " wind_rush_totem " , 538576 )
spec : RegisterStateTable ( " fire_elemental " , setmetatable ( { onReset = function ( self ) self.cast_time = nil end } , {
__index = function ( t , k )
if k == " cast_time " then
t.cast_time = class.abilities . fire_elemental.lastCast or 0
return t.cast_time
end
local elem = talent.primal_elementalist . enabled and pet.primal_fire_elemental or pet.greater_fire_elemental
if k == " active " or k == " up " then
return elem.up
elseif k == " down " then
return not elem.up
elseif k == " remains " then
return max ( 0 , elem.remains )
end
return false
end
} ) )
spec : RegisterStateTable ( " storm_elemental " , setmetatable ( { onReset = function ( self ) self.cast_time = nil end } , {
__index = function ( t , k )
if k == " cast_time " then
t.cast_time = class.abilities . storm_elemental.lastCast or 0
return t.cast_time
end
local elem = talent.primal_elementalist . enabled and pet.primal_storm_elemental or pet.greater_storm_elemental
if k == " active " or k == " up " then
return elem.up
elseif k == " down " then
return not elem.up
elseif k == " remains " then
return max ( 0 , elem.remains )
end
return false
end
} ) )
spec : RegisterStateTable ( " earth_elemental " , setmetatable ( { onReset = function ( self ) self.cast_time = nil end } , {
__index = function ( t , k )
if k == " cast_time " then
t.cast_time = class.abilities . earth_elemental.lastCast or 0
return t.cast_time
end
local elem = talent.primal_elementalist . enabled and pet.primal_earth_elemental or pet.greater_earth_elemental
if k == " active " or k == " up " then
return elem.up
elseif k == " down " then
return not elem.up
elseif k == " remains " then
return max ( 0 , elem.remains )
end
return false
end
} ) )
spec : RegisterHook ( " reset_precast " , function ( )
if talent.master_of_the_elements . enabled and action.lava_burst . in_flight and buff.master_of_the_elements . down then
applyBuff ( " master_of_the_elements " )
end
rawset ( state.pet , " earth_elemental " , talent.primal_elementalist . enabled and state.pet . primal_earth_elemental or state.pet . greater_earth_elemental )
rawset ( state.pet , " fire_elemental " , talent.primal_elementalist . enabled and state.pet . primal_fire_elemental or state.pet . greater_fire_elemental )
rawset ( state.pet , " storm_elemental " , talent.primal_elementalist . enabled and state.pet . primal_storm_elemental or state.pet . greater_storm_elemental )
end )
-- Abilities
spec : RegisterAbilities ( {
ancestral_guidance = {
id = 108281 ,
cast = 0 ,
cooldown = 120 ,
gcd = " off " ,
talent = " ancestral_guidance " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 538564 ,
handler = function ( )
applyBuff ( " ancestral_guidance " )
end ,
} ,
ancestral_spirit = {
id = 2008 ,
cast = 10 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.04 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136077 ,
handler = function ( )
end ,
} ,
ascendance = {
id = 114050 ,
cast = 0 ,
cooldown = 180 ,
gcd = " spell " ,
talent = " ascendance " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 135791 ,
handler = function ( )
applyBuff ( " ascendance " )
gainCharges ( " lava_burst " , 2 )
end ,
} ,
astral_recall = {
id = 556 ,
cast = function ( ) return 10 * haste end ,
cooldown = 600 ,
gcd = " spell " ,
startsCombat = false ,
texture = 136010 ,
handler = function ( )
end ,
} ,
astral_shift = {
id = 108271 ,
cast = 0 ,
cooldown = 90 ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 538565 ,
handler = function ( )
applyBuff ( " astral_shift " )
end ,
} ,
bloodlust = {
id = 2825 ,
cast = 0 ,
cooldown = 300 ,
gcd = " spell " ,
spend = 0.22 ,
spendType = " mana " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 136012 ,
handler = function ( )
applyBuff ( " bloodlust " )
applyDebuff ( " player " , " sated " )
if conduit.spiritual_resonance . enabled then
applyBuff ( " spiritwalkers_grace " , conduit.spiritual_resonance . mod * 0.001 )
end
end ,
} ,
capacitor_totem = {
id = 192058 ,
cast = 0 ,
cooldown = function ( ) return 60 + ( conduit.totemic_surge . mod * 0.001 ) end ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136013 ,
handler = function ( )
end ,
} ,
--[[ chain_harvest = {
id = 320674 ,
cast = function ( ) return 2.5 * haste end ,
cooldown = 90 ,
gcd = " spell " ,
toggle = " covenant " ,
startsCombat = true ,
texture = 3565725 ,
handler = function ( )
end ,
} , ] ]
chain_heal = {
id = 1064 ,
cast = function ( )
if buff.chains_of_devastation_ch . up then return 0 end
return 2.5 * haste
end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.3 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136042 ,
handler = function ( )
removeBuff ( " chains_of_devastation_ch " )
removeBuff ( " echoing_shock " )
if legendary.chains_of_devastation . enabled then
applyBuff ( " chains_of_devastation_cl " )
end
end ,
} ,
chain_lightning = {
id = 188443 ,
cast = function ( ) return ( buff.stormkeeper . up or buff.chains_of_devastation_cl . up ) and 0 or ( 2 * haste ) end ,
cooldown = 0 ,
gcd = " spell " ,
nobuff = " ascendance " ,
bind = " lava_beam " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136015 ,
handler = function ( )
removeBuff ( " master_of_the_elements " )
removeBuff ( " echoing_shock " )
removeBuff ( " chains_of_devastation_cl " )
if legendary.chains_of_devastation . enabled then
applyBuff ( " chains_of_devastation_ch " )
end
-- 4 MS per target, direct.
-- 3 MS per target, overload.
gain ( ( buff.stormkeeper . up and 7 or 4 ) * min ( 5 , active_enemies ) , " maelstrom " )
removeStack ( " stormkeeper " )
if pet.storm_elemental . up then
addStack ( " wind_gust " , nil , 1 )
end
end ,
} ,
cleanse_spirit = {
id = 51886 ,
cast = 0 ,
cooldown = 8 ,
gcd = " spell " ,
spend = 0.06 ,
spendType = " mana " ,
startsCombat = false ,
texture = 236288 ,
handler = function ( )
end ,
} ,
earth_elemental = {
id = 198103 ,
cast = 0 ,
cooldown = 300 ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 136024 ,
handler = function ( )
summonPet ( talent.primal_elementalist . enabled and " primal_earth_elemental " or " greater_earth_elemental " , 60 )
if conduit.vital_accretion . enabled then
applyBuff ( " vital_accretion " )
health.max = health.max * ( 1 + ( conduit.vital_accretion . mod * 0.01 ) )
end
end ,
usable = function ( )
return max ( cooldown.fire_elemental . true_remains , cooldown.storm_elemental . true_remains ) > 0 , " DPS elementals must be on CD first "
end ,
timeToReady = function ( )
return max ( pet.fire_elemental . remains , pet.storm_elemental . remains , pet.primal_fire_elemental . remains , pet.primal_storm_elemental . remains )
end ,
auras = {
-- Conduit
vital_accretion = {
id = 337984 ,
duration = 60 ,
max_stack = 1
}
}
} ,
earth_shield = {
id = 974 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
talent = " earth_shield " ,
startsCombat = false ,
texture = 136089 ,
handler = function ( )
applyBuff ( " earth_shield " )
end ,
} ,
earth_shock = {
id = 8042 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 60 ,
spendType = " maelstrom " ,
startsCombat = true ,
texture = 136026 ,
handler = function ( )
if talent.surge_of_power . enabled then
applyBuff ( " surge_of_power " )
end
if runeforge.echoes_of_great_sundering . enabled then
applyBuff ( " echoes_of_great_sundering " )
end
removeBuff ( " echoing_shock " )
end ,
} ,
earthbind_totem = {
id = 2484 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136102 ,
handler = function ( )
end ,
} ,
earthquake = {
id = 61882 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 60 ,
spendType = " maelstrom " ,
startsCombat = true ,
texture = 451165 ,
handler = function ( )
removeBuff ( " echoes_of_great_sundering " )
removeBuff ( " master_of_the_elements " )
removeBuff ( " echoing_shock " )
end ,
auras = {
echoes_of_great_sundering = {
id = 336217 ,
duration = 25 ,
max_stack = 1
}
}
} ,
echoing_shock = {
id = 320125 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = true ,
texture = 1603013 ,
talent = " echoing_shock " ,
handler = function ( )
applyBuff ( " echoing_shock " )
end ,
} ,
elemental_blast = {
id = 117014 ,
cast = function ( ) return 2 * haste end ,
cooldown = 12 ,
gcd = " spell " ,
spend = - 30 ,
spendType = " maelstrom " ,
startsCombat = true ,
texture = 651244 ,
handler = function ( )
applyBuff ( " elemental_blast " )
if talent.surge_of_power . enabled then
applyBuff ( " surge_of_power " )
end
if runeforge.echoes_of_great_sundering . enabled then
applyBuff ( " echoes_of_great_sundering " )
end
removeBuff ( " master_of_the_elements " )
removeBuff ( " echoing_shock " )
end ,
} ,
far_sight = {
id = 6196 ,
cast = function ( ) return 2 * haste end ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = true ,
texture = 136034 ,
handler = function ( )
end ,
} ,
fire_elemental = {
id = 198067 ,
cast = 0 ,
charges = 1 ,
cooldown = 150 ,
recharge = 150 ,
gcd = " spell " ,
spend = 0.05 ,
spendType = " mana " ,
toggle = " cooldowns " ,
notalent = " storm_elemental " ,
startsCombat = false ,
texture = 135790 ,
timeToReady = function ( )
return max ( pet.earth_elemental . remains , pet.primal_earth_elemental . remains , pet.storm_elemental . remains , pet.primal_storm_elemental . remains )
end ,
handler = function ( )
summonPet ( talent.primal_elementalist . enabled and " primal_fire_elemental " or " greater_fire_elemental " , 30 * ( 1 + ( 0.01 * conduit.call_of_flame . mod ) ) )
end ,
} ,
flame_shock = {
id = 188389 ,
cast = 0 ,
cooldown = 6 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135813 ,
cycle = " flame_shock " ,
min_ttd = function ( ) return debuff.flame_shock . duration / 3 end ,
handler = function ( )
applyDebuff ( " target " , " flame_shock " )
if buff.surge_of_power . up then
active_dot.surge_of_power = min ( active_enemies , active_dot.flame_shock + 1 )
removeBuff ( " surge_of_power " )
end
removeBuff ( " echoing_shock " )
end ,
} ,
frost_shock = {
id = 196840 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135849 ,
handler = function ( )
removeBuff ( " master_of_the_elements " )
removeBuff ( " echoing_shock " )
applyDebuff ( " target " , " frost_shock " )
if buff.icefury . up then
gain ( 8 , " maelstrom " )
removeStack ( " icefury " , 1 )
end
if buff.surge_of_power . up then
applyDebuff ( " target " , " surge_of_power_debuff " )
removeBuff ( " surge_of_power " )
end
end ,
} ,
ghost_wolf = {
id = 2645 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 136095 ,
handler = function ( )
applyBuff ( " ghost_wolf " )
if talent.spirit_wolf . enabled then applyBuff ( " spirit_wolf " ) end
if conduit.thunderous_paws . enabled then applyBuff ( " thunderous_paws " ) end
end ,
} ,
healing_stream_totem = {
id = 5394 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.09 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135127 ,
handler = function ( )
end ,
} ,
healing_surge = {
id = 8004 ,
cast = function ( ) return 1.5 * haste end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.24 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136044 ,
handler = function ( )
removeBuff ( " echoing_shock " )
end ,
} ,
hex = {
id = 51514 ,
cast = function ( ) return 1.7 * haste end ,
cooldown = function ( ) return level > 55 and 20 or 30 end ,
gcd = " spell " ,
startsCombat = false ,
texture = 237579 ,
handler = function ( )
applyDebuff ( " target " , " hex " )
end ,
auras = {
-- Conduit
crippling_hex = {
id = 338055 ,
duration = 8 ,
max_stack = 1
}
}
} ,
icefury = {
id = 210714 ,
cast = 2 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135855 ,
talent = " icefury " ,
handler = function ( )
removeBuff ( " master_of_the_elements " )
removeBuff ( " echoing_shock " )
applyBuff ( " icefury " , 15 , 4 )
gain ( 25 , " maelstrom " )
end ,
} ,
lava_beam = {
id = 114074 ,
cast = function ( ) return 2 * haste end ,
cooldown = 0 ,
gcd = " spell " ,
buff = " ascendance " ,
bind = " chain_lightning " ,
startsCombat = true ,
texture = 236216 ,
handler = function ( )
removeBuff ( " echoing_shock " )
-- 4 MS per target, direct.
-- 3 MS per target, overload.
gain ( ( buff.stormkeeper . up and 7 or 4 ) * min ( 5 , active_enemies ) , " maelstrom " )
removeStack ( " stormkeeper " )
end ,
} ,
lava_burst = {
id = 51505 ,
cast = function ( ) return buff.lava_surge . up and 0 or ( 2 * haste ) end ,
charges = function ( ) return talent.echo_of_the_elements . enabled and 2 or nil end ,
cooldown = function ( ) return buff.ascendance . up and 0 or ( 8 * haste ) end ,
recharge = function ( ) return buff.ascendance . up and 0 or ( 8 * haste ) end ,
gcd = " spell " ,
spend = 0.06 ,
spendType = " mana " ,
startsCombat = true ,
texture = 237582 ,
velocity = 30 ,
handler = function ( )
removeBuff ( " lava_surge " )
removeBuff ( " echoing_shock " )
gain ( 10 , " maelstrom " )
if talent.master_of_the_elements . enabled then applyBuff ( " master_of_the_elements " ) end
if talent.surge_of_power . enabled then
gainChargeTime ( " fire_elemental " , 6 )
removeBuff ( " surge_of_power " )
end
if buff.primordial_wave . up and state.spec . elemental and legendary.splintered_elements . enabled then
applyBuff ( " splintered_elements " , nil , active_dot.flame_shock )
end
removeBuff ( " primordial_wave " )
end ,
impact = function ( ) end , -- This + velocity makes action.lava_burst.in_flight work in APL logic.
} ,
lightning_bolt = {
id = 188196 ,
cast = function ( ) return buff.stormkeeper . up and 0 or ( 2 * haste ) end ,
cooldown = 0 ,
gcd = " spell " ,
essential = true ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136048 ,
handler = function ( )
removeBuff ( " echoing_shock " )
gain ( ( buff.stormkeeper . up and 11 or 8 ) + ( buff.surge_of_power . up and 3 or 0 ) , " maelstrom " )
removeBuff ( " master_of_the_elements " )
removeBuff ( " surge_of_power " )
removeStack ( " stormkeeper " )
if pet.storm_elemental . up then
addStack ( " wind_gust " , nil , 1 )
end
end ,
} ,
lightning_lasso = {
id = 305483 ,
cast = function ( ) return 5 * haste end ,
channeled = true ,
cooldown = 30 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1385911 ,
pvptalent = function ( )
if essence.conflict_and_strife . major then return end
return " lightning_lasso "
end ,
start = function ( )
removeBuff ( " echoing_shock " )
applyDebuff ( " target " , " lightning_lasso " )
end ,
copy = 305485
} ,
lightning_shield = {
id = 192106 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136051 ,
readyTime = function ( ) return buff.lightning_shield . remains - 120 end ,
handler = function ( )
applyBuff ( " lightning_shield " )
end ,
} ,
liquid_magma_totem = {
id = 192222 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 971079 ,
talent = " liquid_magma_totem " ,
handler = function ( )
summonTotem ( " liquid_magma_totem " )
end ,
} ,
primal_strike = {
id = 73899 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.09 ,
spendType = " mana " ,
startsCombat = true ,
texture = 460956 ,
handler = function ( )
end ,
} ,
purge = {
id = 370 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136075 ,
toggle = " interrupts " ,
interrupt = true ,
buff = " dispellable_magic " ,
handler = function ( )
removeBuff ( " dispellable_magic " )
end ,
} ,
spiritwalkers_grace = {
id = 79206 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
spend = 0.14 ,
spendType = " mana " ,
startsCombat = true ,
texture = 451170 ,
handler = function ( )
applyBuff ( " spiritwalkers_grace " )
end ,
} ,
static_discharge = {
id = 342243 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = off ,
texture = 135845 ,
talent = " static_discharge " ,
buff = " lightning_shield " ,
handler = function ( )
applyBuff ( " static_discharge " )
end ,
} ,
storm_elemental = {
id = 192249 ,
cast = 0 ,
charges = 1 ,
cooldown = 150 ,
recharge = 150 ,
gcd = " spell " ,
toggle = " cooldowns " ,
talent = " storm_elemental " ,
startsCombat = true ,
texture = 2065626 ,
timeToReady = function ( )
return max ( pet.earth_elemental . remains , pet.primal_earth_elemental . remains , pet.fire_elemental . remains , pet.primal_fire_elemental . remains )
end ,
handler = function ( )
summonPet ( talent.primal_elementalist . enabled and " primal_storm_elemental " or " greater_storm_elemental " , 30 * ( 1 + ( 0.01 * conduit.call_of_flame . mod ) ) )
end ,
} ,
stormkeeper = {
id = 191634 ,
cast = function ( ) return 1.5 * haste end ,
cooldown = 60 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 839977 ,
talent = " stormkeeper " ,
handler = function ( )
applyBuff ( " stormkeeper " , 20 , 2 )
end ,
} ,
thunderstorm = {
id = 51490 ,
cast = 0 ,
cooldown = 45 ,
gcd = " spell " ,
startsCombat = true ,
texture = 237589 ,
handler = function ( )
if target.within10 then applyDebuff ( " target " , " thunderstorm " ) end
end ,
} ,
tremor_totem = {
id = 8143 ,
cast = 0 ,
cooldown = function ( ) return 60 + ( conduit.totemic_surge . mod * 0.001 ) end ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136108 ,
handler = function ( )
summonTotem ( " tremor_totem " )
end ,
} ,
water_walking = {
id = 546 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 135863 ,
handler = function ( )
applyBuff ( " water_walking " )
end ,
} ,
wind_rush_totem = {
id = 192077 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
startsCombat = false ,
texture = 538576 ,
talent = " wind_rush_totem " ,
handler = function ( )
summonTotem ( " wind_rush_totem " )
end ,
} ,
wind_shear = {
id = 57994 ,
cast = 0 ,
cooldown = 12 ,
gcd = " spell " ,
startsCombat = true ,
texture = 136018 ,
toggle = " interrupts " ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
interrupt ( )
end ,
} ,
-- Pet Abilities
meteor = {
id = 117588 ,
known = function ( ) return talent.primal_elementalist . enabled and not talent.storm_elemental . enabled and fire_elemental.up end ,
cast = 0 ,
cooldown = 60 ,
gcd = " off " ,
startsCombat = true ,
texture = 1033911 ,
talent = " primal_elementalist " ,
usable = function ( ) return fire_elemental.up end ,
handler = function ( ) end ,
} ,
eye_of_the_storm = {
id = 157375 ,
known = function ( ) return talent.primal_elementalist . enabled and talent.storm_elemental . enabled and storm_elemental.up end ,
cast = 0 ,
cooldown = 40 ,
gcd = " off " ,
startsCombat = true ,
-- texture = ,
talent = " primal_elementalist " ,
usable = function ( ) return storm_elemental.up end ,
handler = function ( ) end ,
} ,
-- Shaman - Kyrian - 324386 - vesper_totem (Vesper Totem)
vesper_totem = {
id = 324386 ,
cast = 0 ,
cooldown = 60 ,
gcd = " totem " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = true ,
texture = 3565451 ,
toggle = " essences " ,
handler = function ( )
summonPet ( " vesper_totem " , 30 )
end ,
} ,
-- Shaman - Necrolord - 326059 - primordial_wave (Primordial Wave)
primordial_wave = {
id = 326059 ,
cast = 0 ,
cooldown = 45 ,
recharge = 45 ,
charges = 1 ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = true ,
texture = 3578231 ,
toggle = " essences " ,
cycle = " flame_shock " ,
velocity = 45 ,
handler = function ( )
applyDebuff ( " target " , " flame_shock " )
applyBuff ( " primordial_wave " )
end ,
auras = {
primordial_wave = {
id = 327164 ,
duration = 15 ,
max_stack = 1
} ,
splintered_elements = {
id = 354648 ,
duration = 10 ,
max_stack = 10 ,
} ,
}
} ,
-- Shaman - Night Fae - 328923 - fae_transfusion (Fae Transfusion)
fae_transfusion = {
id = 328923 ,
cast = function ( ) return haste * 3 * ( 1 + ( conduit.essential_extraction . mod * 0.01 ) ) end ,
channeled = true ,
cooldown = 120 ,
gcd = " spell " ,
spend = 0.075 ,
spendType = " mana " ,
startsCombat = true ,
texture = 3636849 ,
toggle = " essences " ,
nobuff = " fae_transfusion " ,
start = function ( )
applyBuff ( " fae_transfusion " )
end ,
tick = function ( )
if legendary.seeds_of_rampant_growth . enabled then
if state.spec . enhancement then reduceCooldown ( " feral_spirit " , 9 )
elseif state.spec . elemental then reduceCooldown ( talent.storm_elemental . enabled and " storm_elemental " or " fire_elemental " , 6 )
else reduceCooldown ( " healing_tide_totem " , 5 ) end
addStack ( " seeds_of_rampant_growth " )
end
end ,
finish = function ( )
if state.spec . enhancement then addStack ( " maelstrom_weapon " , nil , 3 ) end
end ,
auras = {
fae_transfusion = {
id = 328933 ,
duration = 20 ,
max_stack = 1
} ,
seeds_of_rampant_growth = {
id = 358945 ,
duration = 15 ,
max_stack = 5
}
} ,
} ,
fae_transfusion_heal = {
id = 328930 ,
cast = 0 ,
channeled = true ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 3636849 ,
buff = " fae_transfusion " ,
handler = function ( )
removeBuff ( " fae_transfusion " )
end ,
} ,
-- Shaman - Venthyr - 320674 - chain_harvest (Chain Harvest)
chain_harvest = {
id = 320674 ,
cast = 2.5 ,
cooldown = 90 ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = true ,
texture = 3565725 ,
toggle = " essences " ,
handler = function ( )
if legendary.elemental_conduit . enabled then
applyDebuff ( " target " , " flame_shock " )
active_dot.flame_shock = min ( active_enemies , active_dot.flame_shock + min ( 5 , active_enemies ) )
end
end ,
}
} )
--[[ spec:RegisterSetting( "funnel_damage", false, {
name = " Funnel AOE -> Target " ,
desc = function ( )
local s = " If checked, the addon's default priority will encourage you to spread |T135813:0|t Flame Shock but will focus damage on your current target, using |T136026:0|t Earth Shock rather than |T451165:0|t Earthquake. "
if not Hekili.DB . profile.specs [ state.spec . id ] . cycle then
s = s .. " \n \n |cFFFF0000Requires 'Recommend Target Swaps' on Targeting tab.|r "
end
return s
end ,
type = " toggle " ,
width = 1.5
} ) ] ]
spec : RegisterStateExpr ( " funneling " , function ( )
return false
-- return active_enemies > 1 and settings.cycle and settings.funnel_damage
end )
spec : RegisterSetting ( " stack_buffer " , 1.1 , {
name = " |T135855:0|t Icefury and |T839977:0|t Stormkeeper Padding " ,
desc = " The default priority tries to avoid wasting |T839977:0|t Stormkeeper and |T135855:0|t Icefury stacks with a grace period of 1.1 GCD per stack. \n \n " ..
" Increasing this number will reduce the likelihood of wasted Icefury / Stormkeeper stacks due to other procs taking priority, and leave you with more time to react. " ,
type = " range " ,
min = 1 ,
max = 2 ,
step = 0.01 ,
width = " full "
} )
spec : RegisterOptions ( {
enabled = true ,
aoe = 3 ,
nameplates = false ,
nameplateRange = 8 ,
damage = true ,
damageDots = true ,
damageExpiration = 8 ,
potion = " potion_of_spectral_intellect " ,
package = " Elemental " ,
} )
--[[ spec:RegisterSetting( "micromanage_pets", true, {
name = " Micromanage Primal Elemental Pets " ,
desc = " If checked, Meteor, Eye of the Storm, etc. will appear in your recommendations. " ,
type = " toggle " ,
width = 1.5
} ) ] ]
spec : RegisterPack ( " Elemental " , 20210707 , [ [ dGeDecqiKkpsqPAtiXNakYOevCkrQwLGIELiLzjIClGOODHYVernmGshtqAzIk9mGitdOQUgqHTjOKVbevJdOkoNGcTobfyEaH7HK2hqYbbkQAHcIhkOGMiqrLUiqvYhbkQ4KafLvIumtGO0nfukXork9tGOqlvqPupfrtvq1vfukPVcefmwbLI9sXFjAWcDyQwmKEmLMmcxwzZs5ZagTaNwLxlcZwv3gIDl53OA4IYXbQSCOEoOPt66s12fv9DGuJhOk15rQA ( IK9tytOMWnKeUodT5c2CdfSGCWcYzGf8agGpiLRHuPpBgYm3MWbMHSCKzibV ( HSs93qM50 ) CNWeUHeY7y7mKbQMbddsozGtd6Omlhjz4H0FxpEzXEttgEi2KnKO97vWSYGAijCDgAZfS5gkyb5GfKZal4bma ) Cb5gsy2SgAZnSY1qgCeeRmOgsIbTgsWRFiRu ) frYahXlbn00F6frqEsIyUGn3qf0iOjmmWlGbdde0aYuebZklhNXXUoreovVcaYGQBtir7T2WIyJJfrWm7ADm9jjIKkhJKylByMGgqMIiyEccrmSLPJJfrVierWl6NiYBIOgmrKu5yer0b8RygYmmVD ) mKH9WUicE9dzL6Visg4iEjOjSh2frA6p9IiipjrmxWMBOcAe0e2d7IyyyGxadggiOjSh2frqMIiywz54mo21jIWP6vaqguDBcjAV1gweBCSicMzxRJPpjrKu5yKeBzdZe0e2d7IiitrempbHig2Y0XXIOxeIi4f9te5nrudMisQCmIi6a ( vmbncAc7Ii4f49SDDeI4Ypm9IOEite1GjIUv5yr8GION3V3r ) Xe04w94fKLHNLJG6k15ynqUFiRu ) t6AuPt9FLYYWhI ) Y9dzL6 ) bv2kh9hHGMWUig2kCIiPYXij2YgweZWZYrqDve71piueHCKjIobbueb99VicZCqxIiKZlMGg3QhVGSm8SCeuxtJAYTFWal2BAsxJkK3F0RiyzDO2 ) jhUNPhVsLcY7p6veS88317NeY ) 8 RubnUvpEbzz4z5iOUMg1KHkhJKylB4KUgv1 ) vkdQCmsITSHzRC0FeuYb7hHC5xPmNGaYS8EPGaKsLc7hHC5xPmNGaYUcuGbytxqJB1JxqwgEwocQRPrn52HNC ) qwP ( lOXT6Xlildplhb110OM8 ( HSs9xI ( out6Auv ) xPS9dzL6Ve9DOYw5O ) iOaZ2 ) s1XatHmBGFL8pGaTUcaeGKGMWUigYSEhoreKnFiIyGdfrxevSNFViQhYsse1GjIobbVeXS3TdkIHPgCqrCLIPpmfrEjIHHG5kInowebjreolViGIOYfrpp ) iercEh9hitq28HiI8seZ6 ) Ze04w94fKLHNLJG6AAut ( 98 UeTJHAs ) vtAjOcsjDnQ0P ( Vsz7hYk1Fj67qLTYr ) rqbMT ) LQJbMcz2a ) k5FabADfaiaPuPq7TgdQCmsITSHz9mbnUvpEbzz4z5iOUMg1KTb ( vY ) ac06kGKUgv6u ) xPS9dzL6Ve9DOYw5O ) iOaZ2 ) s1XatHmBGFL8pGaTUcauubjk0H2Bngu5yKeBzdZ6zcACRE8cYYWZYrqDnnQjNX1JxcAe0e2frWSshg3ZurK3erRdvitqJB1JxW0OMmOVIqcdMJf04w94fmnQjdZo8PG2 ) eddLay3UKq45VcGAOcACRE8cMg1KZ46XlbnUvpEbtJAYD4KNoeOGg3QhVGPrn527itcd42ejDnQ5qN6 ) kLTFiRu ) LOVdv2kh9hr6uOtpBIRaOqx2ugu5ye5 ( HSs9N5w9Ypk5aZ2 ) s1XatHmBGFL8pGaTUcaeGuQuQ ) RugId1HL8MudMC ) qwPq2kh9hrQu4ETghdmgmb9O45jggkB3W0ljgYbhBGRFzzJiDbnUvpEbtJAYz4dHJjo ) LG2ZVKS0B ) jvhdmfsn0KUgv6q7TgldFiCmX5Ve0E ( X6zuYHUSPmOYXiY9dzL6pZT6LFPsbZ2 ) s1XatHmBGFL8pGaTUcaeGef0ERXa9vesGouzq1TjarUGnvkiV ) OxrW ( 5 esu6Ld82rY ( Xw5O ) isNsoWS9VuDmWuiZg4xj ) diqRRaabyKkL6 ) kLH4qDyjVj1Gj3pKvkKTYr ) rKkfUxRXXaJbtqpkEEIHHY2nm9sIHCWXg46xw2isLcY7p6veSFoHeLE5aVDKSFSvo6pI0f04w94fmnQj3Ehzsya3MiPRrLo9SjUcGso0LnLbvogrUFiRu ) zUvV8lvky2 ( xQogykKzd8RK ) beO1vaGaKOG2BngOVIqc0HkdQUnbiYfSPtjhy2 ( xQogykKzd8RK ) beO1vaGaKsLs9FLYqCOoSK3KAWK7hYkfYw5O ) isLc3R14yGXGjOhfppXWqz7gMEjXqo4ydC9llBePlOXT6XlyAutUD4j3pKvQ ) cACRE8cMg1KrMoowqJB1JxW0OMm6Z5eYwhtFsxJkDQ ) RuMdTRi8Yo2kh9hrQuO9wJ5q7kcVSJ1ZsLYY5pbh0fZH2veEzhdpe ) kiOadWkOXT6XlyAutgDy4WjUciPRrLo1 ) vkZH2veEzhBLJ ( Jivk0ERXCODfHx2X6zcACRE8cMg1KBhEOpNtK01OsN6 ) kL5q7kcVSJTYr ) rKkfAV1yo0UIWl7y9SuPSC ( tWbDXCODfHx2XWdXVcckWaScACRE8cMg1K9YoOI9xA9 ) t6AuPt9FLYCODfHx2Xw5O ) isLcT3AmhAxr4LDSEwQuwo ) j4GUyo0UIWl7y4H4xbbfyawbnUvpEbtJAYOoGK3Kk ( SjGjDnQ0P ( Vszo0UIWl7yRC0FePsrhAV1yo0UIWl7y9mbnUvpEbtJAY5hmByPY1HiOXT6XlyAutU5tQyVGTo84vsxJQLNFLxkRoGav28rHoCVwJJbgdUraL8Me7izEPsamh0AaBGRFzzJGso0P ( VsziouhwYBsnyY9dzLczRC0FePsH2BngId1HL8MudMC ) qwPqwplDkWS9VuDmWuiZg4xj ) diqRRaabijOXT6XlyAutU5tQyVGTo84vsxJQLNFLxkRoGav28rb3R14yGXGBeqjVjXosMxQeaZbTgWg46xw2iOKdDQ ) RugId1HL8MudMC ) qwPq2kh9hrQuO9wJH4qDyjVj1Gj3pKvkK1ZsLcMT ) LQJbMcz2a ) k5FabADfaOOcsPtjhlN ) eCqxS2HNC ) qwP ( ZWdXVccQCbBQuwo ) j4GUyqLJrK7hYk1FgEi ( vqqLlytxqJB1JxW0OMmUxs3QhVK ) b1KkhzuD ( s6AuDRE5NC1qUbbvUuYbMT ) LQJbMcz2a ) k5FabADfaOYnvky2 ( xQogykK9EExIohbu5MUGg3QhVGPrnzCVKUvpEj ) dQjvoYOcVc4NuDmW0KGk ( Sk1qt6AuPt9FLYGkhJi3pKvQ ) Svo6pckUvV8tUAi3GGGAUcACRE8cMg1KX9s6w94L8pOMu5iJkCs4va ) KQJbMMeuXNvPgAsxJQ6 ) kLbvogrUFiRu ) zRC0FeuCRE5NC1qUbbb1Cf0iOXT6XliZ5Jku5ye5 ( HSs9xqJB1JxqMZxAutE0pjVj1GjHkhJK01OI2BnM1 ) x ( hqGwxbWWdXVcckQHcwbnUvpEbzoFPrn55ynaCDpXs6Aur7TgB2a ( vasya3MG1Ze04w94fK58Lg1KTb ( vYahNFqvqJB1JxqMZxAutgQCmsITSHt6Auv ) xPmOYXij2YgMTYr ) riOXT6XliZ5lnQj3Ehzsya3Mijl92Fs1XatHudnPRrfVgEWah9hLCYXT6LFscUYAVJmjmGBtaICP4w9Yp5QHCdccQGeflN ) eCqxSm8HWXeN ) sq75hdpe ) kiicnSOy55x5LYQzX8NJjOqx2ugu5ye5 ( HSs9N5w9YVuPCRE5NKGRS27itcd42eGiukUvV8tUAi3GGIk4tHUSPmOYXiY9dzL6pZT6LFuu ) xPmehQdl5nPgm5 ( HSsHSvo6pI0tLkhCVwJJbgdMGEu88eddLTBy6Led5GJnW1VSSrqHUSPmOYXiY9dzL6pZT6LFPNUGg3QhVGmNV0OMC7DKjHbCBIKUgv6CRE5NKGRS27itcd42euOlBkdQCmIC ) qwP ( Z
end