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

2025 lines
63 KiB

-- DruidGuardian.lua
-- June 2018
local addon, ns = ...
local Hekili = _G[ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
-- Conduits
-- [x] savage_combatant
-- [ ] unchecked_aggression
-- Guardian Endurance
-- [-] layered_mane
-- [x] wellhoned_instincts
if UnitClassBase( "player" ) == "DRUID" then
local spec = Hekili:NewSpecialization( 104 )
spec:RegisterResource( Enum.PowerType.Rage, {
oakhearts_puny_quods = {
aura = "oakhearts_puny_quods",
last = function ()
local app = state.buff.oakhearts_puny_quods.applied
local t = state.query_time
return app + floor( t - app )
end,
interval = 1,
value = 10
},
raging_frenzy = {
aura = "frenzied_regeneration",
pvptalent = "raging_frenzy",
last = function ()
local app = state.buff.frenzied_regeneration.applied
local t = state.query_time
return app + floor( t - app )
end,
interval = 1,
value = 10 -- tooltip says 60, meaning this would be 20, but NOPE.
},
thrash_bear = {
aura = "thrash_bear",
talent = "blood_frenzy",
debuff = true,
last = function ()
return state.debuff.thrash_bear.applied + floor( ( state.query_time - state.debuff.thrash_bear.applied ) / class.auras.thrash_bear.tick_time ) * class.auras.thrash_bear.tick_time
end,
interval = function () return class.auras.thrash_bear.tick_time end,
value = function () return 2 * state.active_dot.thrash_bear end,
}
} )
spec:RegisterResource( Enum.PowerType.LunarPower )
spec:RegisterResource( Enum.PowerType.Mana )
spec:RegisterResource( Enum.PowerType.ComboPoints )
spec:RegisterResource( Enum.PowerType.Energy )
-- Talents
spec:RegisterTalents( {
brambles = 22419, -- 203953
blood_frenzy = 22418, -- 203962
bristling_fur = 22420, -- 155835
tiger_dash = 19283, -- 252216
renewal = 18570, -- 108238
wild_charge = 18571, -- 102401
balance_affinity = 22163, -- 197488
feral_affinity = 22156, -- 202155
restoration_affinity = 22159, -- 197492
mighty_bash = 21778, -- 5211
mass_entanglement = 18576, -- 102359
heart_of_the_wild = 18577, -- 319454
soul_of_the_forest = 21709, -- 158477
galactic_guardian = 21707, -- 203964
incarnation = 22388, -- 102558
earthwarden = 22423, -- 203974
survival_of_the_fittest = 21713, -- 203965
guardian_of_elune = 22390, -- 155578
rend_and_tear = 22426, -- 204053
lunar_beam = 22427, -- 204066
pulverize = 22425, -- 80313
} )
-- PvP Talents
spec:RegisterPvpTalents( {
alpha_challenge = 842, -- 207017
charging_bash = 194, -- 228431
demoralizing_roar = 52, -- 201664
den_mother = 51, -- 236180
emerald_slumber = 197, -- 329042
entangling_claws = 195, -- 202226
freedom_of_the_herd = 3750, -- 213200
grove_protection = 5410, -- 354654
malornes_swiftness = 1237, -- 236147
master_shapeshifter = 49, -- 236144
overrun = 196, -- 202246
raging_frenzy = 192, -- 236153
sharpened_claws = 193, -- 202110
toughness = 50, -- 201259
} )
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,
duration = 3600,
max_stack = 1,
},
astral_influence = {
id = 197524,
},
barkskin = {
id = 22812,
duration = 12,
max_stack = 1,
},
bear_form = {
id = 5487,
duration = 3600,
max_stack = 1,
},
berserk = {
id = 50334,
duration = 15,
max_stack = 1,
},
-- Alias for Berserk vs. Incarnation
berserk_bear = {
alias = { "berserk", "incarnation" },
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 15 end,
},
bristling_fur = {
id = 155835,
duration = 8,
max_stack = 1,
},
cat_form = {
id = 768,
duration = 3600,
max_stack = 1,
},
convoke_the_spirits = {
id = 323764,
duration = 4,
max_stack = 1,
},
dash = {
id = 1850,
duration = 10,
max_stack = 1,
},
earthwarden = {
id = 203975,
duration = 3600,
max_stack = 3,
},
entangling_roots = {
id = 339,
duration = 30,
type = "Magic",
max_stack = 1,
},
feline_swiftness = {
id = 131768,
},
flight_form = {
id = 276029,
duration = 3600,
max_stack = 1,
},
frenzied_regeneration = {
id = 22842,
duration = 3,
max_stack = 1,
},
galactic_guardian = {
id = 213708,
duration = 15,
max_stack = 1,
},
gore = {
id = 93622,
duration = 10,
max_stack = 1,
},
growl = {
id = 6795,
duration = 3,
max_stack = 1,
},
guardian_of_elune = {
id = 213680,
duration = 15,
max_stack = 1,
},
heart_of_the_wild = {
id = 319454,
duration = 45,
max_stack = 1,
copy = { 319451, 319452, 319453 }
},
hibernate = {
id = 2637,
duration = 40,
max_stack = 1,
},
immobilized = {
id = 45334,
duration = 4,
max_stack = 1,
},
incapacitating_roar = {
id = 99,
duration = 3,
max_stack = 1,
},
incarnation = {
id = 102558,
duration = 30,
max_stack = 1,
copy = "incarnation_guardian_of_ursoc"
},
intimidating_roar = {
id = 236748,
duration = 3,
max_stack = 1,
},
ironfur = {
id = 192081,
duration = function () return buff.guardian_of_elune.up and 9 or 7 end,
max_stack = 5,
},
lightning_reflexes = {
id = 231065,
},
mass_entanglement = {
id = 102359,
duration = 30,
type = "Magic",
max_stack = 1,
},
mighty_bash = {
id = 5211,
duration = 4,
max_stack = 1,
},
moonfire = {
id = 164812,
duration = function () return mod_circle_dot( 16 ) end,
tick_time = function () return mod_circle_dot( 2 ) * haste end,
type = "Magic",
max_stack = 1,
},
moonkin_form = {
id = 197625,
duration = 3600,
max_stack = 1,
},
prowl = {
id = 5215,
duration = 3600,
max_stack = 1,
},
pulverize = {
id = 80313,
duration = 10,
max_stack = 1,
},
--[[ rake = {
id = 155722,
duration = 15,
max_stack = 1,
}, ]]
regrowth = {
id = 8936,
duration = function () return mod_circle_hot( 12 ) end,
type = "Magic",
max_stack = 1,
},
rejuvenation = {
id = 774,
duration = function () return mod_circle_hot( 15 ) end,
tick_time = function () return mod_circle_hot( 3 ) * haste end,
max_stack = 1,
},
soulshape = {
id = 310143,
duration = 3600,
max_stack = 1,
},
stampeding_roar = {
id = 77761,
duration = 8,
max_stack = 1,
},
sunfire = {
id = 164815,
duration = function () return mod_circle_dot( 12 ) end,
tick_time = function () return mod_circle_dot( 2 ) * haste end,
max_stack = 1,
type = "Magic",
},
survival_instincts = {
id = 61336,
duration = 6,
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 = function () return legendary.luffainfused_embrace and 4 or 3 end,
},
--[[ thrash_cat = {
id = 106830,
duration = function () return mod_circle_dot( 15 ) end,
tick_time = function () return mod_circle_dot( 3 ) * haste end,
max_stack = 1,
}, ]]
tiger_dash = {
id = 252216,
duration = 5,
max_stack = 1,
},
tooth_and_claw = {
id = 135286,
duration = 15,
max_stack = 2
},
travel_form = {
id = 783,
duration = 3600,
max_stack = 1,
},
typhoon = {
id = 61391,
duration = 6,
max_stack = 1,
type = "Magic",
},
ursols_vortex = {
id = 127797,
duration = 3600,
max_stack = 1,
},
wild_charge = {
id = 102401,
duration = 0.5,
max_stack = 1,
},
wild_growth = {
id = 48438,
duration = 7,
max_stack = 1,
},
yseras_gift = {
id = 145108,
},
any_form = {
alias = { "bear_form", "cat_form", "moonkin_form" },
duration = 3600,
aliasMode = "first",
aliasType = "buff",
},
-- PvP Talents
demoralizing_roar = {
id = 201664,
duration = 8,
max_stack = 1,
},
den_mother = {
id = 236181,
duration = 3600,
max_stack = 1,
},
focused_assault = {
id = 206891,
duration = 6,
max_stack = 1,
},
grove_protection_defense = {
id = 354704,
duration = 12,
max_stack = 1,
},
grove_protection_offense = {
id = 354789,
duration = 12,
max_stack = 1,
},
master_shapeshifter_feral = {
id = 236188,
duration = 3600,
max_stack = 1,
},
overrun = {
id = 202244,
duration = 3,
max_stack = 1,
},
protector_of_the_pack = {
id = 201940,
duration = 3600,
max_stack = 1,
},
sharpened_claws = {
id = 279943,
duration = 6,
max_stack = 1,
},
-- Azerite
masterful_instincts = {
id = 273349,
duration = 30,
max_stack = 1,
},
-- Legendary
lycaras_fleeting_glimpse = {
id = 340060,
duration = 5,
max_stack = 1
},
ursocs_fury_remembered = {
id = 345048,
duration = 15,
max_stack = 1,
},
} )
Hekili:EmbedAdaptiveSwarm( spec )
-- 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" )
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
end )
spec:RegisterStateExpr( "ironfur_damage_threshold", function ()
return ( settings.ironfur_damage_threshold or 0 ) / 100 * ( health.max )
end )
-- Gear.
-- Tier 28
spec:RegisterSetBonuses( "tier28_2pc", 364362, "tier28_4pc", 363496 )
-- 2-Set - Architect's Design - Casting Barkskin causes you to Berserk for 4 sec.
-- 4-Set - Architect's Aligner - While Berserked, you radiate (45%26.6% of Attack power) Cosmic damage to nearby enemies and heal yourself for (61%39.7% of Attack power) every 1 sec.
spec:RegisterAuras( {
architects_aligner = {
id = 363793,
duration = function () return talent.incarnation.enabled and 30 or 15 end,
max_stack = 1,
},
architects_aligner_heal = {
id = 363789,
duration = function () return talent.incarnation.enabled and 30 or 15 end,
max_stack = 1,
}
} )
spec:RegisterGear( "class", 139726, 139728, 139723, 139730, 139725, 139729, 139727, 139724 )
spec:RegisterGear( "tier19", 138330, 138336, 138366, 138324, 138327, 138333 )
spec:RegisterGear( "tier20", 147136, 147138, 147134, 147133, 147135, 147137 ) -- Bonuses NYI
spec:RegisterGear( "tier21", 152127, 152129, 152125, 152124, 152126, 152128 )
spec:RegisterGear( "ailuro_pouncers", 137024 )
spec:RegisterGear( "behemoth_headdress", 151801 )
spec:RegisterGear( "chatoyant_signet", 137040 )
spec:RegisterGear( "dual_determination", 137041 )
spec:RegisterGear( "ekowraith_creator_of_worlds", 137015 )
spec:RegisterGear( "elizes_everlasting_encasement", 137067 )
spec:RegisterGear( "fiery_red_maimers", 144354 )
spec:RegisterGear( "lady_and_the_child", 144295 )
spec:RegisterGear( "luffa_wrappings", 137056 )
spec:RegisterGear( "oakhearts_puny_quods", 144432 )
spec:RegisterAura( "oakhearts_puny_quods", {
id = 236479,
duration = 3,
max_stack = 1,
} )
spec:RegisterGear( "skysecs_hold", 137025 )
spec:RegisterAura( "skysecs_hold", {
id = 208218,
duration = 3,
max_stack = 1,
} )
spec:RegisterGear( "the_wildshapers_clutch", 137094 )
spec:RegisterGear( "soul_of_the_archdruid", 151636 )
spec:RegisterStateExpr( "lunar_eclipse", function ()
return eclipse.wrath_counter
end )
spec:RegisterStateExpr( "solar_eclipse", function ()
return eclipse.starfire_counter
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:RunHandle( "wild_growth" ) end
end, state )
local SinfulHysteriaHandler = setfenv( function ()
applyBuff( "ravenous_frenzy_sinful_hysteria" )
end, state )
spec:RegisterHook( "reset_precast", function ()
if azerite.masterful_instincts.enabled and buff.survival_instincts.up and buff.masterful_instincts.down then
applyBuff( "masterful_instincts", buff.survival_instincts.remains + 30 )
end
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
eclipse.reset() -- from Balance.
end )
spec:RegisterHook( "runHandler", function( ability )
local a = class.abilities[ ability ]
if not a or a.startsCombat then
break_stealth()
end
if buff.ravenous_frenzy.up and ability ~= "ravenous_frenzy" then
addStack( "ravenous_frenzy", nil, 1 )
end
end )
spec:RegisterStateTable( "druid", setmetatable( {
}, {
__index = function( t, k )
if k == "catweave_bear" then
return talent.feral_affinity.enabled and settings.catweave_bear
elseif k == "owlweave_bear" then
return talent.balance_affinity.enabled and settings.owlweave_bear
elseif k == "no_cds" then return not toggle.cooldowns
elseif k == "primal_wrath" then return debuff.rip
elseif k == "lunar_inspiration" then return debuff.moonfire_cat end
local fallthru = rawget( debuff, k )
if fallthru then return fallthru end
end
} ) )
-- Abilities
spec:RegisterAbilities( {
alpha_challenge = {
id = 207017,
cast = 0,
cooldown = 20,
gcd = "spell",
pvptalent = "alpha_challenge",
startsCombat = true,
texture = 132270,
handler = function ()
applyDebuff( "target", "focused_assault" )
end,
},
barkskin = {
id = 22812,
cast = 0,
cooldown = function () return ( talent.survival_of_the_fittest.enabled and 40 or 60 ) * ( 1 + ( conduit.tough_as_bark.mod * 0.01 ) ) end,
gcd = "off",
startsCombat = false,
texture = 136097,
toggle = "defensives",
defensive = true,
usable = function ()
if not tanking then return false, "player is not tanking right now"
elseif incoming_damage_3s == 0 then return false, "player has taken no damage in 3s" end
return true
end,
handler = function ()
applyBuff( "barkskin" )
if legendary.the_natural_orders_will.enabled and buff.bear_form.up then
applyBuff( "ironfur" )
applyBuff( "frenzied_regeneration" )
end
if set_bonus.tier28_2pc > 0 then
applyBuff( "berserk", max( buff.berserk.remains, 4 ) )
if set_bonus.tier28_4pc > 0 then
applyBuff( "architects_aligner", buff.berserk.remains )
applyBuff( "architects_aligner_heal", buff.berserk.remains )
end
end
end,
},
bear_form = {
id = 5487,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = -25,
spendType = "rage",
startsCombat = false,
texture = 132276,
essential = true,
noform = "bear_form",
handler = function ()
shift( "bear_form" )
if conduit.ursine_vigor.enabled then applyBuff( "ursine_vigor" ) end
end,
},
berserk = {
id = 50334,
cast = 0,
cooldown = function () return legendary.legacy_of_the_sleeper.enabled and 150 or 180 end,
gcd = "off",
toggle = "cooldowns",
startsCombat = true,
texture = 236149,
notalent = "incarnation",
handler = function ()
applyBuff( "berserk" )
if set_bonus.tier28_4pc > 0 then
applyBuff( "architects_aligner", buff.berserk.remains )
applyBuff( "architects_aligner_heal", buff.berserk.remains )
end
end,
copy = "berserk_bear"
},
bristling_fur = {
id = 155835,
cast = 0,
cooldown = 40,
gcd = "spell",
startsCombat = false,
texture = 1033476,
talent = "bristling_fur",
usable = function ()
if incoming_damage_3s < health.max * 0.1 then return false, "player has not taken 10% health in dmg in 3s" end
return true
end,
handler = function ()
applyBuff( "bristling_fur" )
end,
},
cat_form = {
id = 768,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 132115,
noform = "cat_form",
handler = function ()
shift( "cat_form" )
if pvptalent.master_shapeshifter.enabled and talent.feral_affinity.enabled then
applyBuff( "master_shapeshifter_feral" )
end
end,
},
cyclone = {
id = 33786,
cast = 1.7,
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 = "spell",
startsCombat = false,
texture = 132120,
handler = function ()
shift( "cat_form" )
applyBuff( "dash" )
end,
},
demoralizing_roar = {
id = 201664,
cast = 0,
cooldown = 30,
gcd = "spell",
pvptalent = "demoralizing_roar",
startsCombat = true,
texture = 132117,
handler = function ()
applyDebuff( "demoralizing_roar" )
active_dot.demoralizing_roar = active_enemies
end,
},
emerald_slumber = {
id = 329042,
cast = 8,
cooldown = 120,
channeled = true,
gcd = "spell",
toggle = "cooldowns",
pvptalent = "emerald_slumber",
startsCombat = false,
texture = 1394953,
handler = function ()
end,
},
entangling_roots = {
id = 339,
cast = function () return pvptalent.entangling_claws.enabled and 0 or 1.7 end,
cooldown = function () return pvptalent.entangling_claws.enabled and 6 or 0 end,
gcd = "spell",
spend = 0.06,
spendType = "mana",
startsCombat = true,
texture = 136100,
handler = function ()
applyDebuff( "target", "entangling_roots" )
end,
},
--[[ ferocious_bite = {
id = 22568,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return args.max_energy == 1 and 50 or 25 end,
spendType = "energy",
startsCombat = true,
texture = 132127,
form = "cat_form",
usable = function ()
if combo_points.current == 0 then return false, "player has no combo points" end
return true
end,
handler = function ()
spend( min( 5, combo_points.current ), "combo_points" )
end,
}, ]]
frenzied_regeneration = {
id = 22842,
cast = 0,
charges = 2,
cooldown = function () return buff.berserk_bear.up and ( level > 57 and 9 or 18 ) or 36 end,
recharge = function () return buff.berserk_bear.up and ( level > 57 and 9 or 18 ) or 36 end,
hasteCD = true,
gcd = "spell",
spend = 10,
spendType = "rage",
startsCombat = false,
texture = 132091,
toggle = "defensives",
defensive = true,
form = "bear_form",
nobuff = "frenzied_regeneration",
handler = function ()
applyBuff( "frenzied_regeneration" )
gain( health.max * 0.08, "health" )
end,
auras = {
-- Conduit (ICD)
wellhoned_instincts = {
id = 340556,
duration = function ()
if conduit.wellhoned_instincts.enabled then return conduit.wellhoned_instincts.mod end
return 90
end,
max_stack = 1
}
}
},
grove_protection = {
id = 354654,
cast = 0,
cooldown = 60,
gcd = "spell",
toggle = "defensives",
startsCombat = false,
texture = 4067364,
handler = function ()
-- Don't apply auras; position dependent.
end,
},
growl = {
id = 6795,
cast = 0,
cooldown = function () return buff.berserk_bear.up and ( level > 57 and 2 or 4 ) or 8 end,
gcd = "spell",
nopvptalent = "alpha_challenge",
startsCombat = true,
texture = 132270,
handler = function ()
applyDebuff( "target", "growl" )
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",
startsCombat = false,
texture = 135879,
handler = function ()
applyBuff( "heart_of_the_wild" )
if talent.balance_affinity.enabled then
shift( "moonkin_form" )
elseif talent.feral_affinity.enabled then
shift( "cat_form" )
elseif talent.restoration_affinity.enabled then
unshift()
end
end,
},
hibernate = {
id = 2637,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.06,
spendType = "mana",
startsCombat = false,
texture = 136090,
handler = function ()
applyDebuff( "target", "hibernate" )
end,
},
incapacitating_roar = {
id = 99,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = true,
texture = 132121,
handler = function ()
applyDebuff( "target", "incapacitating_roar" )
end,
},
incarnation = {
id = 102558,
cast = 0,
cooldown = function () return legendary.legacy_of_the_sleeper.enabled and 150 or 180 end,
gcd = "off",
toggle = "cooldowns",
startsCombat = false,
texture = 571586,
talent = "incarnation",
handler = function ()
applyBuff( "incarnation" )
if set_bonus.tier28_4pc > 0 then
applyBuff( "architects_aligner", buff.incarnation.remains )
applyBuff( "architects_aligner_heal", buff.incarnation.remains )
end
end,
copy = { "incarnation_guardian_of_ursoc", "Incarnation" }
},
ironfur = {
id = 192081,
cast = 0,
cooldown = 0.5,
gcd = "off",
spend = function () return buff.berserk_bear.up and 20 or 40 end,
spendType = "rage",
startsCombat = false,
texture = 1378702,
toggle = "defensives",
defensive = true,
form = "bear_form",
usable = function ()
if not tanking then return false, "player is not tanking right now"
elseif incoming_damage_3s == 0 then return false, "player has taken no damage in 3s" end
return true
end,
handler = function ()
applyBuff( "ironfur" )
removeBuff( "guardian_of_elune" )
end,
},
lunar_beam = {
id = 204066,
cast = 0,
cooldown = 75,
gcd = "spell",
toggle = "defensives",
startsCombat = true,
texture = 136057,
talent = "lunar_beam",
handler = function ()
applyBuff( "lunar_beam" )
end,
auras = {
lunar_beam = {
duration = 8,
max_stack = 1,
generate = function( t )
local applied = action.lunar_beam.lastCast
if not t.name then t.name = class.auras.lunar_beam.name end
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,
},
}
},
maim = {
id = 22570,
cast = 0,
cooldown = 20,
gcd = "spell",
spend = 30,
spendType = "energy",
startsCombat = true,
texture = 132134,
talent = "feral_affinity",
form = "cat_form",
usable = function () return combo_points.current > 0, "requires combo_points" end,
handler = function ()
applyDebuff( "target", "maim", combo_points.current )
spend( combo_points.current, "combo_points" )
end,
},
mangle = {
id = 33917,
cast = 0,
cooldown = function () return ( buff.berserk_bear.up and ( level > 57 and 1.5 or 3 ) or 6 ) * haste end,
gcd = "spell",
spend = function () return buff.gore.up and -19 or -15 end,
spendType = "rage",
startsCombat = true,
texture = 132135,
form = "bear_form",
handler = function ()
if talent.guardian_of_elune.enabled then applyBuff( "guardian_of_elune" ) end
removeBuff( "gore" )
if conduit.savage_combatant.enabled then addStack( "savage_combatant", nil, 1 ) end
end,
auras = {
-- Conduit
savage_combatant = {
id = 340613,
duration = 15,
max_stack = 3
}
}
},
mass_entanglement = {
id = 102359,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = false,
texture = 538515,
talent = "mass_entanglement",
handler = function ()
applyDebuff( "target", "mass_entanglement" )
end,
},
maul = {
id = 6807,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 40,
spendType = "rage",
startsCombat = true,
texture = 132136,
form = "bear_form",
usable = function ()
if settings.maul_rage > 0 and rage.current - cost < settings.maul_rage then return false, "not enough additional rage" end
return true
end,
handler = function ()
if pvptalent.sharpened_claws.enabled or essence.conflict_and_strife.major then applyBuff( "sharpened_claws" ) end
removeBuff( "savage_combatant" )
end,
},
mighty_bash = {
id = 5211,
cast = 0,
cooldown = 60,
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 = 0.06,
spendType = "mana",
startsCombat = true,
texture = 136096,
handler = function ()
applyDebuff( "target", "moonfire" )
if buff.galactic_guardian.up then
gain( 8, "rage" )
removeBuff( "galactic_guardian" )
end
end,
},
moonkin_form = {
id = 197625,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 136036,
noform = "moonkin_form",
talent = "balance_affinity",
handler = function ()
shift( "moonkin_form" )
end,
},
overrun = {
id = 202246,
cast = 0,
cooldown = 25,
gcd = "spell",
startsCombat = true,
texture = 1408833,
pvptalent = "overrun",
handler = function ()
applyDebuff( "target", "overrun" )
setDistance( 5 )
end,
},
prowl = {
id = 5215,
cast = 0,
cooldown = 6,
gcd = "spell",
startsCombat = false,
texture = 514640,
usable = function ()
if time > 0 and ( not boss or not buff.shadowmeld.up ) then return false, "cannot stealth in combat"
elseif buff.prowl.up then return false, "player is already prowling" end
return true
end,
handler = function ()
shift( "cat_form" )
applyBuff( "prowl" )
end,
},
pulverize = {
id = 80313,
cast = 0,
cooldown = 45,
gcd = "spell",
startsCombat = true,
texture = 1033490,
talent = "pulverize",
form = "bear_form",
usable = function ()
if debuff.thrash_bear.stack < 2 then return false, "target has fewer than 2 thrash stacks" end
return true
end,
handler = function ()
if debuff.thrash_bear.count > 2 then debuff.thrash_bear.count = debuff.thrash_bear.count - 2
else removeDebuff( "target", "thrash_bear" ) end
applyBuff( "pulverize" )
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" )
debuff.rake.pmultiplier = persistent_multiplier
gain( 1, "combo_points" )
end,
}, ]]
--[[ rebirth = {
id = 20484,
cast = 2,
cooldown = 600,
gcd = "spell",
spend = 0,
spendType = "rage",
startsCombat = true,
texture = 136080,
handler = function ()
end,
}, ]]
regrowth = {
id = 8936,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.14,
spendType = "mana",
startsCombat = false,
texture = 136085,
talent = "restoration_affinity",
usable = function ()
if not ( buff.bear_form.down and buff.cat_form.down and buff.travel_form.down and buff.moonkin_form.down ) then return false, "player is in a form" end
return true
end,
handler = function ()
applyBuff( "regrowth" )
end,
},
rejuvenation = {
id = 774,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.1,
spendType = "mana",
startsCombat = false,
texture = 136081,
talent = "restoration_affinity",
usable = function ()
if not ( buff.bear_form.down and buff.cat_form.down and buff.travel_form.down and buff.moonkin_form.down ) then return false, "player is in a form" end
return true
end,
handler = function ()
applyBuff( "rejuvenation" )
end,
},
remove_corruption = {
id = 2782,
cast = 0,
cooldown = 8,
gcd = "spell",
spend = 0.06,
spendType = "mana",
startsCombat = false,
texture = 135952,
usable = function ()
if buff.dispellable_poison.down and buff.dispellable_curse.down then return false, "player has no dispellable auras" end
return true
end,
handler = function ()
removeBuff( "dispellable_poison" )
removeBuff( "dispellable_curse" )
end,
},
renewal = {
id = 108238,
cast = 0,
cooldown = 90,
gcd = "spell",
toggle = "defensives",
defensive = true,
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 ()
if combo_points.current == 0 then return false, "player has no combo points" end
return true
end,
handler = function ()
applyDebuff( "target", "rip" )
end,
}, ]]
--[[ shred = {
id = 5221,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 40,
spendType = "energy",
startsCombat = true,
texture = 136231,
handler = function ()
end,
}, ]]
skull_bash = {
id = 106839,
cast = 0,
cooldown = 15,
gcd = "spell",
startsCombat = true,
texture = 236946,
toggle = "interrupts",
debuff = "casting",
readyTime = state.timeToInterrupt,
handler = function ()
interrupt()
end,
},
soothe = {
id = 2908,
cast = 0,
cooldown = 10,
gcd = "spell",
spend = 0.06,
spendType = "mana",
startsCombat = true,
texture = 132163,
debuff = "dispellable_enrage",
handler = function ()
removeDebuff( "target", "dispellable_enrage" )
end,
},
stampeding_roar = {
id = 106898,
cast = 0,
cooldown = function () return pvptalent.freedom_of_the_herd.enabled and 0 or 60 end,
gcd = "spell",
startsCombat = false,
texture = 464343,
handler = function ()
applyBuff( "stampeding_roar" )
if buff.bear_form.down and buff.cat_form.down then
shift( "bear_form" )
end
end,
},
--[[ starfire = {
id = 197628,
cast = 2.5,
cooldown = 0,
gcd = "spell",
spend = 0.03,
spendType = "mana",
startsCombat = true,
texture = 135753,
talent = "balance_affinity",
form = "moonkin_form",
handler = function ()
end,
}, ]]
starsurge = {
id = 197626,
cast = function () return buff.heart_of_the_wild.up and 0 or 2 end,
cooldown = 10,
gcd = "spell",
spend = 0.03,
spendType = "mana",
startsCombat = true,
texture = 135730,
talent = "balance_affinity",
form = "moonkin_form",
handler = function ()
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
end,
},
sunfire = {
id = 197630,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.12,
spendType = "mana",
startsCombat = true,
texture = 236216,
talent = "balance_affinity",
form = "moonkin_form",
handler = function ()
applyDebuff( "target", "sunfire" )
active_dot.sunfire = active_enemies
end,
},
survival_instincts = {
id = 61336,
cast = 0,
charges = 2,
cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( talent.survival_of_the_fittest.enabled and ( 2/3 ) or 1 ) * 180 end,
recharge = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( talent.survival_of_the_fittest.enabled and ( 2/3 ) or 1 ) * 180 end,
gcd = "off",
startsCombat = false,
texture = 236169,
toggle = "defensives",
defensive = true,
usable = function ()
if not tanking then return false, "player is not tanking right now"
elseif incoming_damage_3s == 0 then return false, "player has taken no damage in 3s" end
return true
end,
handler = function ()
applyBuff( "survival_instincts" )
if azerite.masterful_instincts.enabled and buff.survival_instincts.up and buff.masterful_instincts.down then
applyBuff( "masterful_instincts", buff.survival_instincts.remains + 30 )
end
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",
toggle = "defensives",
defensive = true,
usable = function ()
return IsSpellUsable( 18562 ) or buff.regrowth.up or buff.wild_growth.up or buff.rejuvenation.up, "requires a HoT"
end,
handler = function ()
unshift()
if buff.regrowth.up then removeBuff( "regrowth" )
elseif buff.wild_growth.up then removeBuff( "wild_growth" )
elseif buff.rejuvenation.up then removeBuff( "rejuvenation" ) end
end,
},
swipe_bear = {
id = 213771,
known = 213764,
suffix = "(Bear)",
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = true,
texture = 134296,
form = "bear_form",
handler = function ()
end,
copy = { "swipe", 213764 },
bind = { "swipe_bear", "swipe_cat", "swipe" }
},
--[[ teleport_moonglade = {
id = 18960,
cast = 10,
cooldown = 0,
gcd = "spell",
spend = 4,
spendType = "mana",
startsCombat = true,
texture = 135758,
handler = function ()
end,
}, ]]
thrash_bear = {
id = 77758,
known = 106832,
suffix = "(Bear)",
cast = 0,
cooldown = function () return ( buff.berserk_bear.up and ( level > 57 and 1.5 or 3 ) or 6 ) * haste end,
gcd = "spell",
spend = -5,
spendType = "rage",
startsCombat = true,
texture = 451161,
form = "bear_form",
bind = "thrash",
handler = function ()
applyDebuff( "target", "thrash_bear", 15, debuff.thrash_bear.count + 1 )
active_dot.thrash_bear = active_enemies
if legendary.ursocs_fury_remembered.enabled then
applyBuff( "ursocs_fury_remembered" )
end
end,
},
tiger_dash = {
id = 252216,
cast = 0,
cooldown = 45,
gcd = "spell",
startsCombat = false,
texture = 1817485,
talent = "tiger_dash",
handler = function ()
applyBuff( "tiger_dash" )
end,
},
travel_form = {
id = 783,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 132144,
handler = function ()
shift( "travel_form" )
end,
},
typhoon = {
id = 132469,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = true,
texture = 236170,
talent = "balance_affinity",
handler = function ()
if target.distance < 15 then
applyDebuff( "target", "typhoon" )
end
end,
},
ursols_vortex = {
id = 102793,
cast = 0,
cooldown = 60,
gcd = "spell",
talent = "restoration_affinity",
startsCombat = true,
texture = 571588,
handler = function ()
applyDebuff( "target", "ursols_vortex" )
end,
},
wild_charge = {
id = function ()
if buff.bear_form.up then return 16979
elseif buff.cat_form.up then return 49376
elseif buff.moonkin_form.up then return 102383 end
return 102401
end,
known = 102401,
cast = 0,
cooldown = 15,
gcd = "spell",
startsCombat = true,
-- texture = 538771,
talent = "wild_charge",
usable = function () return target.exists and target.distance > 7, "target must be 8+ yards away" end,
handler = function ()
if buff.bear_form.up then target.distance = 5; applyDebuff( "target", "immobilized" )
elseif buff.cat_form.up then target.distance = 5; applyDebuff( "target", "dazed" ) end
end,
copy = { 49376, 16979, 102401, 102383 }
},
wild_growth = {
id = 48438,
cast = 1.5,
cooldown = 10,
gcd = "spell",
spend = 0.22,
spendType = "mana",
startsCombat = false,
texture = 236153,
handler = function ()
applyBuff( "wild_growth" )
end,
},
--[[ wrath = {
id = 5176,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 535045,
handler = function ()
if buff.moonkin_form.down then unshift() end
removeStack( "solar_empowerment" )
end,
}, ]]
} )
spec:RegisterOptions( {
enabled = true,
aoe = 3,
nameplates = true,
nameplateRange = 8,
damage = true,
damageExpiration = 6,
potion = "spectral_agility",
package = "Guardian",
} )
spec:RegisterSetting( "maul_rage", 20, {
name = "Excess Rage for |T132136:0|t Maul",
desc = "If set above zero, the addon will recommend |T132136:0|t Maul only if you have at least this much excess Rage.",
type = "range",
min = 0,
max = 60,
step = 0.1,
width = "full"
} )
spec:RegisterSetting( "mangle_more", false, {
name = "Use |T132135:0|t Mangle More in Multi-Target",
desc = "If checked, the default priority will recommend |T132135:0|t Mangle more often in |cFFFFD100multi-target|r scenarios. This will generate roughly 15% more Rage and allow for more mitigation (or |T132136:0|t Maul) than otherwise, " ..
"funnel slightly more damage into your primary target, but will |T134296:0|t Swipe less often, dealing less damage/threat to your secondary targets.",
type = "toggle",
width = "full",
} )
spec:RegisterSetting( "ironfur_damage_threshold", 5, {
name = "Required Damage % for |T1378702:0|t Ironfur",
desc = "If set above zero, the addon will not recommend |T1378702:0|t Ironfur unless your incoming damage for the past 5 seconds is greater than this percentage of your maximum health.",
type = "range",
min = 0,
max = 100,
step = 0.1,
width = "full"
} )
spec:RegisterSetting( "shift_for_convoke", false, {
name = "|T3636839:0|t Powershift for Convoke the Spirits",
desc = "If checked and you are a Night Fae, the addon will recommend swapping to your Feral/Balance Affinity specialization before using |T3636839:0|t Convoke the Spirits. " ..
"This is a DPS gain unless you die horribly.",
type = "toggle",
width = "full"
} )
spec:RegisterSetting( "catweave_bear", false, {
name = "|T132115:0|t Attempt Catweaving (Experimental)",
desc = function()
local affinity
if state.talent.feral_affinity.enabled then
affinity = "|cFF00FF00" .. ( GetSpellInfo( 202155 ) ) .. "|r"
else
affinity = "|cFFFF0000" .. ( GetSpellInfo( 202155 ) ) .. "|r"
end
return "If checked, the addon will use the experimental |cFFFFD100catweave|r priority included in the default priority pack.\n\nRequires " .. affinity .. "."
end,
type = "toggle",
width = "full",
} )
spec:RegisterSetting( "owlweave_bear", false, {
name = "|T136036:0|t Attempt Owlweaving (Experimental)",
desc = function()
local affinity
if state.talent.balance_affinity.enabled then
affinity = "|cFF00FF00" .. ( GetSpellInfo( 197488 ) ) .. "|r"
else
affinity = "|cFFFF0000" .. ( GetSpellInfo( 197488 ) ) .. "|r"
end
return "If checked, the addon will use the experimental |cFFFFD100owlweave|r priority included in the default priority pack.\n\nRequires " .. affinity .. "."
end,
type = "toggle",
width = "full"
} )
spec:RegisterPack( "Guardian", 20220911, [[Hekili:T3tApooUX(BXiaAS3PJhF0Eow0Ubs2xqWm4LzbshG8(KLvltBR0Yso6O90lAOF7PksrjEkjF09K3I5l70wKSyXI1nlYDX4f)Jf3TYlJS4RtgnzYOpnE8WXJNmD8I7YEApzXD798FWBd8hrE7G)7Fn3lzvGxe2WtHXERWXNgNN4dnUnlBF6p)U3TjiBB(9d9J39U0GD5HEzbXr(jERZWF7)Uf3DFEqy2NJwCVXjF07xCNxE224Kf3DxWUFbGCWQvew3jP(1OrXY)NK8GvfF5oY(mYU7jjflhp(QILi8k(sXx(LTErBiP)CXx(Jfl)CKFCY(4eyglw(lEzV7Vfhh9qaaL9jbXjbzbK0IL9dwxSmLKLfeTPyza8f)Te)hiRgmuhkX7X1wXYSyymBdwNbJpgqIO4SbflVNSoobNR4OhJFGWg)D57HrdD8p7L8qkD6ZtbsCXYdaDRy5179PZpm84O80HlUlminlfj03t8sG)9R0DnsK39HKvl(ZlUZhWDssG3I76bJkF96HypDHjF3W89aX0hXs24PFDrgqYTcKmVqsu2WTqVZCJx7MTL4EiiC1WYExS0bwMWIM1V79c9I8jUERxhefK9uD3gup1AadrHPkOaVZ7G9L1bjerKQpDkH1xwG)d0Tgh8V3rCZIDxfaKVBH9(j0ptjbBa0cGNV7MsMfGuaOuXYNFMcQeY6es6wCYpDynG2hSThjUKiYokl0nflbwy)N8dbi6LSHaBFWMgSIV(LyfFCRPtaRNzLvHHJiVqsq0dKSHzJhgKo03dKzWDBp))DoSSw5MLq8sZtW5bX1QUpP1UpOEBOQzVVre2bkx89okSWrEaDapQ3Ts8EKefNN6cu7OF7jKe9(MejxHkPaONDGaJ0ffd5iaRP4dHkn9YssRxk(mvtuXY09bawNIlNp00ooG2(XafWde(H)jB7tv48llA3cNq9QkiY3ljIA3bxnF0UQUUJSwM66jTewujMp1(m2(6TRZ4eCghpszkzgS3aCvHC9UGgM0mxVK7rKPgmn0heWQwBya(qI3(uCqKqIFwsCAMhQGCFCgWre4fwd(w7jojQwJytcS(2GJ0pomeac(R15zi1rqy0EFqaBZgZ)kolhCniijXf8Pam2)uQRVxyO4ELkxohTSowCcvvXRBCEFciVt5ADSijD0QYysLMfnCm0w6H4KvwB9Gx0krRLgrCBAb(VgC3SK5y7gZoT9Nojh)sTgpZ9NVR4Uf9y2TKAC5qHUG((HjKDEbraQF7CioGRBPt3GDAwnQaALknAm2UnWmVOkhY0C3M(vW)DxM77qqfjt(Ol1REWdSrcEJx6)pDYSBI6O9FOvJ7JTBDQF5csXdh6YQKttFxyGyegjPKKhOXxOAq6YnlkM3NypEO(vBqu8IsFQMgvUIkV7rHH8K0yFvg1sWa7905LA0I3gz3(4dKeCBFLi2GDu1iKQ7uRIZg6TYBp1H80dEj7Cx5TdckCOOV)9y(SdSVM7BqK76WGnBZeeBnaziuSWA4IecBDQwuQy50kTn2rwWYU)d0ajMsrb79Sw(Ry5Sw6BfQkSri3tkn2UD3gcHZXyyqtneygofQMoQ0FTnXlDBPWx98kfngNYj0xz6vzum27dtvwsEeMvbGUecllGiUopfuRs2DFINpzibuZUFpn4BgivxEOwXRf4)1KmCm1GK(Yn(a4FlOlB4mZXloXUo8eChDfzDGFqglK0rCfMycxshUZlAdaWDXyWWv7c0psbTDTYPX5H3hawx2NNMLdWGKKttpJAEl6JQxIdxfFisIulYUpQ04Fz3yiGApgWHiUPX5uKnanvOxDqFdozw2cKBsNDM1EDeXvKJhJXmWb0J04quBkNCG6rbshsKCdwlq)uhGt)Mix3oYXcz62rdKMJD7iaMMb7RJR3AxhcIi0Kdk23nHX3JXqWyNSBC8crsnkKuJJPhc2xABfrN2nFk6QrPFAw00iXBKfhNT1fCqY1p07ax0N6hJyIom1xrjxLMe11oE4SMXgXPOtgnfwF8XL69iiLdbKT7EVm0gUWczA7tp16F0Q8GmDiPijFsOP1THEIAxPmpGNj5jp5cuqAYLjRe0VksPELwXnXa1Rb959Srpe1WMtdFDAJETDeKhNtCnHMeez2pUP8uPK4g1y5yseSPJ0f7(yAK0AA3AUSNfv20MApv8MOo2XXPI(JwcFzprNAlb07Zbv9jb)MugOT4lcGetmB4F6mrmqYTiz049I9tq9Qs3SBSpHEIj4227hvR5libSbNl600KtNt84LpRrQRNOJuwT2uprMylNkc6ILFSXL7hecsI1iqhblR7cYc2WcyQXZpcyJJ3HPqJ57T7mgpxjS4Ff2ybJ2GnFDur0ydG5)uXYTEPzetOvJNavDa2yKizBhU3pJDefcbRdrnsoWsGO9iS6iSOHGgaEsNq2aGnPk6s7Xv0xic8UgCEJ(LpXs0KznDemnS((al0klBQJgoMTbXg0oVVzo3e2DMNz7lp5XGh9cDHTDWfE)SuvxUkHv9Nv3gg1mAozMv8uFYz87qegGbTmtm74jiNeSNn()Y3i(5zO4lbu)9e7eZG)7wcDhcpkx8eGbH(GqecdfM6hYddDVh0WzIxM3RUKM5UM(UUK(z7YbDFwQ0FlK20JmR2DbUtAMV2w(l7xDqtD5yQPOMExKCA1OemnEDlYVoMs5ATllhLJP2s6KGFDNGgg5JdRoPM2LLByse1WyBxPdlRUei2Lm6CNMIlxihgc2xXSSm6sUEOn1qS6Ibra0EPCiJwH28eZDRzI9gxvjEpGRi5J7N2qWE5VBYv6ypiaXs5bs4kWodB7x1xAkEzRZLOzxq)QCLyrCuk9sJhjI0vCBp8ucTIFe34fTsQaeAhn4PLEK0M1oiVc(0iUmvkO9YhtIUGBi5rUS)2flvhwb74Y0vZfOqHp7EZ2rHVg0h(drMlOiZ3Vf35XGDshIKkH8SWa7PgZwHUOWIFHOZxyHI222e5j3XkQqj(sKllnNlt9APC2Gs0i84HCx7rKx4goOqn1PNe3jF)g5n0QqfdSN68hMOPNhA0yabFEDXYdK3GvTPxXsk5IsT8IwHnGBLrVbcB5aqnzL9jN9)D8j5kHEVf(nSgyvi57wdHvgcTwwOKCxyjRGH8p3ckVEelG1Ynd4pwXI(a3lrGLEiiZFlgOeoV1qbPkCCjfWQGSRWOLW1WoEfUsPCnqSeogf(jXqRNvKK7wHrok(E3qPFY7Snnp6DWOF2xuMxroIYrr5iudE73ZCeaYXA9LHJGUG()H8d(I8d2QzmmiBR6yesXwMHYaRlQPktKBMa7zJzRRtra3Rn3C7ztjlhLnw722tExRWtSHMZzr1rsYQkruRp4dNw89sTkotwkag7jZq401jB88FIVQtdjK9KKkBWTof2ZRbXpmyFkzOx0tUrKVLXmsZ)AACOxc97czAkZlHxdc2dGVz4gMhPb3djGZdvbM00cskT8ae2Nqyza)isWg)YqWgi(7nGe5WIL)jFFY(Su8ste9h36LSBDEiVsxGVghf(KGEkGXzfTkZQP1N)nzOR(g3qAHS4QIqsFm5yy72rBrm0USJXaKmSqfsteMlRULSpKjteU9Bu1Tt3u7BsX(Gc5eRDotHfdhL7bGt5zXS0(B2(LuDGjCrASlQBpEa7lbDK0GaBlPK)yMYMMprfpNvD3CzRhLlrrLGo4u6WqALsSkbbw(sL069vPI97(W44v0JIwPxshbRq5ck3RRf7LxIVxeEnDssOloPEkDGQ0I7l19FLVAZo9UkDMQ42gfjv6KKQEuNdy1eCyJDKes9SLIUPseqYG79jG3mHSAWpP5ec0xjxtsvKicp1Z9MljREQ0LdSgjukpuwCNk7jkl2Xs7)5Pexan3PB4RkxhVI(LjLBM29jtwBUbUZgvSBCY4FSzBd0XZppebhE9yEv30jyEMKRwilh1HEudl1JGTH03Am7Iu3VktijMiXz60e7Yy2Ylj69uS7(yqRwQwDQbdOzzUgxV2QwC7PTXaYqrsH0WotOG3HydJ9dW69gVCryfQ8nxwxllFeTuZiPTOxrxksygRcBk)rDsRxN0Aj74OmK7iXspD2L20Udd63mD2LWiFzK8vUZyRoJA4oB1S8hUROlv3WvmQPHNUfIRP0mZ3HW)psZmNNveP9LUeXzvgCFfPiFFtisfBb4eEAEYg1s577AsmAmXmTc32miB56m1DdY)WAXfYAHQdkvmL5ApxbcAkxyS4qvDlrK7VbGjKbft3HhZZvJoTymlaQPptwaKhfCdEOyjbgnc6Qa6BWQm)CflHIlntEYzwI3en5HdvQSBBU114DsJJYaZpD(SLKsXSZOpgNs8RsfMBPimg9QWczGfITuyYmALIDbGw(ieqh2b2BiZhNaEiaCVr4bwS4U)5F6V)1p)1)6pxSSy5)alQVGDShFL1yP99gu)YBWNnd2Ltf9Kbl)pV8S4DE0Sw6ZEazgw8L)3GiOPz)m75CHKqB(n8Rs74H)FVHDIlVr42pJFR)KVnO1HpXWWNOp83F8Z(4om8gMDXH)HZB2Tn8oo7F88M9pDEZ(4Rp(PxCNB8jVZx8Lpt5zXr9jUTQIL0hfiOzqKzpXh14DnnM)1bO(3)WFOyP2JKe(rBpusyB1pws4VUmpysMG0X(OjvcJJ9HtIUSkwEHobIIVu(7Hvh(XBN)oLtJWCN0Cx8QG1ZBZvvN(gcw3r176NF2GhtoM8285Nn9vNwoaIbMxr0S8GRcv8XXug4ncIQ8hIGPN6Hk40VFptRSEgG)aN(90T8oyWZpFCarhgoD4ObgyHernxvrIuj7grldUpye0CBKhf07kWRJQgbFRPe45NBn4)Rmei)8XxPgYU0NeNAv4Qjx3Xs3VA9oVU09R(gSY5z99k8W4NBRi7Rzx5P6uyJJxxMcqLxe9N44MCSJJD2f0rP2nqOQFRQDSgA8aJAKmQaAGJmgtfflp1aPsIVuPuBLdpkHBsBOjP7bOaj1AgRRuJsIgnrZfHHO2FSkpHpgSgSdYk9V3XoxbyaODcCe(yL4WkguKB6Esy8bSOqHV(BWcPSWEewaLJLvAG0gb7WSWwkwUPYKmUUzGeS6XpVdaOu2weHkl5i0kxvj7qbhp)BuM77JXQjAYmya)kDKIfzevu4x9qBJH4LAALhkMWJ()QYoSIWWLqKFBfZQmE38RWn0dDRZ8ORQNxkcZltB6i(lm39PwKxvxIo1fXehUSt5XJTIxtqVlyyYKHIm3kfpZvSYae0Cqfz5mhiZVr2LYcnvxaYPdSHiI7OZet)C)t(gY7yQERVD(g)vVD0WzoiN3nxp6CXplrpJTHYMAwXz703ozg2QPt3WXW5tG9T7vXAPkc71VQJD0A0aBQPkjG3mF8ieDuU8aonEXbGb5WKd5N74ntQOoM0iYXNpnsWjGlhxQb13)GlJ8AGSN4UPrBuQRAMXPFLzY6fX404zVigNgYnXiBCsQcJlbAz2bzGqyV7L1k1WlTLOs65KkZYvG(RS8bxxhW)IEf6EegUQQt4kvckrgWvjCM88NHcKUiBRfgI5B9Wf2oHKE(6q36s5adA8pgzDXTjJbwAIkqJv53z1qU8TkOjciJUvo30akTwl5ovbNynzeMddO(ZkbHCMSf)(BFZxQ2)BDFZ)i33mx7)VY7A1Rj1Q1NTOQlt)wx)SKxvNMe83ZnK3QQprf3f79PN8V2ef0MhU3DxjDCyZP5DOF)ELh3NJWlc(TJNytTotRQOxxDECdu9H(9xguTzeQltRYRnjB26xNh)MFkuF(56m23Cpldor5TsLMpYEDD2C615ztBDAqgXQ3PgnJ9sqt0WsbVyO7eMYw1laEyzVrd9etBxxrdJW2gKNic52q7Ubz5eyA)v9ULb2271DldpjW27XDldSPmUAnJNM2VusxQgJv3Lc73ZeH3r5R8h8y1Vx(uhdc(TLa3xDuQrUYot)ALT9YGShd97vcL0OF1PDV1ClwN)LjxBTXBMpzM2KWFjLyUqiesOOhioME7PVD0f3mHo2jeVjvLof10FJNHTtvAu7MhohyvFnmQb1jEqeAWwmrIAnkxpvmZCTwrwo9yqPTYrZXiSeldTNFULsq72Pdm2hXcp7MPoTwWz3mRH(uImn4XAq5XyAYFsv36MQR5QotgMCOuWNr2Av7bn8MPLPFuVLRD64ZTmqhLr0BNFDjpLcNMHCZujYxMpwDkfnBm0vJx9ZN8TJh5y6ztwB4h5r6EgPjcpJqJzAE6GY05F6jVYclclHTFhog6Z4vrwBhIwz6vYbNonsJh0aRuEyTwq5xTuTyOMwUPz6DjgSEvL4pT3IyhtFMZMpE4m9zIdQw1ltXtwFn)Q7sz20bFV2EbpDogeqJq1RZVtT8v6fg71366zu9tptRNgvQIClDE15CKi6TJLthCBG)yje3oFSblpv6tnqmuPKZB2Kdae1vKL5t3Nr(BURj7wgniD7KMWfZQvm3u5ZWk3MYTZFp)e1eFtzVzYXUF2nMv2uE9e5P0GkmeCQBOtzd)Jgr4piMWU6C9nxy9Q)oJERT33w5zGRaB6prFtBnnpaLT8rPv0h9TvV3P38(zwgMX3F2JfiIEJw6Uzh9M3GdmtSmjMIcra5(Wmhdu4rdh)tBREaxTaz9xZ1kzulVYSLgcfFHzLiuJmJltMjHm1Ot1DcFolGodTGuGQB)TL2Rc4WC7Y34BZ9r5UEBUtv3YBlZJ0972cUkEJTRi3ilHEkTfhNAaAs(9vfaIMYEhv9A87HstesZnwDlTL2al50NFA5DNzD0yXEWAs6K8vN03wwzSgBHpY6mS0gSWYHOAhP6HM1upV0lwJtIQYLgl1xdldtv4XZpZkcKBUEM5XgSVAOk1bI4vPuYtxrAU5CC0vmx(clFv99vMzIwbd41ZYSrgb2psgGXKbisUpY4uj87k83JO)QMCJlfQNxnknyJv(glaeVCWQmDyFf6Dj3(RRQVYj9iuWjmcDXtXfu8l8csRsnuN43YssfVp1lSUmsl6EA8MZYCNr55m7yGExV6VgHP49kq9olckQ1V8FMas19EWoeQFlY66stIRO0T1xFUIYj(e4kQhz1vH0yRxUD1wHzZpTEMaKz7)wotaHX9ddFgn8jYuKBTEieVi024e7WyltJLX)NGOn2uUQad1JJ2BnOjyuPjWWfBQBqWcRll)zQ3h6YLO6DH2cfxy91x9IlBsxhMLk1(X0w38LB280ZV33zlw8Fo]] )
end