-- MageFrost.lua
-- June 2018
local addon , ns = ...
local Hekili = _G [ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
local FindUnitBuffByID = ns.FindUnitBuffByID
local abs = math.abs
-- Conduits
-- [-] ice_bite
-- [-] icy_propulsion
-- [-] shivering_core
-- [-] unrelenting_cold
if UnitClassBase ( ' player ' ) == ' MAGE ' then
local spec = Hekili : NewSpecialization ( 64 , true )
-- spec:RegisterResource( Enum.PowerType.ArcaneCharges )
spec : RegisterResource ( Enum.PowerType . Mana )
-- Talents
spec : RegisterTalents ( {
bone_chilling = 22457 , -- 205027
lonely_winter = 22460 , -- 205024
ice_nova = 22463 , -- 157997
glacial_insulation = 22442 , -- 235297
shimmer = 22443 , -- 212653
ice_floes = 23073 , -- 108839
incanters_flow = 22444 , -- 1463
focus_magic = 22445 , -- 321358
rune_of_power = 22447 , -- 116011
frozen_touch = 22452 , -- 205030
chain_reaction = 22466 , -- 278309
ebonbolt = 22469 , -- 257537
frigid_winds = 22446 , -- 235224
ice_ward = 22448 , -- 205036
ring_of_frost = 22471 , -- 113724
freezing_rain = 22454 , -- 270233
splitting_ice = 23176 , -- 56377
comet_storm = 22473 , -- 153595
thermal_void = 21632 , -- 155149
ray_of_frost = 22309 , -- 205021
glacial_spike = 21634 , -- 199786
} )
-- PvP Talents
spec : RegisterPvpTalents ( {
burst_of_cold = 633 , -- 206431
chilled_to_the_bone = 66 , -- 198126
concentrated_coolness = 632 , -- 198148
deep_shatter = 68 , -- 198123
frostbite = 67 , -- 198120
ice_form = 634 , -- 198144
ice_wall = 5390 , -- 352278
netherwind_armor = 3443 , -- 198062
prismatic_cloak = 3532 , -- 198064
} )
-- Auras
spec : RegisterAuras ( {
alter_time = {
id = 110909 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
active_blizzard = {
duration = function ( ) return 8 * haste end ,
max_stack = 1 ,
generate = function ( t )
if query_time - action.blizzard . lastCast < 8 * haste then
t.count = 1
t.applied = action.blizzard . lastCast
t.expires = t.applied + ( 8 * haste )
t.caster = " player "
return
end
t.count = 0
t.applied = 0
t.expires = 0
t.caster = " nobody "
end ,
} ,
arcane_intellect = {
id = 1459 ,
duration = 3600 ,
type = " Magic " ,
max_stack = 1 ,
shared = " player " , -- use anyone's buff on the player, not just player's.
} ,
blink = {
id = 1953 ,
} ,
blizzard = {
id = 12486 ,
duration = 3 ,
max_stack = 1 ,
} ,
bone_chilling = {
id = 205766 ,
duration = 8 ,
max_stack = 10 ,
} ,
brain_freeze = {
id = 190446 ,
duration = 15 ,
max_stack = 1 ,
} ,
chain_reaction = {
id = 278310 ,
duration = 10 ,
max_stack = 5 ,
} ,
chilled = {
id = 205708 ,
duration = 8 ,
type = " Magic " ,
max_stack = 1 ,
} ,
cone_of_cold = {
id = 212792 ,
duration = 5 ,
type = " Magic " ,
max_stack = 1 ,
} ,
fingers_of_frost = {
id = 44544 ,
duration = 15 ,
max_stack = 2 ,
} ,
flurry = {
id = 228354 ,
duration = 1 ,
type = " Magic " ,
max_stack = 1 ,
} ,
focus_magic = {
id = 321358 ,
duration = 1800 ,
max_stack = 1 ,
friendly = true ,
} ,
focus_magic_buff = {
id = 321363 ,
duration = 10 ,
max_stack = 1 ,
} ,
freezing_rain = {
id = 270232 ,
duration = 12 ,
max_stack = 1 ,
} ,
freeze = {
id = 33395 ,
duration = 8 ,
max_stack = 1
} ,
frost_nova = {
id = 122 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
frostbolt = {
id = 59638 ,
duration = 4 ,
type = " Magic " ,
max_stack = 1 ,
} ,
frozen_orb = {
duration = 10 ,
max_stack = 1 ,
generate = function ( )
local fo = buff.frozen_orb
if query_time - action.frozen_orb . lastCast < 10 then
fo.count = 1
fo.applied = action.frozen_orb . lastCast
fo.expires = fo.applied + 10
fo.caster = " player "
return
end
fo.count = 0
fo.applied = 0
fo.expires = 0
fo.caster = " nobody "
end ,
} ,
frozen_orb_snare = {
id = 289308 ,
duration = 3 ,
max_stack = 1 ,
} ,
glacial_spike = {
id = 228600 ,
duration = 4 ,
max_stack = 1 ,
} ,
hypothermia = {
id = 41425 ,
duration = 30 ,
max_stack = 1 ,
} ,
ice_barrier = {
id = 11426 ,
duration = 60 ,
type = " Magic " ,
max_stack = 1 ,
} ,
ice_block = {
id = 45438 ,
duration = 10 ,
type = " Magic " ,
max_stack = 1 ,
} ,
ice_floes = {
id = 108839 ,
duration = 15 ,
type = " Magic " ,
max_stack = 1 ,
} ,
ice_nova = {
id = 157997 ,
duration = 2 ,
type = " Magic " ,
max_stack = 1 ,
} ,
icicles = {
id = 205473 ,
duration = 60 ,
max_stack = 5 ,
} ,
icy_veins = {
id = 12472 ,
duration = function ( ) return talent.thermal_void . enabled and 30 or 20 + ( level > 55 and 3 or 0 ) end ,
type = " Magic " ,
max_stack = 1 ,
} ,
incanters_flow = {
id = 116267 ,
duration = 3600 ,
max_stack = 5 ,
meta = {
stack = function ( ) return state.incanters_flow_stacks end ,
stacks = function ( ) return state.incanters_flow_stacks end ,
}
} ,
preinvisibility = {
id = 66 ,
duration = 3 ,
max_stack = 1 ,
} ,
invisibility = {
id = 32612 ,
duration = 20 ,
max_stack = 1
} ,
mirror_image = {
id = 55342 ,
duration = 40 ,
max_stack = 3 ,
generate = function ( )
local mi = buff.mirror_image
if action.mirror_image . lastCast > 0 and query_time < action.mirror_image . lastCast + 40 then
mi.count = 1
mi.applied = action.mirror_image . lastCast
mi.expires = mi.applied + 40
mi.caster = " player "
return
end
mi.count = 0
mi.applied = 0
mi.expires = 0
mi.caster = " nobody "
end ,
} ,
polymorph = {
id = 118 ,
duration = 60 ,
max_stack = 1
} ,
ray_of_frost = {
id = 205021 ,
duration = 5 ,
max_stack = 1 ,
} ,
rune_of_power = {
id = 116014 ,
duration = 12 ,
max_stack = 1 ,
} ,
shatter = {
id = 12982 ,
} ,
shimmer = {
id = 212653 ,
} ,
slow_fall = {
id = 130 ,
duration = 30 ,
max_stack = 1 ,
} ,
temporal_displacement = {
id = 80354 ,
duration = 600 ,
max_stack = 1 ,
} ,
winters_chill = {
id = 228358 ,
duration = 6 ,
type = " Magic " ,
max_stack = 2 ,
} ,
frozen = {
duration = 1 ,
meta = {
spell = function ( t )
if debuff.winters_chill . up and remaining_winters_chill > 0 then return debuff.winters_chill end
return debuff.frost_nova
end ,
up = function ( t )
return t.spell . up
end ,
down = function ( t )
return t.spell . down
end ,
applied = function ( t )
return t.spell . applied
end ,
remains = function ( t )
return t.spell . remains
end ,
count = function ( t )
return t.spell . count
end ,
stack = function ( t )
return t.spell . stack
end ,
stacks = function ( t )
return t.spell . stacks
end ,
}
} ,
roll_the_bones = {
alias = rtb_buff_list ,
aliasMode = " first " , -- use duration info from the first buff that's up, as they should all be equal.
aliasType = " buff " ,
duration = 30 ,
} ,
-- Azerite Powers (overrides)
frigid_grasp = {
id = 279684 ,
duration = 20 ,
max_stack = 1 ,
} ,
overwhelming_power = {
id = 266180 ,
duration = 25 ,
max_stack = 25 ,
} ,
tunnel_of_ice = {
id = 277904 ,
duration = 300 ,
max_stack = 3
} ,
-- Legendaries
cold_front = {
id = 327327 ,
duration = 30 ,
max_stack = 30
} ,
cold_front_ready = {
id = 327330 ,
duration = 30 ,
max_stack = 1
} ,
expanded_potential = {
id = 327495 ,
duration = 300 ,
max_stack = 1
} ,
freezing_winds = {
id = 327478 ,
duration = 30 ,
max_stack = 1
} ,
slick_ice = {
id = 327509 ,
duration = 60 ,
max_stack = 10
}
} )
spec : RegisterTotem ( " rune_of_power " , 609815 )
spec : RegisterStateExpr ( " fingers_of_frost_active " , function ( )
return false
end )
spec : RegisterStateFunction ( " fingers_of_frost " , function ( active )
fingers_of_frost_active = active
end )
spec : RegisterStateExpr ( " remaining_winters_chill " , function ( )
if debuff.winters_chill . down then return 0 end
return max ( 0 , debuff.winters_chill . stack - ( state : IsInFlight ( " ice_lance " ) and 1 or 0 ) )
end )
spec : RegisterStateTable ( " ground_aoe " , {
frozen_orb = setmetatable ( { } , {
__index = setfenv ( function ( t , k )
if k == " remains " then
return buff.frozen_orb . remains
end
end , state )
} ) ,
blizzard = setmetatable ( { } , {
__index = setfenv ( function ( t , k )
if k == " remains " then return buff.active_blizzard . remains end
end , state )
} )
} )
spec : RegisterStateTable ( " frost_info " , {
last_target_actual = " nobody " ,
last_target_virtual = " nobody " ,
watching = true ,
real_brain_freeze = false ,
virtual_brain_freeze = false
} )
local brain_freeze_removed = 0
local lastCometCast = 0
local lastAutoComet = 0
spec : RegisterHook ( " COMBAT_LOG_EVENT_UNFILTERED " , function ( event , _ , subtype , _ , sourceGUID , sourceName , _ , _ , destGUID , destName , destFlags , _ , spellID , spellName )
if sourceGUID == GUID then
if subtype == " SPELL_CAST_SUCCESS " then
if spellID == 116 then
frost_info.last_target_actual = destGUID
end
if spellID == 44614 then
frost_info.real_brain_freeze = FindUnitBuffByID ( " player " , 190446 ) ~= nil
end
elseif subtype == " SPELL_AURA_REMOVED " and spellID == 190446 then
brain_freeze_removed = GetTime ( )
end
if ( spellID == 153595 or spellID == 153596 ) then
local t = GetTime ( )
if subtype == " SPELL_CAST_SUCCESS " then
lastCometCast = t
elseif subtype == " SPELL_DAMAGE " and t - lastCometCast > 3 and t - lastAutoComet > 3 then
-- TODO: Revisit strategy for detecting auto comets.
lastAutoComet = t
end
end
end
end )
spec : RegisterStateExpr ( " brain_freeze_active " , function ( )
return frost_info.virtual_brain_freeze
end )
spec : RegisterStateTable ( " rotation " , setmetatable ( { } ,
{
__index = function ( t , k )
if k == " standard " then return true end
return false
end ,
} ) )
spec : RegisterStateTable ( " incanters_flow " , {
changed = 0 ,
count = 0 ,
direction = 0 ,
startCount = 0 ,
startTime = 0 ,
startIndex = 0 ,
values = {
[ 0 ] = { 0 , 1 } ,
{ 1 , 1 } ,
{ 2 , 1 } ,
{ 3 , 1 } ,
{ 4 , 1 } ,
{ 5 , 0 } ,
{ 5 , - 1 } ,
{ 4 , - 1 } ,
{ 3 , - 1 } ,
{ 2 , - 1 } ,
{ 1 , 0 }
} ,
f = CreateFrame ( " Frame " ) ,
fRegistered = false ,
reset = setfenv ( function ( )
if talent.incanters_flow . enabled then
if not incanters_flow.fRegistered then
Hekili : ProfileFrame ( " Incanters_Flow_Frost " , incanters_flow.f )
-- One-time setup.
incanters_flow.f : RegisterUnitEvent ( " UNIT_AURA " , " player " )
incanters_flow.f : SetScript ( " OnEvent " , function ( )
-- Check to see if IF changed.
if state.talent . incanters_flow.enabled then
local flow = state.incanters_flow
local name , _ , count = FindUnitBuffByID ( " player " , 116267 , " PLAYER " )
local now = GetTime ( )
if name then
if count ~= flow.count then
if count == 1 then flow.direction = 0
elseif count == 5 then flow.direction = 0
else flow.direction = ( count > flow.count ) and 1 or - 1 end
flow.changed = GetTime ( )
flow.count = count
end
else
flow.count = 0
flow.changed = GetTime ( )
flow.direction = 0
end
end
end )
incanters_flow.fRegistered = true
end
if now - incanters_flow.changed >= 1 then
if incanters_flow.count == 1 and incanters_flow.direction == 0 then
incanters_flow.direction = 1
incanters_flow.changed = incanters_flow.changed + 1
elseif incanters_flow.count == 5 and incanters_flow.direction == 0 then
incanters_flow.direction = - 1
incanters_flow.changed = incanters_flow.changed + 1
end
end
if incanters_flow.count == 0 then
incanters_flow.startCount = 0
incanters_flow.startTime = incanters_flow.changed + floor ( now - incanters_flow.changed )
incanters_flow.startIndex = 0
else
incanters_flow.startCount = incanters_flow.count
incanters_flow.startTime = incanters_flow.changed + floor ( now - incanters_flow.changed )
incanters_flow.startIndex = 0
for i , val in ipairs ( incanters_flow.values ) do
if val [ 1 ] == incanters_flow.count and val [ 2 ] == incanters_flow.direction then incanters_flow.startIndex = i ; break end
end
end
else
incanters_flow.count = 0
incanters_flow.changed = 0
incanters_flow.direction = 0
end
end , state ) ,
} )
spec : RegisterStateExpr ( " bf_flurry " , function ( ) return false end )
-- Tier 28
spec : RegisterSetBonuses ( " tier28_2pc " , 363535 , " tier28_4pc " , 364544 )
-- 2-Set - Frost Storm - Your spells have a 25% chance to call down a Comet Storm on your target enemy. This effect cannot occur more than once every 20 sec.
-- 4-Set - Frost Storm - Enemies hit by Comet Storm take 2% increased damage from your Frost Spells, up to 10% for 8 sec.
spec : RegisterAura ( " frost_storm " , {
id = 363544 ,
duration = 8 ,
max_stack = 5 ,
} )
-- Track ICD?
spec : RegisterAbility ( " frost_storm " , {
cast = 0 ,
cooldown = 20 ,
gcd = " off " ,
unlisted = true ,
known = function ( ) return set_bonus.tier28_2pc > 0 end ,
} )
spec : RegisterHook ( " reset_precast " , function ( )
if pet.rune_of_power . up then applyBuff ( " rune_of_power " , pet.rune_of_power . remains )
else removeBuff ( " rune_of_power " ) end
frost_info.last_target_virtual = frost_info.last_target_actual
frost_info.virtual_brain_freeze = frost_info.real_brain_freeze
-- Icicles take a second to get used.
if now - action.ice_lance . lastCast < gcd.execute then removeBuff ( " icicles " ) end
if abs ( now - brain_freeze_removed ) < 1 then applyDebuff ( " target " , " winters_chill " ) end
if prev_gcd [ 1 ] . flurry and now - action.flurry . lastCast < gcd.execute and debuff.winters_chill . up then debuff.winters_chill . count = 2 end
incanters_flow.reset ( )
if Hekili.ActiveDebug then
Hekili : Debug ( " Ice Lance in-flight? %s \n Winter's Chill Actual Stacks? %d \n remaining_winters_chill: %d " , state : IsInFlight ( " ice_lance " ) and " Yes " or " No " , state.debuff . winters_chill.stack , state.remaining_winters_chill )
end
if set_bonus.tier28_3pc > 0 and now - lastAutoComet < 20 then
setCooldown ( " frost_storm " , lastAutoComet + 20 - now )
end
end )
Hekili : EmbedDisciplinaryCommand ( spec )
-- Abilities
spec : RegisterAbilities ( {
arcane_intellect = {
id = 1459 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.04 ,
spendType = " mana " ,
nobuff = " arcane_intellect " ,
essential = true ,
startsCombat = false ,
texture = 135932 ,
handler = function ( )
applyBuff ( " arcane_intellect " )
end ,
} ,
blink = {
id = function ( ) return talent.shimmer . enabled and 212653 or 1953 end ,
cast = 0 ,
charges = function ( ) return talent.shimmer . enabled and 2 or nil end ,
cooldown = function ( ) return ( talent.shimmer . enabled and 20 or 15 ) - conduit.flow_of_time . mod * 0.001 end ,
recharge = function ( ) return ( talent.shimmer . enabled and ( 20 - conduit.flow_of_time . mod * 0.001 ) or nil ) end ,
gcd = " off " ,
discipline = " arcane " ,
spend = function ( ) return 0.02 * ( buff.arcane_power . up and ( talent.overpowered . enabled and 0.4 or 0.7 ) or 1 ) end ,
spendType = " mana " ,
startsCombat = false ,
texture = function ( ) return talent.shimmer . enabled and 135739 or 135736 end ,
handler = function ( )
if talent.displacement . enabled then applyBuff ( " displacement_beacon " ) end
end ,
copy = { 212653 , 1953 , " shimmer " }
} ,
blizzard = {
id = 190356 ,
cast = function ( ) return buff.freezing_rain . up and 0 or 2 * haste end ,
cooldown = 8 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135857 ,
velocity = 20 ,
handler = function ( )
applyDebuff ( " target " , " blizzard " )
applyBuff ( " active_blizzard " )
end ,
} ,
cold_snap = {
id = 235219 ,
cast = 0 ,
cooldown = function ( ) return level > 53 and 270 or 300 end ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 135865 ,
handler = function ( )
setCooldown ( " ice_barrier " , 0 )
setCooldown ( " frost_nova " , 0 )
setCooldown ( " cone_of_cold " , 0 )
setCooldown ( " ice_block " , 0 )
end ,
} ,
comet_storm = {
id = 153595 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 2126034 ,
talent = " comet_storm " ,
handler = function ( )
if set_bonus.tier28_4pc > 0 then
applyDebuff ( " target " , " frost_storm " )
active_dot.frost_storm = max ( 1 , active_enemies )
end
end ,
} ,
cone_of_cold = {
id = 120 ,
cast = 0 ,
cooldown = 12 ,
gcd = " spell " ,
spend = 0.04 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135852 ,
usable = function ( )
return target.distance <= 12
end ,
handler = function ( )
applyDebuff ( " target " , " cone_of_cold " )
active_dot.cone_of_cold = max ( active_enemies , active_dot.cone_of_cold )
end ,
} ,
--[[ conjure_refreshment = {
id = 190336 ,
cast = 3 ,
cooldown = 15 ,
gcd = " spell " ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = false ,
texture = 134029 ,
handler = function ( )
end ,
} , ] ]
counterspell = {
id = 2139 ,
cast = 0 ,
cooldown = function ( ) return 24 - ( conduit.grounding_surge . mod * 0.1 ) end ,
gcd = " off " ,
discipline = " arcane " ,
interrupt = true ,
toggle = function ( )
if runeforge.disciplinary_command . enabled then return end
return " interrupts "
end ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135856 ,
debuff = function ( )
if runeforge.disciplinary_command . enabled then return end
return " casting "
end ,
readyTime = function ( )
if runeforge.disciplinary_command . enabled then return end
return state.timeToInterrupt ( )
end ,
handler = function ( )
interrupt ( )
end ,
} ,
ebonbolt = {
id = 257537 ,
cast = 2.5 ,
cooldown = 45 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1392551 ,
velocity = 30 ,
handler = function ( )
applyBuff ( " brain_freeze " )
end ,
} ,
flurry = {
id = 44614 ,
cast = function ( )
if buff.brain_freeze . up then return 0 end
return 3 * haste
end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 1506795 ,
velocity = 50 ,
handler = function ( )
if buff.brain_freeze . up then
if buff.expanded_potential . up then removeBuff ( " expanded_potential " )
else
if legendary.sinful_delight . enabled then gainChargeTime ( " mirrors_of_torment " , 4 ) end
removeBuff ( " brain_freeze " )
end
frost_info.virtual_brain_freeze = true
else
frost_info.virtual_brain_freeze = false
end
removeBuff ( " cold_front_ready " )
if legendary.cold_front . enabled then
addStack ( " cold_front " )
if buff.cold_front . stack == 30 then
removeBuff ( " cold_front " )
applyBuff ( " cold_front_ready " )
end
end
applyDebuff ( " target " , " flurry " )
addStack ( " icicles " , nil , 1 )
if talent.bone_chilling . enabled then addStack ( " bone_chilling " , nil , 1 ) end
removeBuff ( " ice_floes " )
end ,
impact = function ( )
if frost_info.virtual_brain_freeze then
applyDebuff ( " target " , " winters_chill " , nil , 2 )
frost_info.virtual_brain_freeze = false
end
end ,
copy = 228354 -- ID of the Flurry impact.
} ,
focus_magic = {
id = 321358 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135754 ,
talent = " focus_magic " ,
usable = function ( ) return active_dot.focus_magic == 0 and group , " can apply one in a group " end ,
handler = function ( )
applyBuff ( " focus_magic " )
end ,
} ,
frost_nova = {
id = 122 ,
cast = 0 ,
charges = function ( ) return talent.ice_ward . enabled and 2 or nil end ,
cooldown = 30 ,
recharge = 30 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135848 ,
usable = function ( ) return not state.spec . frost or target.distance < 12 , " target out of range " end ,
handler = function ( )
applyDebuff ( " target " , " frost_nova " )
if legendary.grisly_icicle . enabled then applyDebuff ( " target " , " grisly_icicle " ) end
end ,
} ,
frostbolt = {
id = 116 ,
cast = function ( ) return 2 * ( 1 - 0.02 * buff.slick_ice . stack ) * haste end ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135846 ,
handler = function ( )
addStack ( " icicles " , nil , 1 )
applyDebuff ( " target " , " chilled " )
if talent.bone_chilling . enabled then addStack ( " bone_chilling " , nil , 1 ) end
removeBuff ( " ice_floes " )
removeBuff ( " cold_front_ready " )
if legendary.cold_front . enabled then
addStack ( " cold_front " )
if buff.cold_front . stack == 15 then
removeBuff ( " cold_front " )
applyBuff ( " cold_front_ready " )
end
end
if legendary.slick_ice . enabled then
addStack ( " slick_ice " , nil , 1 )
end
if azerite.tunnel_of_ice . enabled then
if frost_info.last_target_virtual == target.unit then
addStack ( " tunnel_of_ice " , nil , 1 )
else
removeBuff ( " tunnel_of_ice " )
end
frost_info.last_target_virtual = target.unit
end
end ,
} ,
frozen_orb = {
id = 84714 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
spend = 0.01 ,
spendType = " mana " ,
-- toggle = "cooldowns",
startsCombat = true ,
texture = 629077 ,
velocity = 20 ,
handler = function ( )
if talent.freezing_rain . enabled then applyBuff ( " freezing_rain " ) end
applyBuff ( " frozen_orb " )
end ,
--[[ Not modeling because you can throw it off in a random direction and get no procs. Just react.
impact = function ( )
addStack ( " fingers_of_frost " , nil , 1 )
applyDebuff ( " target " , " frozen_orb_snare " )
end , ] ]
copy = 198149
} ,
glacial_spike = {
id = 199786 ,
cast = 3 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 1698699 ,
talent = " glacial_spike " ,
velocity = 40 ,
usable = function ( ) return buff.icicles . stack >= 5 end ,
handler = function ( )
removeBuff ( " icicles " )
applyDebuff ( " target " , " glacial_spike " )
end ,
} ,
ice_barrier = {
id = 11426 ,
cast = 0 ,
cooldown = 25 ,
gcd = " spell " ,
defensive = true ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = false ,
texture = 135988 ,
handler = function ( )
applyBuff ( " ice_barrier " )
if legendary.triune_ward . enabled then
applyBuff ( " blazing_barrier " )
applyBuff ( " prismatic_barrier " )
end
end ,
} ,
ice_block = {
id = 45438 ,
cast = 0 ,
cooldown = function ( ) return 240 + ( conduit.winters_protection . mod * 0.001 ) end ,
gcd = " spell " ,
toggle = " defensives " ,
defensive = true ,
startsCombat = false ,
texture = 135841 ,
handler = function ( )
applyBuff ( " ice_block " )
applyDebuff ( " player " , " hypothermia " )
end ,
} ,
ice_floes = {
id = 108839 ,
cast = 0 ,
charges = 3 ,
cooldown = 20 ,
recharge = 20 ,
gcd = " spell " ,
startsCombat = false ,
texture = 610877 ,
talent = " ice_floes " ,
handler = function ( )
applyBuff ( " ice_floes " )
end ,
} ,
ice_lance = {
id = 30455 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135844 ,
velocity = 47 ,
handler = function ( )
if not talent.glacial_spike . enabled then removeStack ( " icicles " ) end
if buff.fingers_of_frost . up or debuff.frozen . up then
if talent.chain_reaction . enabled then addStack ( " chain_reaction " , nil , 1 ) end
if talent.thermal_void . enabled and buff.icy_veins . up then buff.icy_veins . expires = buff.icy_veins . expires + 1 end
end
removeStack ( " fingers_of_frost " )
applyDebuff ( " target " , " chilled " )
if talent.bone_chilling . enabled then addStack ( " bone_chilling " , nil , 1 ) end
if azerite.whiteout . enabled then
cooldown.frozen_orb . expires = max ( 0 , cooldown.frozen_orb . expires - 0.5 )
end
end ,
impact = function ( )
if debuff.winters_chill . up then
if debuff.winters_chill . stack > 1 then removeDebuffStack ( " target " , " winters_chill " , 1 )
else removeDebuff ( " target " , " winters_chill " ) end
end
end ,
copy = 228598
} ,
ice_nova = {
id = 157997 ,
cast = 0 ,
cooldown = 25 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1033909 ,
talent = " ice_nova " ,
handler = function ( )
applyDebuff ( " target " , " ice_nova " )
end ,
} ,
icy_veins = {
id = function ( )
return pvptalent.ice_form . enabled and 198144 or 12472
end ,
cast = 0 ,
cooldown = function ( ) return ( essence.vision_of_perfection . enabled and 0.87 or 1 ) * 180 end ,
gcd = " off " ,
toggle = " cooldowns " ,
startsCombat = false ,
handler = function ( )
if pvptalent.ice_form . enabled then
applyBuff ( " ice_form " )
else
applyBuff ( " icy_veins " )
stat.haste = stat.haste + 0.30
end
if azerite.frigid_grasp . enabled then
applyBuff ( " frigid_grasp " , 10 )
addStack ( " fingers_of_frost " , nil , 1 )
end
if talent.rune_of_power . enabled then
applyBuff ( " rune_of_power " )
end
end ,
copy = { 12472 , 198144 , " ice_form " } ,
auras = {
ice_form = {
id = 198144 ,
duration = 22 ,
max_stack = 1 ,
}
}
} ,
ice_form = {
id = 198144 ,
known = 12472 ,
cast = 0 ,
cooldown = function ( ) return ( essence.vision_of_perfection . enabled and 0.87 or 1 ) * 180 end ,
gcd = " off " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 135838 ,
pvptalent = " ice_form " ,
handler = function ( )
applyBuff ( " ice_form " )
if azerite.frigid_grasp . enabled then
applyBuff ( " frigid_grasp " , 10 )
addStack ( " fingers_of_frost " , nil , 1 )
end
if talent.rune_of_power . enabled then
applyBuff ( " rune_of_power " )
end
end ,
bind = " icy_veins "
} ,
invisibility = {
id = 66 ,
cast = 0 ,
cooldown = 300 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.03 ,
spendType = " mana " ,
toggle = " defensives " ,
defensive = true ,
startsCombat = false ,
texture = 132220 ,
handler = function ( )
applyBuff ( " preinvisibility " )
applyBuff ( " invisibility " , 23 )
if conduit.incantation_of_swiftness . enabled then applyBuff ( " incantation_of_swiftness " ) end
end ,
} ,
mirror_image = {
id = 55342 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.02 ,
spendType = " mana " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 135994 ,
handler = function ( )
applyBuff ( " mirror_image " , nil , 3 )
end ,
} ,
polymorph = {
id = 118 ,
cast = 1.7 ,
cooldown = 0 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.04 ,
spendType = " mana " ,
startsCombat = false ,
texture = 136071 ,
handler = function ( )
applyDebuff ( " target " , " polymorph " )
end ,
} ,
ray_of_frost = {
id = 205021 ,
cast = 5 ,
channeled = true ,
cooldown = 75 ,
gcd = " spell " ,
spend = 0.02 ,
spendType = " mana " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 1698700 ,
talent = " ray_of_frost " ,
start = function ( )
applyDebuff ( " target " , " ray_of_frost " )
end ,
} ,
remove_curse = {
id = 475 ,
cast = 0 ,
cooldown = 8 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = true ,
texture = 136082 ,
debuff = " dispellable_curse " ,
handler = function ( )
removeDebuff ( " player " , " dispellable_curse " )
end ,
} ,
ring_of_frost = {
id = 113724 ,
cast = 2 ,
cooldown = 45 ,
gcd = " spell " ,
spend = 0.08 ,
spendType = " mana " ,
startsCombat = true ,
texture = 464484 ,
talent = " ring_of_frost " ,
handler = function ( )
end ,
} ,
rune_of_power = {
id = 116011 ,
cast = 1.5 ,
charges = 2 ,
cooldown = 40 ,
recharge = 40 ,
gcd = " spell " ,
discipline = " arcane " ,
startsCombat = false ,
texture = 609815 ,
nobuff = " rune_of_power " ,
talent = " rune_of_power " ,
handler = function ( )
applyBuff ( " rune_of_power " )
end ,
} ,
slow_fall = {
id = 130 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.01 ,
spendType = " mana " ,
startsCombat = false ,
texture = 135992 ,
handler = function ( )
applyBuff ( " slow_fall " )
end ,
} ,
spellsteal = {
id = 30449 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
discipline = " arcane " ,
spend = 0.21 ,
spendType = " mana " ,
startsCombat = true ,
texture = 135729 ,
debuff = " stealable_magic " ,
handler = function ( )
removeDebuff ( " target " , " stealable_magic " )
end ,
} ,
water_elemental = {
id = 31687 ,
cast = 1.5 ,
cooldown = 30 ,
gcd = " spell " ,
spend = 0.03 ,
spendType = " mana " ,
startsCombat = false ,
texture = 135862 ,
notalent = " lonely_winter " ,
nomounted = true ,
usable = function ( ) return not pet.alive end ,
handler = function ( )
summonPet ( " water_elemental " )
end ,
copy = " summon_water_elemental "
} ,
time_warp = {
id = 80353 ,
cast = 0 ,
cooldown = 300 ,
gcd = " off " ,
discipline = " arcane " ,
spend = 0.04 ,
spendType = " mana " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 458224 ,
handler = function ( )
applyBuff ( " time_warp " )
applyDebuff ( " player " , " temporal_displacement " )
end ,
} ,
} )
spec : RegisterOptions ( {
enabled = true ,
aoe = 3 ,
nameplates = false ,
nameplateRange = 8 ,
damage = true ,
damageExpiration = 6 ,
potion = " phantom_fire " ,
package = " Frost Mage " ,
} )
spec : RegisterSetting ( " ignore_freezing_rain_st " , true , {
name = " Ignore |T629077:0|t Freezing Rain in Single-Target " ,
desc = " If checked, the default action list will not recommend using |T135857:0|t Blizzard in single-target due to the |T629077:0|t Freezing Rain talent proc. " ,
type = " toggle " ,
width = " full " ,
} )
spec : RegisterPack ( " Frost Mage " , 20211123 , [ [ dO063aqijr1JufvBsv4tIuJsK0PejEfHYSKKClqiSls ( fsXWqQ4yKQwMQipdPktdeQRPkkTnjr5BeQOXbcjNdeIwhsvnpKk19aP9bcoiHk1crk9qjrMiHk0frQeTrvrr ( isLuNuvuyLKkZKqv3KqLStvj ) ees1qvff1srQeEkOMki6ReQGXkj1Er8xrnyuDyPwSQ6XOmzjUm0MP0NLuJwvQtlSAqiLxJKy2uCBc2nv ) wPHJehhPsYYv55enDfxNu2oH8Dr04rs68iPwVKW8fH9dmrpbscCPhK86j68KE96FIEQN0tp690ZsGhQPGeyknJkDnsG9wajWpt3khaxC11ibMstTz7cbscSC1ogsGFpdfj9PHM6yER9vSvGgziOz6jwNDTDOrgcmAiWFTWmpdN8jWLEqYRNOZt61R ) j6PEsp9O3t6jWT28EpcmCiujc87OuqN8jWfuYiWIRUgb8NPBLdq3Rvek8XdW1tVQa8NOZt6b6a6Q072Rrj9b6GiaCXX1tpaE4mJwbbCAnHtfapCaxCTIqb0haxC ) mlEapvkRmMy9WRb8qc4nGtX0uJhGxqwiJ1tbOdIaWfxnvqaxUciGN2g1VN8HcD4Y0ao6ZfOeWBkumud4Zc4 ) vkbCBu ) EKa ( 6 gQveytihjbscCbTTMziqsEPNajbg9 ( BWcHwcm7IbVOjWvoGFAoA3RgvLqYckMW7J6mBfeAVOqV ) gSa4pa8c ( 1 SwfRLt41knka ( daVGFnRvXA5eET6qHoCjGt3aUEaprcaNTRPSjD1xZAZLqYckMW7J6mBfeAVOoSlud4pa8VM1QkHKfumH3h1z2ki0Ej3hRDuv2KobUztSobMTA ( GNKcAmKH86jcKey07VbleAjWnBI1jWS2yYnBI1ZMqoeytiNS3cibMvKKH8IEeijWO3Fdwi0sGB2eRtGzTXKB2eRNnHCiWMqozVfqcmkLOZqjziVGycKey07VbleAjWSlg8IMa3SjeHz0rHaLaoeGc40JalNlyd5LEcCZMyDcmRnMCZMy9SjKdb2eYj7TasG7fjd51ZsGKaJE ) nyHqlbMDXGx0e4MnHimJokeOeWPBaNEey5CbBiV0tGB2eRtGzTXKB2eRNnHCiWMqozVfqcSCid5vLrGKaJE ) nyHqlbUztSobM1gtUztSE2eYHaBc5K9wajWcRiua9HmKHat5q2k87Haj5LEcKe4MnX6e4 ( yTJ5Wh0yq2qGrV ) gSqOLmKxprGKa3SjwNaNSh8YObfqFAdbg9 ( BWcHwYqErpcKey07VbleAjWSlg8IMa3SjeHz0rHaLaoeGc4prGB2eRtG ) MOIk6RqgYliMajbg9 ( BWcHwcm7IbVOjWnBcrygDuiqjGdfW1tGB2eRtGT3kN ) AgYqgcCVibsYl9eijWnBI1jW2BRa98EFcm693GfcTKH86jcKe4MnX6e4VjQOI ( key07VbleAjd5f9iqsGrV ) gSqOLaZUyWlAcCQa ( HcD4HxNtg ( GNmZEhgdGdfWPdGNibGxWVM1Qsg ( GNmZEhgJQSjDapfa ) bGNkGt5qr5AwrPxH ) 1 ) Rza8eja8VM1Q ( xhE2EiwbQoSzdG ) aW ) AwRYgEnEY8AZ2BLJ6WMnaouaNoaEke4MnX6eyRr7oQjd5fetGKa3SjwNahmm7ROMaJE ) nyHqlziVEwcKe4MnX6ey2kGtwo7jqGrV ) gSqOLmKxvgbscm693GfcTey2fdErtG ) AwRYgEnEY8AZ2BLJ6WMnaEIeaEb ) AwRYEBfORouOdxc4qaWNRfHM8eciGNibGFOqhE415KHp4jZS3HXa4pa8c ( 1 SwvYWh8Kz27Wyuhk0HlbCia4Z1IqtEcbKa3SjwNahmmBANHKH8sCsGKaJE ) nyHqlbMDXGx0ey5Qz ( HxuSv43twalX0tSUc9 ( BWcbUztSob ( 6 s0 ( KLu6JkKH8cIIajbUztSobwiUBpzET5zpb0hcm693GfcTKH8cIKajbUztSobw ( oSt41zkBs8iWO3Fdwi0sgYl90Hajbg9 ( BWcHwcm7IbVOjWNMJ29Qrv9fsd15GfmdQqV ) gSa4pa8PVACugueAaC6gkGBqrObWFa4f8RzTk7TvGUQSjDcCZMyDcS9w5K9vutgYl96jqsGrV ) gSqOLaZUyWlAc8P5ODVAuvcjlOycVpQZSvqO9Ic9 ( BWcG ) aWz7AkBsx91S2CjKSGIj8 ( OoZwbH2lQd7c1a ( da ) RzTQsizbft49rDMTccTxY24qvzt6e4MnX6eyBCy ( BA5qgYl9prGKaJE ) nyHqlbMDXGx0eyH2Bff2a4qaWPhDa8haEZMqeMrhfcuc4qakGxza ( daVYb8tZr7E1OQ20SOnz711cOpsf693GfcCZMyDcCFS2XmsvkMvgRtgYl90JajbUztSobg ) R ) xZqGrV ) gSqOLmKx6HycKey07VbleAjWSlg8IMaFAoA3Rgv1MMfTjBVUwa9rQqV ) gSa4pa8ub8PnOpkjftmt415GHk07VblaEIeaEZMqeMrhfcuc4qakG ) SaEka ( daFUweAYtiGaoDd413Q5LCVO6BIkQOVI6qHoCjbUztSoboyy20odjd5L ( NLajbUztSob2ERC ( RziWO3Fdwi0sgYqGzfjbsYl9eijWO3Fdwi0sGB2eRtGLV7YMel59 ( 51 MN9eqFiWSlg8IMa ) 1 Sw1P5yETzkBs8uLnPtG9wajWY3DztIL8E ) 8 AZZEcOpKH86jcKey07VbleAjWSlg8IMat5qr51AZ1SIkyuNfHHlb8eja8 ) kLa ( da3g1VN8HcD4saNUbC6rhcCZMyDcmLDI1jd5f9iqsGB2eRtGlypV ) 75 ibg9 ( BWcHwYqEbXeijWO3Fdwi0sGzxm4fnbUzticZOJcbkbC6gWPhG ) aWtfWzRx0IrjdkVxhlzH2emuHE ) nybWtKaWLRM5hErLSLdAAVKPClLlWHAf693Gfapfa ) bG ) 1 Sw1 ) 6 WZ2dXkq1HnBaCOaoDiWnBI1jWcXD7jZRnp7jG ( qgYRNLajbg9 ( BWcHwcm7IbVOjWSDnLnPRcg1zry4s1HcD4sahcaU ( Na8ha ( xZAvNMJ51MPSjXtv2KobUztSob ( 0 CmV2mLnjEKH8QYiqsGrV ) gSqOLaZUyWlAc8xZAvNMJ51MPSjXtv2KoG ) aWtfW ) AwRkyuNfHHlvLnPd4jsa4tBqFuNMJ51MPSjXtHE ) nybWtbWFa4Pc4FnRvjnbJk5GHQYM0b8eja8MnHimJokeOeWHaua ) japfcCZMyDcCWOolcdxsgYlXjbscm693GfcTey2fdErtGpnhT7vJQbfOSxBYj7JIc9 ( BWcG ) aW ) AwRcP67wtoX6knka ( dapvaNYHIYR1MRzfvWOolcdxc4jsa4 ) vkb8haUnQFp5df6WLaoDd4qmDa8uiWnBI1jWtiG5K9rHmKxqueijWnBI1jWAsmhdkijWO3Fdwi0sgYliscKe4MnX6e4Vz3s2QDutGrV ) gSqOLmKx6PdbscCZMyDc8hpjEuj8Acm693GfcTKH8sVEcKe4MnX6eytu ) EKziAALAb0hcm693GfcTKH8s ) teijWnBI1jW24WVz3cbg9 ( BWcHwYqEPNEeijWnBI1jWTZq5CTjZAJHaJE ) nyHqlziV0dXeijWnBI1jW ) UoV28CbJkscm693GfcTKHmey5qGK8spbscm693GfcTey2fdErtGtfWpuOdp86CYWh8Kz27WyaCOaoDa8eja8c ( 1 SwvYWh8Kz27WyuLnPd4Pa4pa8ubCkhkkxZkk9k8V ( FndGNibG ) 1 Sw1 ) 6 WZ2dXkq1HnBa8haEQaoLdfLRzfLEvTPzrBYskbvqaprcaNYHIY1SIsVYERC ( Rza8haEQaELd4S1lAXOIdZRnpVXClzOxWIc9 ( BWcGNibGZ21u2KU66s0 ( KLu6JkQdf6WLaEIea ( P5ODVAuzpeRi86CYWlsf693GfapfaprcaNYHIY1SIsV66s0 ( KLu6JkaEIea ( xZAv2WRXtMxB2ERCuh2SbWHc40bWFa4Pc4f8RzTkH4U9K51MN9eqFuAua8eja8VM1QShIveEDoz4fPsJcGNibG ) 1 SwfsvkTxWsMYoOpr
end