-- DruidBalance.lua
-- June 2018
local addon , ns = ...
local Hekili = _G [ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
-- Conduits
-- [-] fury_of_the_skies
-- [x] precise_alignment
-- [-] stellar_inspiration
-- [-] umbral_intensity
-- Covenants
-- [x] deep_allegiance
-- [-] endless_thirst
-- [-] evolved_swarm
-- [-] conflux_of_elements
-- Endurance
-- [x] tough_as_bark
-- [x] ursine_vigor
-- [-] innate_resolve
-- Finesse
-- [x] born_anew
-- [-] front_of_the_pack
-- [x] born_of_the_wilds
-- [x] tireless_pursuit
if UnitClassBase ( " player " ) == " DRUID " then
local spec = Hekili : NewSpecialization ( 102 , true )
spec : RegisterResource ( Enum.PowerType . LunarPower , {
fury_of_elune = {
aura = " fury_of_elune_ap " ,
debuff = true ,
last = function ( )
local app = state.debuff . fury_of_elune_ap.applied
local t = state.query_time
return app + floor ( ( t - app ) * 2 ) * 0.5
end ,
interval = 0.5 ,
value = 2.5
} ,
celestial_infusion = {
aura = " celestial_infusion " ,
last = function ( )
local app = state.buff . celestial_infusion.applied
local t = state.query_time
return app + floor ( ( t - app ) * 2 ) * 0.5
end ,
interval = 0.5 ,
value = 2.5
} ,
natures_balance = {
talent = " natures_balance " ,
last = function ( )
local app = state.combat
local t = state.query_time
return app + floor ( ( t - app ) / 2 ) * 2
end ,
interval = 2 ,
value = 1 ,
}
} )
spec : RegisterResource ( Enum.PowerType . Mana )
spec : RegisterResource ( Enum.PowerType . Energy )
spec : RegisterResource ( Enum.PowerType . ComboPoints )
spec : RegisterResource ( Enum.PowerType . Rage )
-- Talents
spec : RegisterTalents ( {
natures_balance = 22385 , -- 202430
warrior_of_elune = 22386 , -- 202425
force_of_nature = 22387 , -- 205636
tiger_dash = 19283 , -- 252216
renewal = 18570 , -- 108238
wild_charge = 18571 , -- 102401
feral_affinity = 22155 , -- 202157
guardian_affinity = 22157 , -- 197491
restoration_affinity = 22159 , -- 197492
mighty_bash = 21778 , -- 5211
mass_entanglement = 18576 , -- 102359
heart_of_the_wild = 18577 , -- 319454
soul_of_the_forest = 18580 , -- 114107
starlord = 21706 , -- 202345
incarnation = 21702 , -- 102560
twin_moons = 22389 , -- 279620
stellar_drift = 21712 , -- 202354
stellar_flare = 22165 , -- 202347
solstice = 21648 , -- 343647
fury_of_elune = 21193 , -- 202770
new_moon = 21655 , -- 274281
} )
-- PvP Talents
spec : RegisterPvpTalents ( {
celestial_guardian = 180 , -- 233754
crescent_burn = 182 , -- 200567
deep_roots = 834 , -- 233755
dying_stars = 822 , -- 232546
faerie_swarm = 836 , -- 209749
high_winds = 5383 , -- 200931
moon_and_stars = 184 , -- 233750
moonkin_aura = 185 , -- 209740
owlkin_adept = 5407 , -- 354541
protector_of_the_grove = 3728 , -- 209730
star_burst = 3058 , -- 356517
thorns = 3731 , -- 305497
} )
spec : RegisterPower ( " lively_spirit " , 279642 , {
id = 279648 ,
duration = 20 ,
max_stack = 1 ,
} )
local mod_circle_hot = setfenv ( function ( x )
return legendary.circle_of_life_and_death . enabled and ( 0.85 * x ) or x
end , state )
local mod_circle_dot = setfenv ( function ( x )
return legendary.circle_of_life_and_death . enabled and ( 0.75 * x ) or x
end , state )
-- Auras
spec : RegisterAuras ( {
aquatic_form = {
id = 276012 ,
} ,
astral_influence = {
id = 197524 ,
} ,
barkskin = {
id = 22812 ,
duration = 12 ,
max_stack = 1 ,
} ,
bear_form = {
id = 5487 ,
duration = 3600 ,
max_stack = 1 ,
} ,
cat_form = {
id = 768 ,
duration = 3600 ,
max_stack = 1 ,
} ,
celestial_alignment = {
id = 194223 ,
duration = function ( ) return 20 + ( conduit.precise_alignment . mod * 0.001 ) end ,
max_stack = 1 ,
} ,
dash = {
id = 1850 ,
duration = 10 ,
max_stack = 1 ,
} ,
eclipse_lunar = {
id = 48518 ,
duration = 15 ,
max_stack = 1 ,
meta = {
empowered = function ( t ) return t.up and t.empowerTime >= t.applied end ,
}
} ,
eclipse_solar = {
id = 48517 ,
duration = 15 ,
max_stack = 1 ,
meta = {
empowered = function ( t ) return t.up and t.empowerTime >= t.applied end ,
}
} ,
elunes_wrath = {
id = 64823 ,
duration = 10 ,
max_stack = 1
} ,
entangling_roots = {
id = 339 ,
duration = 30 ,
type = " Magic " ,
max_stack = 1 ,
} ,
feline_swiftness = {
id = 131768 ,
} ,
flight_form = {
id = 276029 ,
} ,
force_of_nature = {
id = 205644 ,
duration = 15 ,
max_stack = 1 ,
} ,
frenzied_regeneration = {
id = 22842 ,
duration = 3 ,
max_stack = 1 ,
} ,
fury_of_elune_ap = {
id = 202770 ,
duration = 8 ,
tick_time = 0.5 ,
max_stack = 1 ,
generate = function ( t )
local applied = action.fury_of_elune . lastCast
if applied and now - applied < 8 then
t.count = 1
t.expires = applied + 8
t.applied = applied
t.caster = " player "
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = " nobody "
end ,
copy = " fury_of_elune "
} ,
growl = {
id = 6795 ,
duration = 3 ,
max_stack = 1 ,
} ,
heart_of_the_wild = {
id = 108291 ,
duration = 45 ,
max_stack = 1 ,
copy = { 108292 , 108293 , 108294 }
} ,
incarnation = {
id = 102560 ,
duration = function ( ) return 30 + ( conduit.precise_alignment . mod * 0.001 ) end ,
max_stack = 1 ,
copy = " incarnation_chosen_of_elune "
} ,
ironfur = {
id = 192081 ,
duration = 7 ,
max_stack = 1 ,
} ,
mass_entanglement = {
id = 102359 ,
duration = 30 ,
type = " Magic " ,
max_stack = 1 ,
} ,
mighty_bash = {
id = 5211 ,
duration = 5 ,
max_stack = 1 ,
} ,
moonfire = {
id = 164812 ,
duration = function ( ) return mod_circle_dot ( 22 ) end ,
tick_time = function ( ) return mod_circle_dot ( 2 ) * haste end ,
type = " Magic " ,
max_stack = 1 ,
} ,
moonkin_form = {
id = 24858 ,
duration = 3600 ,
max_stack = 1 ,
} ,
owlkin_frenzy = {
id = 157228 ,
duration = 10 ,
max_stack = function ( ) return pvptalent.owlkin_adept . enabled and 2 or 1 end ,
} ,
prowl = {
id = 5215 ,
duration = 3600 ,
max_stack = 1 ,
} ,
regrowth = {
id = 8936 ,
duration = function ( ) return mod_circle_hot ( 12 ) end ,
type = " Magic " ,
max_stack = 1 ,
} ,
shadowmeld = {
id = 58984 ,
duration = 3600 ,
max_stack = 1 ,
} ,
solar_beam = {
id = 81261 ,
duration = 3600 ,
max_stack = 1 ,
} ,
solstice = {
id = 343648 ,
duration = 6 ,
max_stack = 1 ,
} ,
stag_form = {
id = 210053 ,
duration = 3600 ,
max_stack = 1 ,
generate = function ( )
local form = GetShapeshiftForm ( )
local stag = form and form > 0 and select ( 4 , GetShapeshiftFormInfo ( form ) )
local sf = buff.stag_form
if stag == 210053 then
sf.count = 1
sf.applied = now
sf.expires = now + 3600
sf.caster = " player "
return
end
sf.count = 0
sf.applied = 0
sf.expires = 0
sf.caster = " nobody "
end ,
} ,
starfall = {
id = 191034 ,
duration = 8 ,
max_stack = 1 ,
} ,
starlord = {
id = 279709 ,
duration = 20 ,
max_stack = 3 ,
} ,
stellar_flare = {
id = 202347 ,
duration = function ( ) return mod_circle_dot ( 24 ) end ,
tick_time = function ( ) return mod_circle_dot ( 2 ) * haste end ,
type = " Magic " ,
max_stack = 1 ,
} ,
sunfire = {
id = 164815 ,
duration = function ( ) return mod_circle_dot ( 18 ) end ,
tick_time = function ( ) return mod_circle_dot ( 2 ) * haste end ,
type = " Magic " ,
max_stack = 1 ,
} ,
thick_hide = {
id = 16931 ,
} ,
thrash_bear = {
id = 192090 ,
duration = function ( ) return mod_circle_dot ( 15 ) end ,
tick_time = function ( ) return mod_circle_dot ( 3 ) * haste end ,
max_stack = 3 ,
} ,
tiger_dash = {
id = 252216 ,
duration = 5 ,
max_stack = 1 ,
} ,
travel_form = {
id = 783 ,
duration = 3600 ,
max_stack = 1 ,
} ,
treant_form = {
id = 114282 ,
duration = 3600 ,
max_stack = 1 ,
} ,
typhoon = {
id = 61391 ,
duration = 6 ,
type = " Magic " ,
max_stack = 1 ,
} ,
warrior_of_elune = {
id = 202425 ,
duration = 3600 ,
type = " Magic " ,
max_stack = 3 ,
} ,
wild_charge = {
id = 102401 ,
duration = 0.5 ,
max_stack = 1 ,
} ,
yseras_gift = {
id = 145108 ,
} ,
-- Alias for Celestial Alignment vs. Incarnation
ca_inc = { } ,
--[[
alias = { " incarnation " , " celestial_alignment " } ,
aliasMode = " first " , -- use duration info from the first buff that's up, as they should all be equal.
aliasType = " buff " ,
-- duration = function () return talent.incarnation.enabled and 30 or 20 end,
} , ] ]
any_form = {
alias = { " bear_form " , " cat_form " , " moonkin_form " } ,
duration = 3600 ,
aliasMode = " first " ,
aliasType = " buff " ,
} ,
-- PvP Talents
celestial_guardian = {
id = 234081 ,
duration = 3600 ,
max_stack = 1 ,
} ,
cyclone = {
id = 33786 ,
duration = 6 ,
max_stack = 1 ,
} ,
faerie_swarm = {
id = 209749 ,
duration = 5 ,
type = " Magic " ,
max_stack = 1 ,
} ,
high_winds = {
id = 200931 ,
duration = 4 ,
max_stack = 1 ,
} ,
moon_and_stars = {
id = 234084 ,
duration = 10 ,
max_stack = 1 ,
} ,
moonkin_aura = {
id = 209746 ,
duration = 18 ,
type = " Magic " ,
max_stack = 3 ,
} ,
thorns = {
id = 305497 ,
duration = 12 ,
type = " Magic " ,
max_stack = 1 ,
} ,
-- Azerite Powers
arcanic_pulsar = {
id = 287790 ,
duration = 3600 ,
max_stack = 9 ,
} ,
dawning_sun = {
id = 276153 ,
duration = 8 ,
max_stack = 1 ,
} ,
sunblaze = {
id = 274399 ,
duration = 20 ,
max_stack = 1
} ,
-- Legendaries
balance_of_all_things_arcane = {
id = 339946 ,
duration = 8 ,
max_stack = 8
} ,
balance_of_all_things_nature = {
id = 339943 ,
duration = 8 ,
max_stack = 8 ,
} ,
celestial_infusion = {
id = 367907 ,
duration = 8 ,
max_stack = 1
} ,
oath_of_the_elder_druid = {
id = 338643 ,
duration = 60 ,
max_stack = 1
} ,
oneths_perception = {
id = 339800 ,
duration = 30 ,
max_stack = 1 ,
} ,
oneths_clear_vision = {
id = 339797 ,
duration = 30 ,
max_stack = 1 ,
} ,
primordial_arcanic_pulsar = {
id = 338825 ,
duration = 3600 ,
max_stack = 10 ,
} ,
timeworn_dreambinder = {
id = 340049 ,
duration = 6 ,
max_stack = 2 ,
} ,
} )
-- Adaptive Swarm Stuff
do
local applications = {
SPELL_AURA_APPLIED = true ,
SPELL_AURA_REFRESH = true ,
SPELL_AURA_APPLIED_DOSE = true
}
local casts = { SPELL_CAST_SUCCESS = true }
local removals = {
SPELL_AURA_REMOVED = true ,
SPELL_AURA_BROKEN = true ,
SPELL_AURA_BROKEN_SPELL = true ,
SPELL_AURA_REMOVED_DOSE = true ,
SPELL_DISPEL = true
}
local deaths = {
UNIT_DIED = true ,
UNIT_DESTROYED = true ,
UNIT_DISSIPATES = true ,
PARTY_KILL = true ,
SPELL_INSTAKILL = true ,
}
local spellIDs = {
[ 325733 ] = true ,
[ 325748 ] = true ,
[ 325727 ] = true
}
local flights = { }
local pending = { }
local swarms = { }
-- Flow: Cast -> In Flight -> Application -> Ticks -> Removal -> In Flight -> Application -> Ticks -> Removal -> ...
-- If the swarm target dies, it will jump again.
local insert , remove = table.insert , table.remove
function Hekili : EmbedAdaptiveSwarm ( s )
s : RegisterCombatLogEvent ( function ( _ , subtype , _ , sourceGUID , sourceName , _ , _ , destGUID , destName , destFlags , _ , spellID , spellName )
if not state.covenant . necrolord then return end
if sourceGUID == state.GUID and spellIDs [ spellID ] then
-- On cast, we need to show we have a cast-in-flight.
if casts [ subtype ] then
local dot
if bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 then
dot = " adaptive_swarm_damage "
else
dot = " adaptive_swarm_heal "
end
insert ( flights , { destGUID , 3 , GetTime ( ) + 5 , dot } )
-- On application, we need to store the GUID of the unit so we can get the stacks and expiration time.
elseif applications [ subtype ] and # flights > 0 then
local n , flight
for i , v in ipairs ( flights ) do
if v [ 1 ] == destGUID then
n = i
flight = v
break
end
if not flight and v [ 1 ] == " unknown " then
n = i
flight = v
end
end
if flight then
local swarm = swarms [ destGUID ]
local now = GetTime ( )
if swarm and swarm.expiration > now then
swarm.stacks = swarm.stacks + flight [ 2 ]
swarm.dot = bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 and " adaptive_swarm_damage " or " adaptive_swarm_heal "
swarm.expiration = now + class.auras [ swarm.dot ] . duration
else
swarms [ destGUID ] = { }
swarms [ destGUID ] . stacks = flight [ 2 ]
swarms [ destGUID ] . dot = bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 and " adaptive_swarm_damage " or " adaptive_swarm_heal "
swarms [ destGUID ] . expiration = now + class.auras [ swarms [ destGUID ] . dot ] . duration
end
remove ( flights , n )
else
swarms [ destGUID ] = { }
swarms [ destGUID ] . stacks = 3 -- We'll assume it's fresh.
swarms [ destGUID ] . dot = bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 and " adaptive_swarm_damage " or " adaptive_swarm_heal "
swarms [ destGUID ] . expiration = GetTime ( ) + class.auras [ swarms [ destGUID ] . dot ] . duration
end
elseif removals [ subtype ] then
-- If we have a swarm for this, remove it.
local swarm = swarms [ destGUID ]
if swarm then
swarms [ destGUID ] = nil
if swarm.stacks > 1 then
local dot
if bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 then
dot = " adaptive_swarm_heal "
else
dot = " adaptive_swarm_damage "
end
insert ( flights , { " unknown " , swarm.stacks - 1 , GetTime ( ) + 5 , dot } )
end
end
end
elseif swarms [ destGUID ] and deaths [ subtype ] then
-- If we have a swarm for this, remove it.
local swarm = swarms [ destGUID ]
if swarm then
swarms [ destGUID ] = nil
if swarm.stacks > 1 then
if bit.band ( destFlags , COMBATLOG_OBJECT_REACTION_FRIENDLY ) == 0 then
dot = " adaptive_swarm_heal "
else
dot = " adaptive_swarm_damage "
end
insert ( flights , { " unknown " , swarm.stacks - 1 , GetTime ( ) + 5 , dot } )
end
end
end
end )
--[[ s:RegisterEvent( "UNIT_AURA", function( _, unit )
if not state.covenant . necrolord then return end
local guid = UnitGUID ( unit )
if pending [ guid ] then
if UnitIsFriend ( unit , " player " ) then
local name , _ , count , _ , _ , expirationTime = FindUnitBuffByID ( unit , 325748 , " PLAYER " )
print ( " Buff " , name , count , guid , pending [ guid ] )
if name then
swarms [ guid ] = {
stacks = count ,
expiration = expirationTime ,
}
pending [ guid ] = nil
return
end
else
local name , _ , count , _ , _ , expirationTime = FindUnitDebuffByID ( unit , 325733 , " PLAYER " )
print ( " Debuff " , name , count , guid , pending [ guid ] )
if name then
swarms [ guid ] = {
stacks = count ,
expiration = expirationTime ,
}
pending [ guid ] = nil
return
end
end
pending [ guid ] = pending [ guid ] + 1
if pending [ guid ] > 2 then
pending [ guid ] = nil
end
end
end ) ] ]
function s . GetActiveSwarms ( )
return swarms
end
function s . GetPendingSwarms ( )
return pending
end
function s . GetInFlightSwarms ( )
return flights
end
local flySwarm , landSwarm
landSwarm = setfenv ( function ( aura )
if aura.key == " adaptive_swarm_heal_in_flight " then
applyBuff ( " adaptive_swarm_heal " , 12 , min ( 5 , buff.adaptive_swarm_heal . stack + aura.count ) )
buff.adaptive_swarm_heal . expires = query_time + 12
state : QueueAuraEvent ( " adaptive_swarm " , flySwarm , buff.adaptive_swarm_heal . expires , " AURA_EXPIRATION " , buff.adaptive_swarm_heal )
else
applyDebuff ( " target " , " adaptive_swarm_damage " , 12 , min ( 5 , debuff.adaptive_swarm_damage . stack + aura.count ) )
debuff.adaptive_swarm_damage . expires = query_time + 12
state : QueueAuraEvent ( " adaptive_swarm " , flySwarm , debuff.adaptive_swarm_damage . expires , " AURA_EXPIRATION " , debuff.adaptive_swarm_damage )
end
end , state )
flySwarm = setfenv ( function ( aura )
if aura.key == " adaptive_swarm_heal " then
applyBuff ( " adaptive_swarm_heal_in_flight " , 5 , aura.count - 1 )
state : QueueAuraEvent ( " adaptive_swarm " , landSwarm , query_time + 5 , " AURA_EXPIRATION " , buff.adaptive_swarm_heal_in_flight )
else
applyBuff ( " adaptive_swarm_damage_in_flight " , 5 , aura.count - 1 )
state : QueueAuraEvent ( " adaptive_swarm " , landSwarm , query_time + 5 , " AURA_EXPIRATION " , buff.adaptive_swarm_damage_in_flight )
end
end , state )
s.SwarmOnReset = setfenv ( function ( )
for k , v in pairs ( swarms ) do
if v.expiration + 0.1 <= now then swarms [ k ] = nil end
end
for i = # flights , 1 , - 1 do
if flights [ i ] [ 3 ] + 0.1 <= now then remove ( flights , i ) end
end
local target = UnitGUID ( " target " )
local tSwarm = swarms [ target ]
if not UnitIsFriend ( " target " , " player " ) and tSwarm and tSwarm.expiration > now then
applyDebuff ( " target " , " adaptive_swarm_damage " , tSwarm.expiration - now , tSwarm.stacks )
debuff.adaptive_swarm_damage . expires = tSwarm.expiration
if tSwarm.stacks > 1 then
state : QueueAuraEvent ( " adaptive_swarm " , flySwarm , tSwarm.expiration , " AURA_EXPIRATION " , debuff.adaptive_swarm_damage )
end
end
if buff.adaptive_swarm_heal . up and buff.adaptive_swarm_heal . stack > 1 then
state : QueueAuraEvent ( " adaptive_swarm " , flySwarm , buff.adaptive_swarm_heal . expires , " AURA_EXPIRATION " , buff.adaptive_swarm_heal )
else
for k , v in pairs ( swarms ) do
if k ~= target and v.dot == " adaptive_swarm_heal " then
applyBuff ( " adaptive_swarm_heal " , v.expiration - now , v.stacks )
buff.adaptive_swarm_heal . expires = v.expiration
if v.stacks > 1 then
state : QueueAuraEvent ( " adaptive_swarm " , flySwarm , buff.adaptive_swarm_heal . expires , " AURA_EXPIRATION " , buff.adaptive_swarm_heal )
end
end
end
end
local flight
for i , v in ipairs ( flights ) do
if not flight or v [ 3 ] > now and v [ 3 ] > flight then flight = v end
end
if flight then
local dot = flight [ 4 ] .. " _in_flight "
applyBuff ( dot , flight [ 3 ] - now , flight [ 2 ] )
state : QueueAuraEvent ( dot , landSwarm , flight [ 3 ] , " AURA_EXPIRATION " , buff [ dot ] )
end
Hekili : Debug ( " Swarm Info: \n Damage - %.2f remains, %d stacks. \n Dmg In Flight - %.2f remains, %d stacks. \n Heal - %.2f remains, %d stacks. \n Heal In Flight - %.2f remains, %d stacks. \n Count Dmg: %d, Count Heal: %d. " , dot.adaptive_swarm_damage . remains , dot.adaptive_swarm_damage . stack , buff.adaptive_swarm_damage_in_flight . remains , buff.adaptive_swarm_damage_in_flight . stack , buff.adaptive_swarm_heal . remains , buff.adaptive_swarm_heal . stack , buff.adaptive_swarm_heal_in_flight . remains , buff.adaptive_swarm_heal_in_flight . stack , active_dot.adaptive_swarm_damage , active_dot.adaptive_swarm_heal )
end , state )
function Hekili : DumpSwarmInfo ( )
local line = " Flights: "
for k , v in pairs ( flights ) do
line = line .. " " .. k .. " : " .. table.concat ( v , " : " )
end
print ( line )
line = " Pending: "
for k , v in pairs ( pending ) do
line = line .. " " .. k .. " : " .. v
end
print ( line )
line = " Swarms: "
for k , v in pairs ( swarms ) do
line = line .. " " .. k .. " : " .. v.stacks .. " : " .. v.expiration
end
print ( line )
end
-- Druid - Necrolord - 325727 - adaptive_swarm (Adaptive Swarm)
spec : RegisterAbility ( " adaptive_swarm " , {
id = 325727 ,
cast = 0 ,
cooldown = 25 ,
gcd = " spell " ,
spend = 0.05 ,
spendType = " mana " ,
startsCombat = true ,
texture = 3578197 ,
-- For Feral, we want to put Adaptive Swarm on the highest health enemy.
indicator = function ( )
if state.spec . feral and active_enemies > 1 and target.time_to_die < longest_ttd then return " cycle " end
end ,
handler = function ( )
applyDebuff ( " target " , " adaptive_swarm_dot " , nil , 3 )
if soulbind.kevins_oozeling . enabled then applyBuff ( " kevins_oozeling " ) end
end ,
copy = { " adaptive_swarm_damage " , " adaptive_swarm_heal " , 325733 , 325748 } ,
auras = {
adaptive_swarm_dot = {
id = 325733 ,
duration = function ( ) return mod_circle_dot ( 12 ) end ,
tick_time = function ( ) return mod_circle_dot ( 2 ) * haste end ,
max_stack = 5 ,
--[[ meta = {
stack = function ( t ) return t.down and dot.adaptive_swarm_hot . up and max ( 0 , dot.adaptive_swarm_hot . count - 1 ) or t.count end ,
} , ] ]
copy = " adaptive_swarm_damage "
} ,
adaptive_swarm_hot = {
id = 325748 ,
duration = function ( ) return mod_circle_hot ( 12 ) end ,
tick_time = function ( ) return mod_circle_hot ( 2 ) * haste end ,
max_stack = 5 ,
--[[ meta = {
stack = function ( t ) return t.down and dot.adaptive_swarm_dot . up and max ( 0 , dot.adaptive_swarm_dot . count - 1 ) or t.count end ,
} , ] ]
dot = " buff " ,
copy = " adaptive_swarm_heal "
} ,
adaptive_swarm_damage_in_flight = {
duration = 5 ,
max_stack = 5
} ,
adaptive_swarm_heal_in_flight = {
duration = 5 ,
max_stack = 5 ,
} ,
adaptive_swarm = {
alias = { " adaptive_swarm_damage " , " adaptive_swarm_heal " } ,
aliasMode = " first " , -- use duration info from the first buff that's up, as they should all be equal.
aliasType = " any " ,
} ,
adaptive_swarm_in_flight = {
alias = { " adaptive_swarm_damage " , " adaptive_swarm_heal " } ,
aliasMode = " shortest " , -- use duration info from the first buff that's up, as they should all be equal.
aliasType = " any " ,
} ,
}
} )
end
end
Hekili : EmbedAdaptiveSwarm ( spec )
spec : RegisterStateFunction ( " break_stealth " , function ( )
removeBuff ( " shadowmeld " )
if buff.prowl . up then
setCooldown ( " prowl " , 6 )
removeBuff ( " prowl " )
end
end )
-- Function to remove any form currently active.
spec : RegisterStateFunction ( " unshift " , function ( )
if conduit.tireless_pursuit . enabled and ( buff.cat_form . up or buff.travel_form . up ) then applyBuff ( " tireless_pursuit " ) end
removeBuff ( " cat_form " )
removeBuff ( " bear_form " )
removeBuff ( " travel_form " )
removeBuff ( " moonkin_form " )
removeBuff ( " travel_form " )
removeBuff ( " aquatic_form " )
removeBuff ( " stag_form " )
removeBuff ( " celestial_guardian " )
if legendary.oath_of_the_elder_druid . enabled and debuff.oath_of_the_elder_druid_icd . down and talent.restoration_affinity . enabled then
applyBuff ( " heart_of_the_wild " )
applyDebuff ( " player " , " oath_of_the_elder_druid_icd " )
end
end )
local affinities = {
bear_form = " guardian_affinity " ,
cat_form = " feral_affinity " ,
moonkin_form = " balance_affinity " ,
}
-- Function to apply form that is passed into it via string.
spec : RegisterStateFunction ( " shift " , function ( form )
if conduit.tireless_pursuit . enabled and ( buff.cat_form . up or buff.travel_form . up ) then applyBuff ( " tireless_pursuit " ) end
removeBuff ( " cat_form " )
removeBuff ( " bear_form " )
removeBuff ( " travel_form " )
removeBuff ( " moonkin_form " )
removeBuff ( " travel_form " )
removeBuff ( " aquatic_form " )
removeBuff ( " stag_form " )
applyBuff ( form )
if affinities [ form ] and legendary.oath_of_the_elder_druid . enabled and debuff.oath_of_the_elder_druid_icd . down and talent [ affinities [ form ] ] . enabled then
applyBuff ( " heart_of_the_wild " )
applyDebuff ( " player " , " oath_of_the_elder_druid_icd " )
end
if form == " bear_form " and pvptalent.celestial_guardian . enabled then
applyBuff ( " celestial_guardian " )
end
end )
spec : RegisterStateExpr ( " lunar_eclipse " , function ( )
return 0
end )
spec : RegisterStateExpr ( " solar_eclipse " , function ( )
return 0
end )
spec : RegisterHook ( " runHandler " , function ( ability )
local a = class.abilities [ ability ]
if not a or a.startsCombat then
break_stealth ( )
end
end )
--[[ This is intended to cause an AP reset on entering an encounter, but it's not working.
spec : RegisterHook ( " start_combat " , function ( action )
if boss and astral_power.current > 50 then
spend ( astral_power.current - 50 , " astral_power " )
end
end ) ] ]
spec : RegisterHook ( " pregain " , function ( amt , resource , overcap , clean )
if buff.memory_of_lucid_dreams . up then
if amt > 0 and resource == " astral_power " then
return amt * 2 , resource , overcap , true
end
end
end )
spec : RegisterHook ( " prespend " , function ( amt , resource , clean )
if buff.memory_of_lucid_dreams . up then
if amt < 0 and resource == " astral_power " then
return amt * 2 , resource , overcap , true
end
end
end )
local check_for_ap_overcap = setfenv ( function ( ability )
local a = ability or this_action
if not a then return true end
a = action [ a ]
if not a then return true end
local cost = 0
if a.spendType == " astral_power " then cost = a.cost end
return astral_power.current - cost + ( talent.shooting_stars . enabled and 4 or 0 ) + ( talent.natures_balance . enabled and ceil ( execute_time / 2 ) or 0 ) < astral_power.max
end , state )
spec : RegisterStateExpr ( " ap_check " , function ( ) return check_for_ap_overcap ( ) end )
-- Simplify lookups for AP abilities consistent with SimC.
local ap_checks = {
" force_of_nature " , " full_moon " , " half_moon " , " incarnation " , " moonfire " , " new_moon " , " starfall " , " starfire " , " starsurge " , " sunfire " , " wrath "
}
for i , lookup in ipairs ( ap_checks ) do
spec : RegisterStateExpr ( lookup , function ( )
return action [ lookup ]
end )
end
spec : RegisterStateExpr ( " active_moon " , function ( )
return " new_moon "
end )
local function IsActiveSpell ( id )
local slot = FindSpellBookSlotBySpellID ( id )
if not slot then return false end
local _ , _ , spellID = GetSpellBookItemName ( slot , " spell " )
return id == spellID
end
state.IsActiveSpell = IsActiveSpell
local ExpireCelestialAlignment = setfenv ( function ( )
eclipse.state = " ANY_NEXT "
eclipse.reset_stacks ( )
if buff.eclipse_lunar . down then removeBuff ( " starsurge_empowerment_lunar " ) end
if buff.eclipse_solar . down then removeBuff ( " starsurge_empowerment_solar " ) end
if Hekili.ActiveDebug then Hekili : Debug ( " Expire CA_Inc: %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
end , state )
local ExpireEclipseLunar = setfenv ( function ( )
eclipse.state = " SOLAR_NEXT "
eclipse.reset_stacks ( )
eclipse.wrath_counter = 0
removeBuff ( " starsurge_empowerment_lunar " )
if Hekili.ActiveDebug then Hekili : Debug ( " Expire Lunar: %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
end , state )
local ExpireEclipseSolar = setfenv ( function ( )
eclipse.state = " LUNAR_NEXT "
eclipse.reset_stacks ( )
eclipse.starfire_counter = 0
removeBuff ( " starsurge_empowerment_solar " )
if Hekili.ActiveDebug then Hekili : Debug ( " Expire Solar: %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
end , state )
spec : RegisterStateTable ( " eclipse " , setmetatable ( {
-- ANY_NEXT, IN_SOLAR, IN_LUNAR, IN_BOTH, SOLAR_NEXT, LUNAR_NEXT
state = " ANY_NEXT " ,
wrath_counter = 2 ,
starfire_counter = 2 ,
reset = setfenv ( function ( )
eclipse.starfire_counter = GetSpellCount ( 197628 ) or 0
eclipse.wrath_counter = GetSpellCount ( 5176 ) or 0
if buff.eclipse_solar . up and buff.eclipse_lunar . up then
eclipse.state = " IN_BOTH "
-- eclipse.reset_stacks()
elseif buff.eclipse_solar . up then
eclipse.state = " IN_SOLAR "
-- eclipse.reset_stacks()
elseif buff.eclipse_lunar . up then
eclipse.state = " IN_LUNAR "
-- eclipse.reset_stacks()
elseif eclipse.starfire_counter > 0 and eclipse.wrath_counter > 0 then
eclipse.state = " ANY_NEXT "
elseif eclipse.starfire_counter == 0 and eclipse.wrath_counter > 0 then
eclipse.state = " LUNAR_NEXT "
elseif eclipse.starfire_counter > 0 and eclipse.wrath_counter == 0 then
eclipse.state = " SOLAR_NEXT "
elseif eclipse.starfire_count == 0 and eclipse.wrath_counter == 0 and buff.eclipse_lunar . down and buff.eclipse_solar . down then
eclipse.state = " ANY_NEXT "
eclipse.reset_stacks ( )
end
if buff.ca_inc . up then
state : QueueAuraExpiration ( " ca_inc " , ExpireCelestialAlignment , buff.ca_inc . expires )
elseif buff.eclipse_solar . up then
state : QueueAuraExpiration ( " eclipse_solar " , ExpireEclipseSolar , buff.eclipse_solar . expires )
elseif buff.eclipse_lunar . up then
state : QueueAuraExpiration ( " eclipse_lunar " , ExpireEclipseLunar , buff.eclipse_lunar . expires )
end
buff.eclipse_solar . empowerTime = 0
buff.eclipse_lunar . empowerTime = 0
if buff.eclipse_solar . up and action.starsurge . lastCast > buff.eclipse_solar . applied then buff.eclipse_solar . empowerTime = action.starsurge . lastCast end
if buff.eclipse_lunar . up and action.starsurge . lastCast > buff.eclipse_lunar . applied then buff.eclipse_lunar . empowerTime = action.starsurge . lastCast end
end , state ) ,
reset_stacks = setfenv ( function ( )
eclipse.wrath_counter = 2
eclipse.starfire_counter = 2
end , state ) ,
trigger_both = setfenv ( function ( duration )
eclipse.state = " IN_BOTH "
eclipse.reset_stacks ( )
if legendary.balance_of_all_things . enabled then
applyBuff ( " balance_of_all_things_arcane " , nil , 8 , 8 )
applyBuff ( " balance_of_all_things_nature " , nil , 8 , 8 )
end
if talent.solstice . enabled then applyBuff ( " solstice " ) end
removeBuff ( " starsurge_empowerment_lunar " )
removeBuff ( " starsurge_empowerment_solar " )
applyBuff ( " eclipse_lunar " , ( duration or class.auras . eclipse_lunar.duration ) + buff.eclipse_lunar . remains )
if set_bonus.tier28_2pc > 0 then applyBuff ( " celestial_infusion " ) end
applyBuff ( " eclipse_solar " , ( duration or class.auras . eclipse_solar.duration ) + buff.eclipse_solar . remains )
state : QueueAuraExpiration ( " ca_inc " , ExpireCelestialAlignment , buff.ca_inc . expires )
state : RemoveAuraExpiration ( " eclipse_solar " )
state : QueueAuraExpiration ( " eclipse_solar " , ExpireEclipseSolar , buff.eclipse_solar . expires )
state : RemoveAuraExpiration ( " eclipse_lunar " )
state : QueueAuraExpiration ( " eclipse_lunar " , ExpireEclipseLunar , buff.eclipse_lunar . expires )
end , state ) ,
advance = setfenv ( function ( )
if Hekili.ActiveDebug then Hekili : Debug ( " Eclipse Advance (Pre): %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
if not ( eclipse.state == " IN_SOLAR " or eclipse.state == " IN_LUNAR " or eclipse.state == " IN_BOTH " ) then
if eclipse.starfire_counter == 0 and ( eclipse.state == " SOLAR_NEXT " or eclipse.state == " ANY_NEXT " ) then
applyBuff ( " eclipse_solar " , class.auras . eclipse_solar.duration + buff.eclipse_solar . remains )
state : RemoveAuraExpiration ( " eclipse_solar " )
state : QueueAuraExpiration ( " eclipse_solar " , ExpireEclipseSolar , buff.eclipse_solar . expires )
if talent.solstice . enabled then applyBuff ( " solstice " ) end
if legendary.balance_of_all_things . enabled then applyBuff ( " balance_of_all_things_nature " , nil , 5 , 8 ) end
eclipse.state = " IN_SOLAR "
eclipse.starfire_counter = 0
eclipse.wrath_counter = 2
if Hekili.ActiveDebug then Hekili : Debug ( " Eclipse Advance (Post): %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
return
end
if eclipse.wrath_counter == 0 and ( eclipse.state == " LUNAR_NEXT " or eclipse.state == " ANY_NEXT " ) then
applyBuff ( " eclipse_lunar " , class.auras . eclipse_lunar.duration + buff.eclipse_lunar . remains )
if set_bonus.tier28_2pc > 0 then applyDebuff ( " target " , " fury_of_elune_ap " ) end
state : RemoveAuraExpiration ( " eclipse_lunar " )
state : QueueAuraExpiration ( " eclipse_lunar " , ExpireEclipseLunar , buff.eclipse_lunar . expires )
if talent.solstice . enabled then applyBuff ( " solstice " ) end
if legendary.balance_of_all_things . enabled then applyBuff ( " balance_of_all_things_nature " , nil , 5 , 8 ) end
eclipse.state = " IN_LUNAR "
eclipse.wrath_counter = 0
eclipse.starfire_counter = 2
if Hekili.ActiveDebug then Hekili : Debug ( " Eclipse Advance (Post): %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
return
end
end
if eclipse.state == " IN_SOLAR " then eclipse.state = " LUNAR_NEXT " end
if eclipse.state == " IN_LUNAR " then eclipse.state = " SOLAR_NEXT " end
if eclipse.state == " IN_BOTH " then eclipse.state = " ANY_NEXT " end
if Hekili.ActiveDebug then Hekili : Debug ( " Eclipse Advance (Post): %s - Starfire(%d), Wrath(%d), Solar(%.2f), Lunar(%.2f) " , eclipse.state , eclipse.starfire_counter , eclipse.wrath_counter , buff.eclipse_solar . remains , buff.eclipse_lunar . remains ) end
end , state )
} , {
__index = function ( t , k )
-- any_next
if k == " any_next " then
return eclipse.state == " ANY_NEXT "
-- in_any
elseif k == " in_any " then
return eclipse.state == " IN_SOLAR " or eclipse.state == " IN_LUNAR " or eclipse.state == " IN_BOTH "
-- in_solar
elseif k == " in_solar " then
return eclipse.state == " IN_SOLAR "
-- in_lunar
elseif k == " in_lunar " then
return eclipse.state == " IN_LUNAR "
-- in_both
elseif k == " in_both " then
return eclipse.state == " IN_BOTH "
-- solar_next
elseif k == " solar_next " then
return eclipse.state == " SOLAR_NEXT "
-- solar_in
elseif k == " solar_in " then
return eclipse.starfire_counter
-- solar_in_2
elseif k == " solar_in_2 " then
return eclipse.starfire_counter == 2
-- solar_in_1
elseif k == " solar_in_1 " then
return eclipse.starfire_counter == 1
-- lunar_next
elseif k == " lunar_next " then
return eclipse.state == " LUNAR_NEXT "
-- lunar_in
elseif k == " lunar_in " then
return eclipse.wrath_counter
-- lunar_in_2
elseif k == " lunar_in_2 " then
return eclipse.wrath_counter == 2
-- lunar_in_1
elseif k == " lunar_in_1 " then
return eclipse.wrath_counter == 1
end
end
} ) )
spec : RegisterStateTable ( " druid " , setmetatable ( { } , {
__index = function ( t , k )
if k == " catweave_bear " then return false
elseif k == " owlweave_bear " then return false
elseif k == " primal_wrath " then return debuff.rip
elseif k == " lunar_inspiration " then return debuff.moonfire_cat
elseif k == " no_cds " then return not toggle.cooldowns
elseif k == " delay_berserking " then return settings.delay_berserking
elseif rawget ( debuff , k ) ~= nil then return debuff [ k ] end
return false
end
} ) )
local LycarasHandler = setfenv ( function ( )
if buff.travel_form . up then state : RunHandler ( " stampeding_roar " )
elseif buff.moonkin_form . up then state : RunHandler ( " starfall " )
elseif buff.bear_form . up then state : RunHandler ( " barkskin " )
elseif buff.cat_form . up then state : RunHandler ( " primal_wrath " )
else state : RunHandler ( " wild_growth " ) end
end , state )
local SinfulHysteriaHandler = setfenv ( function ( )
applyBuff ( " ravenous_frenzy_sinful_hysteria " )
end , state )
spec : RegisterHook ( " reset_precast " , function ( )
if IsActiveSpell ( class.abilities . new_moon.id ) then active_moon = " new_moon "
elseif IsActiveSpell ( class.abilities . half_moon.id ) then active_moon = " half_moon "
elseif IsActiveSpell ( class.abilities . full_moon.id ) then active_moon = " full_moon "
else active_moon = nil end
-- UGLY
if talent.incarnation . enabled then
rawset ( cooldown , " ca_inc " , cooldown.incarnation )
rawset ( buff , " ca_inc " , buff.incarnation )
else
rawset ( cooldown , " ca_inc " , cooldown.celestial_alignment )
rawset ( buff , " ca_inc " , buff.celestial_alignment )
end
if buff.warrior_of_elune . up then
setCooldown ( " warrior_of_elune " , 3600 )
end
eclipse.reset ( )
if buff.lycaras_fleeting_glimpse . up then
state : QueueAuraExpiration ( " lycaras_fleeting_glimpse " , LycarasHandler , buff.lycaras_fleeting_glimpse . expires )
end
if legendary.sinful_hysteria . enabled and buff.ravenous_frenzy . up then
state : QueueAuraExpiration ( " ravenous_frenzy " , SinfulHysteriaHandler , buff.ravenous_frenzy . expires )
end
end )
spec : RegisterHook ( " step " , function ( )
if Hekili.ActiveDebug then Hekili : Debug ( " Eclipse State: %s, Wrath: %d, Starfire: %d; Lunar: %.2f, Solar: %.2f \n " , eclipse.state or " NOT SET " , eclipse.wrath_counter , eclipse.starfire_counter , buff.eclipse_lunar . remains , buff.eclipse_solar . remains ) end
end )
spec : RegisterHook ( " spend " , function ( amt , resource )
if legendary.primordial_arcanic_pulsar . enabled and resource == " astral_power " and amt > 0 then
local v1 = ( buff.primordial_arcanic_pulsar . v1 or 0 ) + amt
if v1 >= 300 then
applyBuff ( talent.incarnation . enabled and " incarnation " or " celestial_alignment " , 9 )
v1 = v1 - 300
end
if v1 > 0 then
applyBuff ( " primordial_arcanic_pulsar " , nil , max ( 1 , floor ( amt / 30 ) ) )
buff.primordial_arcanic_pulsar . v1 = v1
else
removeBuff ( " primordial_arcanic_pulsar " )
end
end
end )
-- Tier 28
spec : RegisterGear ( " tier28 " , 188853 , 188851 , 188849 , 188848 , 188847 )
spec : RegisterSetBonuses ( " tier28_2pc " , 364423 , " tier28_4pc " , 363497 )
-- 2-Set - Celestial Pillar - Entering Lunar Eclipse creates a Fury of Elune at 25% effectiveness that follows your current target for 8 sec.
-- 4-Set - Umbral Infusion - While in an Eclipse, the cost of Starsurge and Starfall is reduced by 20%.
-- Legion Sets (for now).
spec : RegisterGear ( " tier21 " , 152127 , 152129 , 152125 , 152124 , 152126 , 152128 )
spec : RegisterAura ( " solar_solstice " , {
id = 252767 ,
duration = 6 ,
max_stack = 1 ,
} )
spec : RegisterGear ( " tier20 " , 147136 , 147138 , 147134 , 147133 , 147135 , 147137 )
spec : RegisterGear ( " tier19 " , 138330 , 138336 , 138366 , 138324 , 138327 , 138333 )
spec : RegisterGear ( " class " , 139726 , 139728 , 139723 , 139730 , 139725 , 139729 , 139727 , 139724 )
spec : RegisterGear ( " impeccable_fel_essence " , 137039 )
spec : RegisterGear ( " oneths_intuition " , 137092 )
spec : RegisterAuras ( {
oneths_intuition = {
id = 209406 ,
duration = 3600 ,
max_stacks = 1 ,
} ,
oneths_overconfidence = {
id = 209407 ,
duration = 3600 ,
max_stacks = 1 ,
} ,
} )
spec : RegisterGear ( " radiant_moonlight " , 151800 )
spec : RegisterGear ( " the_emerald_dreamcatcher " , 137062 )
spec : RegisterAura ( " the_emerald_dreamcatcher " , {
id = 224706 ,
duration = 5 ,
max_stack = 2 ,
} )
-- Abilities
spec : RegisterAbilities ( {
barkskin = {
id = 22812 ,
cast = 0 ,
cooldown = function ( ) return 60 * ( 1 + ( conduit.tough_as_bark . mod * 0.01 ) ) end ,
gcd = " off " ,
toggle = " defensives " ,
defensive = true ,
startsCombat = false ,
texture = 136097 ,
handler = function ( )
applyBuff ( " barkskin " )
end ,
} ,
bear_form = {
id = 5487 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = - 25 ,
spendType = " rage " ,
startsCombat = false ,
texture = 132276 ,
noform = " bear_form " ,
handler = function ( )
shift ( " bear_form " )
if conduit.ursine_vigor . enabled then applyBuff ( " ursine_vigor " ) end
end ,
auras = {
-- Conduit
ursine_vigor = {
id = 340541 ,
duration = 4 ,
max_stack = 1
}
}
} ,
cat_form = {
id = 768 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 132115 ,
noform = " cat_form " ,
handler = function ( )
shift ( " cat_form " )
end ,
auras = {
-- Conduit
tireless_pursuit = {
id = 340546 ,
duration = function ( ) return conduit.tireless_pursuit . enabled and conduit.tireless_pursuit . mod or 3 end ,
max_stack = 1 ,
}
}
} ,
celestial_alignment = {
id = 194223 ,
cast = 0 ,
cooldown = function ( ) return ( essence.vision_of_perfection . enabled and 0.85 or 1 ) * 180 end ,
gcd = " off " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 136060 ,
notalent = " incarnation " ,
handler = function ( )
applyBuff ( " celestial_alignment " )
stat.haste = stat.haste + 0.1
eclipse.trigger_both ( 20 )
if pvptalent.moon_and_stars . enabled then applyBuff ( " moon_and_stars " ) end
end ,
copy = " ca_inc "
} ,
cyclone = {
id = 33786 ,
cast = function ( ) return pvptalent.owlkin_adept . enabled and buff.owlkin_frenzy . up and 0.85 or 1.7 end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.1 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136022 ,
handler = function ( )
applyDebuff ( " target " , " cyclone " )
end ,
} ,
dash = {
id = 1850 ,
cast = 0 ,
cooldown = 120 ,
gcd = " off " ,
startsCombat = false ,
texture = 132120 ,
notalent = " tiger_dash " ,
handler = function ( )
if not buff.cat_form . up then
shift ( " cat_form " )
end
applyBuff ( " dash " )
end ,
} ,
entangling_roots = {
id = 339 ,
cast = function ( ) return pvptalent.owlkin_adept . enabled and buff.owlkin_frenzy . up and 0.85 or 1.7 end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.06 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136100 ,
handler = function ( )
applyDebuff ( " target " , " entangling_roots " )
end ,
} ,
faerie_swarm = {
id = 209749 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
pvptalent = " faerie_swarm " ,
startsCombat = true ,
texture = 538516 ,
handler = function ( )
applyDebuff ( " target " , " faerie_swarm " )
end ,
} ,
ferocious_bite = {
id = 22568 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 50 ,
spendType = " energy " ,
startsCombat = true ,
texture = 132127 ,
form = " cat_form " ,
usable = function ( ) return combo_points.current > 0 end ,
handler = function ( )
--[[ if target.health.pct < 25 and debuff.rip.up then
applyDebuff ( " target " , " rip " , min ( debuff.rip . duration * 1.3 , debuff.rip . remains + debuff.rip . duration ) )
end ] ]
spend ( combo_points.current , " combo_points " )
end ,
} ,
--[[ flap = {
id = 164862 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = true ,
texture = 132925 ,
handler = function ( )
end ,
} , ] ]
force_of_nature = {
id = 205636 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
spend = - 20 ,
spendType = " astral_power " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 132129 ,
talent = " force_of_nature " ,
ap_check = function ( ) return check_for_ap_overcap ( " force_of_nature " ) end ,
handler = function ( )
summonPet ( " treants " , 10 )
end ,
} ,
frenzied_regeneration = {
id = 22842 ,
cast = 0 ,
charges = function ( ) return ( talent.guardian_affinity . enabled and buff.heart_of_the_wild . up ) and 2 or nil end ,
cooldown = 36 ,
recharge = 36 ,
gcd = " spell " ,
spend = 10 ,
spendType = " rage " ,
startsCombat = false ,
texture = 132091 ,
form = " bear_form " ,
talent = " guardian_affinity " ,
handler = function ( )
applyBuff ( " frenzied_regeneration " )
gain ( 0.08 * health.max , " health " )
end ,
} ,
full_moon = {
id = 274283 ,
known = 274281 ,
cast = 3 ,
charges = 3 ,
cooldown = 20 ,
recharge = 20 ,
gcd = " spell " ,
spend = - 40 ,
spendType = " astral_power " ,
texture = 1392542 ,
startsCombat = true ,
talent = " new_moon " ,
bind = " half_moon " ,
ap_check = function ( ) return check_for_ap_overcap ( " full_moon " ) end ,
usable = function ( ) return active_moon == " full_moon " end ,
handler = function ( )
spendCharges ( " new_moon " , 1 )
spendCharges ( " half_moon " , 1 )
-- Radiant Moonlight, NYI.
active_moon = " new_moon "
end ,
} ,
fury_of_elune = {
id = 202770 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
-- toggle = "cooldowns",
startsCombat = true ,
texture = 132123 ,
handler = function ( )
if not buff.moonkin_form . up then unshift ( ) end
applyDebuff ( " target " , " fury_of_elune_ap " )
end ,
} ,
growl = {
id = 6795 ,
cast = 0 ,
cooldown = 8 ,
gcd = " off " ,
startsCombat = true ,
texture = 132270 ,
form = " bear_form " ,
handler = function ( )
applyDebuff ( " target " , " growl " )
end ,
} ,
half_moon = {
id = 274282 ,
known = 274281 ,
cast = 2 ,
charges = 3 ,
cooldown = 20 ,
recharge = 20 ,
gcd = " spell " ,
spend = - 20 ,
spendType = " astral_power " ,
texture = 1392543 ,
startsCombat = true ,
talent = " new_moon " ,
bind = " new_moon " ,
ap_check = function ( ) return check_for_ap_overcap ( " half_moon " ) end ,
usable = function ( ) return active_moon == " half_moon " end ,
handler = function ( )
spendCharges ( " new_moon " , 1 )
spendCharges ( " full_moon " , 1 )
active_moon = " full_moon "
end ,
} ,
heart_of_the_wild = {
id = 319454 ,
cast = 0 ,
cooldown = function ( ) return 300 * ( 1 - ( conduit.born_of_the_wilds . mod * 0.01 ) ) end ,
gcd = " spell " ,
toggle = " cooldowns " ,
talent = " heart_of_the_wild " ,
startsCombat = true ,
texture = 135879 ,
handler = function ( )
applyBuff ( " heart_of_the_wild " )
if talent.feral_affinity . enabled then
shift ( " cat_form " )
elseif talent.guardian_affinity . enabled then
shift ( " bear_form " )
elseif talent.restoration_affinity . enabled then
unshift ( )
end
end ,
} ,
hibernate = {
id = 2637 ,
cast = 1.5 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.15 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136090 ,
handler = function ( )
applyDebuff ( " target " , " hibernate " )
end ,
} ,
incarnation = {
id = 102560 ,
cast = 0 ,
cooldown = function ( ) return ( essence.vision_of_perfection . enabled and 0.85 or 1 ) * 180 end ,
gcd = " off " ,
spend = - 40 ,
spendType = " astral_power " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 571586 ,
talent = " incarnation " ,
handler = function ( )
shift ( " moonkin_form " )
applyBuff ( " incarnation " )
stat.crit = stat.crit + 0.10
stat.haste = stat.haste + 0.10
eclipse.trigger_both ( 20 )
if pvptalent.moon_and_stars . enabled then applyBuff ( " moon_and_stars " ) end
end ,
copy = { " incarnation_chosen_of_elune " , " Incarnation " } ,
} ,
innervate = {
id = 29166 ,
cast = 0 ,
cooldown = 180 ,
gcd = " off " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 136048 ,
usable = function ( ) return group end ,
handler = function ( )
active_dot.innervate = 1
end ,
auras = {
innervate = {
id = 29166 ,
duration = 10 ,
max_stack = 1
}
}
} ,
ironfur = {
id = 192081 ,
cast = 0 ,
cooldown = 0.5 ,
gcd = " spell " ,
spend = 45 ,
spendType = " rage " ,
startsCombat = true ,
texture = 1378702 ,
handler = function ( )
applyBuff ( " ironfur " )
end ,
} ,
maim = {
id = 22570 ,
cast = 0 ,
cooldown = 20 ,
gcd = " spell " ,
talent = " feral_affinity " ,
spend = 30 ,
spendType = " energy " ,
startsCombat = true ,
texture = 132134 ,
usable = function ( ) return combo_points.current > 0 , " requires combo points " end ,
handler = function ( )
applyDebuff ( " target " , " maim " )
spend ( combo_points.current , " combo_points " )
end ,
} ,
mangle = {
id = 33917 ,
cast = 0 ,
cooldown = 6 ,
gcd = " spell " ,
spend = - 10 ,
spendType = " rage " ,
startsCombat = true ,
texture = 132135 ,
form = " bear_form " ,
handler = function ( )
end ,
} ,
mass_entanglement = {
id = 102359 ,
cast = 0 ,
cooldown = function ( ) return 30 * ( 1 - ( conduit.born_of_the_wilds . mod * 0.01 ) ) end ,
gcd = " spell " ,
startsCombat = false ,
texture = 538515 ,
talent = " mass_entanglement " ,
handler = function ( )
applyDebuff ( " target " , " mass_entanglement " )
active_dot.mass_entanglement = max ( active_dot.mass_entanglement , active_enemies )
end ,
} ,
mighty_bash = {
id = 5211 ,
cast = 0 ,
cooldown = function ( ) return 50 * ( 1 - ( conduit.born_of_the_wilds . mod * 0.01 ) ) end ,
gcd = " spell " ,
startsCombat = true ,
texture = 132114 ,
talent = " mighty_bash " ,
handler = function ( )
applyDebuff ( " target " , " mighty_bash " )
end ,
} ,
moonfire = {
id = 8921 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = - 2 ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 136096 ,
cycle = " moonfire " ,
ap_check = function ( ) return check_for_ap_overcap ( " moonfire " ) end ,
handler = function ( )
if not buff.moonkin_form . up and not buff.bear_form . up then unshift ( ) end
applyDebuff ( " target " , " moonfire " )
if talent.twin_moons . enabled and active_enemies > 1 then
active_dot.moonfire = min ( active_enemies , active_dot.moonfire + 1 )
end
end ,
} ,
moonkin_form = {
id = 24858 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 136036 ,
noform = " moonkin_form " ,
essential = true ,
handler = function ( )
shift ( " moonkin_form " )
end ,
} ,
new_moon = {
id = 274281 ,
cast = 1 ,
charges = 3 ,
cooldown = 20 ,
recharge = 20 ,
gcd = " spell " ,
spend = - 10 ,
spendType = " astral_power " ,
texture = 1392545 ,
startsCombat = true ,
talent = " new_moon " ,
bind = " full_moon " ,
ap_check = function ( ) return check_for_ap_overcap ( " new_moon " ) end ,
usable = function ( ) return active_moon == " new_moon " end ,
handler = function ( )
spendCharges ( " half_moon " , 1 )
spendCharges ( " full_moon " , 1 )
active_moon = " half_moon "
end ,
} ,
prowl = {
id = 5215 ,
cast = 0 ,
cooldown = 6 ,
gcd = " spell " ,
startsCombat = false ,
texture = 514640 ,
usable = function ( ) return time == 0 end ,
handler = function ( )
shift ( " cat_form " )
applyBuff ( " prowl " )
removeBuff ( " shadowmeld " )
end ,
} ,
rake = {
id = 1822 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 35 ,
spendType = " energy " ,
startsCombat = true ,
texture = 132122 ,
talent = " feral_affinity " ,
form = " cat_form " ,
handler = function ( )
applyDebuff ( " target " , " rake " )
end ,
} ,
regrowth = {
id = 8936 ,
cast = 1.5 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.17 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136085 ,
handler = function ( )
if buff.moonkin_form . down then unshift ( ) end
applyBuff ( " regrowth " )
end ,
} ,
rejuvenation = {
id = 774 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.11 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136081 ,
talent = " restoration_affinity " ,
handler = function ( )
if buff.moonkin_form . down then unshift ( ) end
applyBuff ( " rejuvenation " )
end ,
} ,
remove_corruption = {
id = 2782 ,
cast = 0 ,
cooldown = 8 ,
gcd = " spell " ,
spend = 0.06 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135952 ,
handler = function ( )
end ,
} ,
renewal = {
id = 108238 ,
cast = 0 ,
cooldown = 90 ,
gcd = " spell " ,
startsCombat = true ,
texture = 136059 ,
talent = " renewal " ,
handler = function ( )
gain ( 0.3 * health.max , " health " )
end ,
} ,
--[[ revive = {
id = 50769 ,
cast = 10 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.04 ,
spendType = " mana " ,
startsCombat = true ,
texture = 132132 ,
handler = function ( )
end ,
} , ] ]
rip = {
id = 1079 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 30 ,
spendType = " energy " ,
startsCombat = true ,
texture = 132152 ,
talent = " feral_affinity " ,
form = " cat_form " ,
usable = function ( ) return combo_points.current > 0 end ,
handler = function ( )
spend ( combo_points.current , " combo_points " )
applyDebuff ( " target " , " rip " )
end ,
} ,
shred = {
id = 5221 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 40 ,
spendType = " energy " ,
startsCombat = true ,
texture = 136231 ,
form = " cat_form " ,
handler = function ( )
gain ( 1 , " combo_points " )
end ,
} ,
solar_beam = {
id = 78675 ,
cast = 0 ,
cooldown = 60 ,
gcd = " off " ,
spend = 0.17 ,
spendType = " mana " ,
toggle = " interrupts " ,
startsCombat = true ,
texture = 252188 ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
if buff.moonkin_form . down then unshift ( ) end
interrupt ( )
end ,
} ,
soothe = {
id = 2908 ,
cast = 0 ,
cooldown = 10 ,
gcd = " spell " ,
spend = 0.06 ,
spendType = " mana " ,
startsCombat = true ,
texture = 132163 ,
usable = function ( ) return buff.dispellable_enrage . up end ,
handler = function ( )
if buff.moonkin_form . down then unshift ( ) end
removeBuff ( " dispellable_enrage " )
end ,
} ,
stag_form = {
id = 210053 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 1394966 ,
noform = " travel_form " ,
handler = function ( )
shift ( " stag_form " )
end ,
} ,
stampeding_roar = {
id = 106898 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
startsCombat = false ,
texture = 464343 ,
handler = function ( )
if buff.bear_form . down and buff.cat_form . down then
shift ( " bear_form " )
end
applyBuff ( " stampeding_roar " )
end ,
} ,
starfall = {
id = 191034 ,
cast = 0 ,
cooldown = function ( ) return talent.stellar_drift . enabled and 12 or 0 end ,
gcd = " spell " ,
spend = function ( ) return ( buff.oneths_perception . up and 0 or 50 ) * ( 1 - ( buff.timeworn_dreambinder . stack * 0.1 ) ) * ( set_bonus.tier28_4pc > 0 and ( buff.eclipse_solar . up or buff.eclipse_lunar . up ) and 0.85 or 1 ) end ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 236168 ,
ap_check = function ( ) return check_for_ap_overcap ( " starfall " ) end ,
handler = function ( )
if talent.starlord . enabled then
if buff.starlord . stack < 3 then stat.haste = stat.haste + 0.04 end
addStack ( " starlord " , buff.starlord . remains > 0 and buff.starlord . remains or nil , 1 )
end
applyBuff ( " starfall " )
if level > 53 then
if debuff.moonfire . up then debuff.moonfire . expires = debuff.moonfire . expires + 4 end
if debuff.sunfire . up then debuff.sunfire . expires = debuff.sunfire . expires + 4 end
end
removeBuff ( " oneths_perception " )
if legendary.timeworn_dreambinder . enabled then
addStack ( " timeworn_dreambinder " , nil , 1 )
end
end ,
} ,
starfire = {
id = function ( ) return state.spec . balance and 194153 or 197628 end ,
known = function ( ) return state.spec . balance and IsPlayerSpell ( 194153 ) or IsPlayerSpell ( 197628 ) end ,
cast = function ( )
if buff.warrior_of_elune . up or buff.elunes_wrath . up or buff.owlkin_frenzy . up then return 0 end
return haste * ( buff.eclipse_lunar and ( level > 46 and 0.8 or 0.92 ) or 1 ) * 2.25
end ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return ( buff.warrior_of_elune . up and 1.4 or 1 ) * - 8 end ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 135753 ,
ap_check = function ( ) return check_for_ap_overcap ( " starfire " ) end ,
talent = function ( ) return ( not state.spec . balance and " balance_affinity " or nil ) end ,
handler = function ( )
if not buff.moonkin_form . up then unshift ( ) end
if eclipse.state == " ANY_NEXT " or eclipse.state == " SOLAR_NEXT " then
eclipse.starfire_counter = eclipse.starfire_counter - 1
eclipse.advance ( )
end
if level > 53 then
if debuff.moonfire . up then debuff.moonfire . expires = debuff.moonfire . expires + 4 end
if debuff.sunfire . up then debuff.sunfire . expires = debuff.sunfire . expires + 4 end
end
if buff.elunes_wrath . up then
removeBuff ( " elunes_wrath " )
elseif buff.warrior_of_elune . up then
removeStack ( " warrior_of_elune " )
if buff.warrior_of_elune . down then
setCooldown ( " warrior_of_elune " , 45 )
end
elseif buff.owlkin_frenzy . up then
removeStack ( " owlkin_frenzy " )
end
if azerite.dawning_sun . enabled then applyBuff ( " dawning_sun " ) end
end ,
copy = { 194153 , 197628 }
} ,
starsurge = {
id = 78674 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return ( buff.oneths_clear_vision . up and 0 or 30 ) * ( 1 - ( buff.timeworn_dreambinder . stack * 0.1 ) ) * ( set_bonus.tier28_4pc > 0 and ( buff.eclipse_solar . up or buff.eclipse_lunar . up ) and 0.85 or 1 ) end ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 135730 ,
ap_check = function ( ) return check_for_ap_overcap ( " starsurge " ) end ,
handler = function ( )
if talent.starlord . enabled then
if buff.starlord . stack < 3 then stat.haste = stat.haste + 0.04 end
addStack ( " starlord " , buff.starlord . remains > 0 and buff.starlord . remains or nil , 1 )
end
removeBuff ( " oneths_clear_vision " )
removeBuff ( " sunblaze " )
if buff.eclipse_solar . up then buff.eclipse_solar . empowerTime = query_time ; applyBuff ( " starsurge_empowerment_solar " ) end
if buff.eclipse_lunar . up then buff.eclipse_lunar . empowerTime = query_time ; applyBuff ( " starsurge_empowerment_lunar " ) end
if pvptalent.moonkin_aura . enabled then
addStack ( " moonkin_aura " , nil , 1 )
end
if azerite.arcanic_pulsar . enabled then
addStack ( " arcanic_pulsar " )
if buff.arcanic_pulsar . stack == 9 then
removeBuff ( " arcanic_pulsar " )
applyBuff ( " ca_inc " , 6 )
eclipse.trigger_both ( 6 )
end
end
if legendary.timeworn_dreambinder . enabled then
addStack ( " timeworn_dreambinder " , nil , 1 )
end
end ,
auras = {
starsurge_empowerment_lunar = {
duration = 3600 ,
max_stack = 30 ,
generate = function ( t )
local last = action.starsurge . lastCast
t.name = " Starsurge Empowerment (Lunar) "
if eclipse.in_any then
t.applied = last
t.duration = buff.eclipse_lunar . expires - last
t.expires = t.applied + t.duration
t.count = 1
t.caster = " player "
return
end
t.applied = 0
t.duration = 0
t.expires = 0
t.count = 0
t.caster = " nobody "
end ,
copy = " starsurge_lunar "
} ,
starsurge_empowerment_solar = {
duration = 3600 ,
max_stack = 30 ,
generate = function ( t )
local last = action.starsurge . lastCast
t.name = " Starsurge Empowerment (Solar) "
if eclipse.in_any then
t.applied = last
t.duration = buff.eclipse_solar . expires - last
t.expires = t.applied + t.duration
t.count = 1
t.caster = " player "
return
end
t.applied = 0
t.duration = 0
t.expires = 0
t.count = 0
t.caster = " nobody "
end ,
copy = " starsurge_solar "
}
}
} ,
stellar_flare = {
id = 202347 ,
cast = 1.5 ,
cooldown = 0 ,
gcd = " spell " ,
spend = - 8 ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 1052602 ,
cycle = " stellar_flare " ,
talent = " stellar_flare " ,
ap_check = function ( ) return check_for_ap_overcap ( " stellar_flare " ) end ,
handler = function ( )
applyDebuff ( " target " , " stellar_flare " )
end ,
} ,
sunfire = {
id = 93402 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = - 2 ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 236216 ,
cycle = " sunfire " ,
ap_check = function ( )
return astral_power.current - action.sunfire . cost + ( talent.shooting_stars . enabled and 4 or 0 ) + ( talent.natures_balance . enabled and ceil ( execute_time / 1.5 ) or 0 ) < astral_power.max
end ,
readyTime = function ( )
return mana [ " time_to_ " .. ( 0.12 * mana.max ) ]
end ,
handler = function ( )
spend ( 0.12 * mana.max , " mana " ) -- I want to see AP in mouseovers.
applyDebuff ( " target " , " sunfire " )
active_dot.sunfire = active_enemies
end ,
} ,
swiftmend = {
id = 18562 ,
cast = 0 ,
charges = 1 ,
cooldown = 25 ,
recharge = 25 ,
gcd = " spell " ,
spend = 0.14 ,
spendType = " mana " ,
startsCombat = false ,
texture = 134914 ,
talent = " restoration_affinity " ,
handler = function ( )
if buff.moonkin_form . down then unshift ( ) end
gain ( health.max * 0.1 , " health " )
end ,
} ,
--[[ May want to revisit this and split out swipe_cat from swipe_bear.
swipe_bear = {
id = 213764 ,
cast = 0 ,
cooldown = function ( ) return haste * ( buff.cat_form . up and 0 or 6 ) end ,
gcd = " spell " ,
spend = function ( ) return buff.cat_form . up and 40 or nil end ,
spendType = function ( ) return buff.cat_form . up and " energy " or nil end ,
startsCombat = true ,
texture = 134296 ,
talent = " feral_affinity " ,
usable = function ( ) return buff.cat_form . up or buff.bear_form . up end ,
handler = function ( )
if buff.cat_form . up then
gain ( 1 , " combo_points " )
end
end ,
copy = { " swipe " , 106785 , 213771 } ,
bind = { " swipe " , " swipe_bear " , " swipe_cat " }
} , ] ]
thrash_bear = {
id = 106832 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = - 5 ,
spendType = " rage " ,
cycle = " thrash_bear " ,
startsCombat = true ,
texture = 451161 ,
talent = " guardian_affinity " ,
form = " bear_form " ,
handler = function ( )
applyDebuff ( " target " , " thrash_bear " , nil , debuff.thrash . stack + 1 )
end ,
copy = { " thrash " , 106832 } ,
bind = { " thrash " , " thrash_bear " , " thrash_cat " }
} ,
tiger_dash = {
id = 252216 ,
cast = 0 ,
cooldown = 45 ,
gcd = " off " ,
startsCombat = false ,
texture = 1817485 ,
talent = " tiger_dash " ,
handler = function ( )
shift ( " cat_form " )
applyBuff ( " tiger_dash " )
end ,
} ,
thorns = {
id = 305497 ,
cast = 0 ,
cooldown = 45 ,
gcd = " spell " ,
pvptalent = function ( )
if essence.conflict_and_strife . enabled then return end
return " thorns "
end ,
spend = 0.12 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136104 ,
handler = function ( )
applyBuff ( " thorns " )
end ,
} ,
travel_form = {
id = 783 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 132144 ,
noform = " travel_form " ,
handler = function ( )
shift ( " travel_form " )
end ,
} ,
treant_form = {
id = 114282 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = false ,
texture = 132145 ,
handler = function ( )
shift ( " treant_form " )
end ,
} ,
typhoon = {
id = 132469 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
startsCombat = true ,
texture = 236170 ,
talent = " typhoon " ,
handler = function ( )
applyDebuff ( " target " , " typhoon " )
if target.distance < 15 then setDistance ( target.distance + 5 ) end
end ,
} ,
ursols_vortex = {
id = 102793 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
talent = " restoration_affinity " ,
startsCombat = true ,
texture = 571588 ,
handler = function ( )
end ,
} ,
warrior_of_elune = {
id = 202425 ,
cast = 0 ,
cooldown = 45 ,
gcd = " spell " ,
startsCombat = true ,
texture = 135900 ,
talent = " warrior_of_elune " ,
usable = function ( ) return buff.warrior_of_elune . down end ,
handler = function ( )
applyBuff ( " warrior_of_elune " , nil , 3 )
end ,
} ,
--[[ wartime_ability = {
id = 264739 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1518639 ,
handler = function ( )
end ,
} , ] ]
wild_charge = {
id = function ( ) return buff.moonkin_form . up and 102383 or 102401 end ,
known = 102401 ,
cast = 0 ,
cooldown = 15 ,
gcd = " spell " ,
startsCombat = false ,
-- texture = 538771,
talent = " wild_charge " ,
handler = function ( )
if buff.moonkin_form . up then setDistance ( target.distance + 10 ) end
end ,
copy = { 102401 , 102383 }
} ,
wild_growth = {
id = 48438 ,
cast = 1.5 ,
cooldown = 10 ,
gcd = " spell " ,
spend = 0.3 ,
spendType = " mana " ,
startsCombat = false ,
texture = 236153 ,
talent = " wild_growth " ,
handler = function ( )
unshift ( )
applyBuff ( " wild_growth " )
end ,
} ,
wrath = {
id = 190984 ,
known = function ( ) return state.spec . balance and IsPlayerSpell ( 190984 ) or IsPlayerSpell ( 5176 ) end ,
cast = function ( ) return haste * ( buff.eclipse_solar . up and ( level > 46 and 0.8 or 0.92 ) or 1 ) * 1.5 end ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return ( talent.soul_of_the_forest . enabled and buff.eclipse_solar . up ) and - 9 or - 6 end ,
spendType = " astral_power " ,
startsCombat = true ,
texture = 535045 ,
ap_check = function ( ) return check_for_ap_overcap ( " solar_wrath " ) end ,
velocity = 20 ,
impact = function ( )
if not state.spec . balance and ( eclipse.state == " ANY_NEXT " or eclipse.state == " LUNAR_NEXT " ) then
eclipse.wrath_counter = eclipse.wrath_counter - 1
eclipse.advance ( )
end
end ,
handler = function ( )
if not buff.moonkin_form . up then unshift ( ) end
if state.spec . balance and ( eclipse.state == " ANY_NEXT " or eclipse.state == " LUNAR_NEXT " ) then
eclipse.wrath_counter = eclipse.wrath_counter - 1
eclipse.advance ( )
end
removeBuff ( " dawning_sun " )
if azerite.sunblaze . enabled then applyBuff ( " sunblaze " ) end
end ,
copy = { " solar_wrath " , 5176 }
} ,
} )
spec : RegisterOptions ( {
enabled = true ,
aoe = 3 ,
nameplates = false ,
nameplateRange = 8 ,
damage = true ,
damageDots = true ,
damageExpiration = 6 ,
enhancedRecheck = true ,
potion = " spectral_intellect " ,
package = " Balance " ,
} )
spec : RegisterSetting ( " starlord_cancel " , false , {
name = " Cancel |T462651:0|t Starlord " ,
desc = " If checked, the addon will recommend canceling your Starlord buff before starting to build stacks with Starsurge again. \n \n " ..
" You will likely want a |cFFFFD100/cancelaura Starlord|r macro to manage this during combat. " ,
icon = 462651 ,
iconCoords = { 0.1 , 0.9 , 0.1 , 0.9 } ,
type = " toggle " ,
width = " full "
} )
spec : RegisterSetting ( " delay_berserking " , false , {
name = " Delay |T135727:0|t Berserking " ,
desc = " If checked, the default priority will attempt to adjust the timing of |T135727:0|t Berserking to be consistent with simmed Power Infusion usage. " ,
type = " toggle " ,
width = " full " ,
} )
-- Starlord Cancel Override
class.specs [ 0 ] . abilities.cancel_buff . funcs.usable = setfenv ( function ( )
if not settings.starlord_cancel and args.buff_name == " starlord " then return false , " starlord cancel option disabled " end
return args.buff_name ~= nil , " no buff name detected "
end , state )
spec : RegisterPack ( " Balance " , 20220911 , [ [ Hekili : S33AZjoswI ( BXXgnfySXGW4YvhL9g1ZD7E7xB76o99tglarHUfiXijSlVHd ( TFZZ5KVvMscm1m9mZgXmDz0JuzEYZ7x5TdU9t3EZSWIOB ) LG ( bb9F1Gb9gmyWLJgD7nfpUo62Bwho9lHFM9hjHRy ) 33 gUmmzkE9hxMgodE ) 80 nzWLwuuSo ) 7 p7Sj0ZCAE8QP9 ( CCXInt6fNEg ) vp9M4vV7SvZ6TOy1Y ) 95 XlJUI ) c9k ( AXT3mzt8YIFi52jUNydU9MWnflsZU9gyGyF14zZIOhpkFQCgU9U3NTjE22F8MO1frRMeLT9Ubdoz7DWWT9h3 ( JVBryYNJY ) ( T ) 4 PBV7nSXy227UjDzi75EBu4QE41PhIDNIWSphvmoE ( 27 MgMhLZUsk7pFC6YOX09YP343JwLEp8gBssIMgLNhM9427UpmloCYs49Ah3lQhBESol6 ( X5S3nFd713E3PxtxRN8ADOr8n3NYwhW9yF5I4KpV9U ) ilSyX27GztCXlGjZc2i8qwkCZpmDz868i6L ) 5 WVWUZ7stUpf ( d85UzDCwCb7Tc3E3Y4IILSRTknJ9FNVm6RXtGF3gg7ht3S9UfHZsErb7FJlGV227yBRBwweMeLUjFjBT9qmmxE7V ( MpT9UUSVveBzwehUKnZxg ) 5 KvrjfNGZt2Ii ) lXR7OpZwLMZgYxmp ( ZlkgNfTkmoj ) fSNBAucdKLctY1RHVcaUNKMZUa ( SS ) nnz5J0q9PSOq2O8P0vSrmLnXF7YWfM ) 3 qA5MVoAko1kYIt ( sub9 ( ) 66 Oea ) qS1GGxT ) 9 g2oY84SOoS5B4mj0klkpEzmB5rZUOWm2VydZ00vtclof2h5FGpg ) 1 T39FfNmldWm ( WQ1PpeLTcFZPlIM ( f2IkL9IV79m0MCg1MoQ027MbiY9sshpDwo ) faKTT ) 4 Bsssly0iSXuI1 ) MF7Nau0eg0c2qt3KWUlaDomuNlJZlYbI ( ueMX ( RFb5HW2Uy4nZU9TmYZPfXPj3EZda0JOkZIxtx73iKygvOejoeNGeqMtkKYM938jbM1Va73myyye ) HFBkGQbamXgd7xmm7ShIZzSHyFTIig52T30MTPWjgwUHHpnoj6RSr6PNuxpozCor0BD1jPW3w ) IHjpYhagEqloX6GEpqld2foIFTa6A3wW4D5b2KZN4wZ224GKTjjIHpWqd4G ( XPZhhUC54IfmQ ) 8E8 XJMDhb4B3ZUusrVeKkAoaO43IHVdVhNbf ( vzd027UIXmu ( qfHlJG3oSyddLESy ) w ( z6qpPg0ebzUHMiGExHMDeWVCgp2jPjBY7vWiLcUCCW6Pasxsed5 ) 2 BgbW0HvatreilGAJbNTCdkBvhyCxM9fabX8qgdujPJC ( Ja1jmzp6lphirQvxrmWX714EdJI6ygbcoyecypGuBm9mDL3sG6PF3oa0llEAbmLKtOPaqI ( XyGUNO ( htkcWP ) DSFKUMnArfQXri8d ( RLBy ) JpW51i4SLGoGJxc3FzA2mt8E5nzdfdSnllEErju2k ( qbwCMUjcKP8M0pqSFg2Ly ) KUPayaZgCoZhIN0n85e ) IbDn4aDpqCGqP48XHPrau68dbucz1bqjNtEMUiHG8IhweLOZBeLgGIVH5jFaHhlEkOeroijBz09HG4iuoeQLaxncUK3iK328OmucgbjO3NjJyji1d1hkeWsmw ( 0 KcGaJ2ziaQI0NNoJXLDvAAcTAG9vTBKVXZ1vItCChcnW6gZ3K9iWBiIXdt716LXwajmLDgpplk5 ) 5 r6ot2mFoJeACCY0EC9wq ( b6xF2ggzymGobVHy51JJuyUf ( x43fG ( Hc9cYjD8q9WcHfzCckRKnFjaEiPBiUHLhxSH ) 5 yyaWthk1ZHX3TykTxVjh2bJrfekEicqvGTTCJ9TeaKaBAx4HzltF68OSVWyGATo ( ) aOmVvExs3dC ( fbinG2zFKdgj80fSpEen1cNG67Cr ) VJP0v48caTsQ6kxnZ0WpXX ) KeCI79U3C2pKm1Pi1keronnD5S0hs6nL ( smXcrJZjvK7TzT85ASyesCGt8dG0DKqAHCoX ( NIfpYfAw ( QwdgmLexYcZuCV2EUTCE8AqWftGbtjZZrXgQfxECY8nlhV4XCegAY015I61GHv09z ) ZzcUU89vs40GEVc ) AwCTNZ ( pAkAWMi97naFqsN3zrldFC8enSj8rgkuAGa1kcljA7l9kYSDTBn2kHvpeXpCMnOVQ6TlUKkY0MwCRBgRpcbJ8TqT0ToTqqjekigeCtIZrB4yx ) 32 SmhuqBDw6usjAImejrNtQAZPf3imSjzMIWFDk ( Vmy8L7m ) 8 PrXlr4B7sRZtjW ) P60Jw7qDqKRbx2h ) t2 ( 1 ooCoiV9m2e9zwy8SXrazyVWzZye4FfS9rdfP8mnC2JnJVc ) r7iO59SKVgyuZW6wZunKzM3yRvj8Uk80PcdVLFftnB9 ) ng23EEufSQMjfa67xHTjwyTVlC50nWaHAKeb80bzuiXUK3Fs6daQniZMXXf ( bkseqozRy4YKvLKCWqqL2WvmtFlibo8XPRGMOK8oX6LnZEKjbHHC ) QDg5UTq1QEGo1JlshplosYxb3QSqOazWSBpsI01Us5c89gf3qleUSqWi9SuaC0PSA0gA3yYeZPmh5h08fTz7Z0OC0UicX5cSzFo3Qw1LeLzmdwNfVIPDoqleMXu ) nE641iFp1C5u61KakW62 ) 6 M41RJygASA9Jmy7YXSXiHCRst3Dk9QMaSlEjoHBVdanDZJR8ZOZrrUuYt3WupVaCB44SntE01kXsNi5hX ( Dhp88rx2FGfkW5L ) OSBonBtbSag ) x3W ( eBwXiTUpMdiLFa ) pNoQT8XlsrFMXy5WErCopC0OHbdmynDoN3J ( ( jWgJzKaZ2v2RbYmiyGAGnV ) 4 Hx8YGZnxNb8H1Iz31LzSAGzg0xSbYNtT1KIZmRMPm ( yPk6kNYu1JmudPv4fZIbeaBSyYqdJ2TLZYDKnEN6NqbLMnbvpBc ( woB4a8YwLWTycvPKlPa91kxebx0aPmex ( ZS0nOfzP4LI42Da2eIUUL ) 60 Ra2yZ4QZW6OBAPdftwGHaNzmGtYSyHUud6VZYBa ) nXiqNeNai4zmPGJZJI ( suMj ) 2 YiSb973iDoj ( ua90PCEVMFgMD0GNRpgXa6OPoSZhduZ4sCOA3i2E8H1RvYBS3rdtEuIJLZ3QqhMt7ppegtXob9WbSB9HnRxKYgosxy9DhJfWy4nX9iBhDx2U3pWzlV9UFvk5iOFE00CWA75PCJYfiBiofmDYtLkQxiu0bCBi7rwl0P3Ln0IOYvsCGUfpE18JZwRvtv8t986CXkdSAcQqFb ( vZqfg63CVAXLh ( sfvuzafSXA7G1YBS3qIcreOFhfJEX3 ( DvB5VwMXw1 ( 6 f ( DYqRAe ( 70 b4ngb5Is4hM6wxJbp0i0Pc1sBS15vzZd9zKyPvA ) EFtn20vYPiBZuMsj5mn9VhCY ) KiLU3ptd ( n0NYT ( OnrNZRLQG4IWHqfAKABg7AvQ3M5xUULAF94FyHUdKMEd2Z0qgCNzMWCM2wrzjGvVmM ) ZTd ( Zr8DcVp ) 4 ZLo5Rrpyl ) ( pkq3qU9fy10nK6rJgouYiXlWcaX7EKj ( BOd0aDIh1tQnYWEevi ( wtwMMoB5M8cbDfxJLEKNFQ ( zBePCx ( ODC92t0CJjUsTzRmtZ3oKcHRoeZ ) 8 W2Xsa6Bw ( q4J5C5I ) W ) 97 nDxpjQ0xqcmckXF1wPz7ikjqy9t3OZDqXouFGDXPuqhvX4cth7yL4qnIfHmqhG6 ) RztukpicCbNAL ) qm46ey ) MB2BzgBUDfHtndqJPTymz4ijn0ajFilhkzjeXLEFoDJLp3luNQek2PZsleX5Rxr8uksa0hcVLr0eKpaFvuDihGhQIaTouFkiIbPXCOP8RnOSQ6bBT7Yog2xmvSduunK8NRl ( 1 dAhGzBhofX7Wn3YoC0FAby9lAbmGfr ( 0 LzL2KuG1fylgpHUwH5agglwPn2m4FHUHCIWpdAoptx1zb ) d0spPRIXFHdeYpja ( z ( si0iWxa06bIOkLpkAwlI5qK7PGtEg2EE4ORe5UWr16iKdRpGAAadBxNSwnPN
end