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.
1429 lines
51 KiB
1429 lines
51 KiB
-- HunterSurvival.lua
|
|
-- June 2018
|
|
|
|
local addon, ns = ...
|
|
local Hekili = _G[ addon ]
|
|
|
|
local class = Hekili.Class
|
|
local state = Hekili.State
|
|
|
|
local PTR = ns.PTR
|
|
|
|
|
|
-- Shadowlands Legendaries
|
|
-- [x] Wildfire Cluster
|
|
-- [-] Rylakstalker's Confounding Strikes (passive/reactive)
|
|
-- [x] Latent Poison Injectors
|
|
-- [x] Butcher's Bone Fragments
|
|
|
|
-- Conduits
|
|
-- [x] Deadly Tandem
|
|
-- [x] Flame Infusion
|
|
-- [-] Stinging Strike
|
|
-- [-] Strength of the Pack
|
|
|
|
|
|
if UnitClassBase( "player" ) == "HUNTER" then
|
|
local spec = Hekili:NewSpecialization( 255 )
|
|
|
|
spec:RegisterResource( Enum.PowerType.Focus, {
|
|
terms_of_engagement = {
|
|
aura = "terms_of_engagement",
|
|
|
|
last = function ()
|
|
local app = state.buff.terms_of_engagement.applied
|
|
local t = state.query_time
|
|
|
|
return app + floor( t - app )
|
|
end,
|
|
|
|
interval = 1,
|
|
value = 2,
|
|
},
|
|
|
|
death_chakram = {
|
|
resource = "focus",
|
|
aura = "death_chakram",
|
|
|
|
last = function ()
|
|
return state.buff.death_chakram.applied + floor( ( state.query_time - state.buff.death_chakram.applied ) / class.auras.death_chakram.tick_time ) * class.auras.death_chakram.tick_time
|
|
end,
|
|
|
|
interval = function () return class.auras.death_chakram.tick_time end,
|
|
value = function () return state.conduit.necrotic_barrage.enabled and 5 or 3 end,
|
|
}
|
|
} )
|
|
|
|
-- Talents
|
|
spec:RegisterTalents( {
|
|
vipers_venom = 22275, -- 268501
|
|
terms_of_engagement = 22283, -- 265895
|
|
alpha_predator = 22296, -- 269737
|
|
|
|
guerrilla_tactics = 21997, -- 264332
|
|
hydras_bite = 22769, -- 260241
|
|
butchery = 22297, -- 212436
|
|
|
|
trailblazer = 19347, -- 199921
|
|
natural_mending = 19348, -- 270581
|
|
camouflage = 23100, -- 199483
|
|
|
|
bloodseeker = 22277, -- 260248
|
|
steel_trap = 19361, -- 162488
|
|
a_murder_of_crows = 22299, -- 131894
|
|
|
|
born_to_be_wild = 22268, -- 266921
|
|
posthaste = 22276, -- 109215
|
|
binding_shot = 22499, -- 109248
|
|
|
|
tip_of_the_spear = 22300, -- 260285
|
|
mongoose_bite = 22278, -- 259387
|
|
flanking_strike = 22271, -- 269751
|
|
|
|
birds_of_prey = 22272, -- 260331
|
|
wildfire_infusion = 22301, -- 271014
|
|
chakrams = 23105, -- 259391
|
|
} )
|
|
|
|
-- PvP Talents
|
|
spec:RegisterPvpTalents( {
|
|
chimaeral_sting = 3609, -- 356719
|
|
diamond_ice = 686, -- 203340
|
|
dragonscale_armor = 3610, -- 202589
|
|
hiexplosive_trap = 3606, -- 236776
|
|
hunting_pack = 661, -- 203235
|
|
mending_bandage = 662, -- 212640
|
|
roar_of_sacrifice = 663, -- 53480
|
|
sticky_tar = 664, -- 203264
|
|
survival_tactics = 3607, -- 202746
|
|
trackers_net = 665, -- 212638
|
|
tranquilizing_darts = 5420, -- 356015
|
|
wild_kingdom = 5443, -- 356707
|
|
} )
|
|
|
|
-- Auras
|
|
spec:RegisterAuras( {
|
|
a_murder_of_crows = {
|
|
id = 131894,
|
|
duration = 15,
|
|
max_stack = 1,
|
|
},
|
|
aspect_of_the_eagle = {
|
|
id = 186289,
|
|
duration = 15,
|
|
max_stack = 1,
|
|
},
|
|
aspect_of_the_turtle = {
|
|
id = 186265,
|
|
duration = 8,
|
|
max_stack = 1,
|
|
},
|
|
binding_shot = {
|
|
id = 117405,
|
|
duration = 3600,
|
|
max_stack = 1,
|
|
},
|
|
camouflage = {
|
|
id = 199483,
|
|
duration = 60,
|
|
max_stack = 1,
|
|
},
|
|
coordinated_assault = {
|
|
id = 266779,
|
|
duration = function () return 20 + ( conduit.deadly_tandem.mod * 0.001 ) end,
|
|
max_stack = 1,
|
|
},
|
|
eagle_eye = {
|
|
id = 6197,
|
|
},
|
|
feign_death = {
|
|
id = 5384,
|
|
duration = 360,
|
|
max_stack = 1,
|
|
},
|
|
freezing_trap = {
|
|
id = 3355,
|
|
duration = 60,
|
|
type = "Magic",
|
|
max_stack = 1,
|
|
},
|
|
growl = {
|
|
id = 2649,
|
|
duration = 3,
|
|
max_stack = 1,
|
|
},
|
|
harpoon = {
|
|
id = 190927,
|
|
duration = 3,
|
|
max_stack = 1,
|
|
},
|
|
hunters_mark = {
|
|
id = 257284,
|
|
duration = 3600,
|
|
type = "Magic",
|
|
max_stack = 1,
|
|
},
|
|
internal_bleeding = {
|
|
id = 270343,
|
|
duration = 9,
|
|
max_stack = 3
|
|
},
|
|
intimidation = {
|
|
id = 24394,
|
|
duration = 5,
|
|
max_stack = 1,
|
|
},
|
|
kill_command = {
|
|
id = 259277,
|
|
duration = 8,
|
|
max_stack = 1,
|
|
copy = "bloodseeker"
|
|
},
|
|
masters_call = {
|
|
id = 54216,
|
|
duration = 4,
|
|
type = "Magic",
|
|
max_stack = 1,
|
|
},
|
|
misdirection = {
|
|
id = 35079,
|
|
duration = 8,
|
|
max_stack = 1,
|
|
},
|
|
mongoose_fury = {
|
|
id = 259388,
|
|
duration = 14,
|
|
max_stack = 5,
|
|
},
|
|
pathfinding = {
|
|
id = 264656,
|
|
duration = 3600,
|
|
max_stack = 1,
|
|
},
|
|
pheromone_bomb = {
|
|
id = 270332,
|
|
duration = 6,
|
|
max_stack = 1,
|
|
},
|
|
posthaste = {
|
|
id = 118922,
|
|
duration = 4,
|
|
max_stack = 1,
|
|
},
|
|
predator = {
|
|
id = 260249,
|
|
duratinon = 3600,
|
|
max_stack = 10,
|
|
},
|
|
serpent_sting = {
|
|
id = 259491,
|
|
duration = function () return 12 * haste end,
|
|
tick_time = function () return 3 * haste end,
|
|
type = "Poison",
|
|
max_stack = 1,
|
|
},
|
|
shrapnel_bomb = {
|
|
id = 270339,
|
|
duration = 6,
|
|
max_stack = 1,
|
|
},
|
|
steel_trap = {
|
|
id = 162487,
|
|
duration = 20,
|
|
max_stack = 1,
|
|
},
|
|
steel_trap_immobilize = {
|
|
id = 162480,
|
|
duration = 20,
|
|
max_stack = 1,
|
|
},
|
|
tar_trap = {
|
|
id = 135299,
|
|
duration = 3600,
|
|
max_stack = 1,
|
|
},
|
|
terms_of_engagement = {
|
|
id = 265898,
|
|
duration = 10,
|
|
max_stack = 1,
|
|
},
|
|
tip_of_the_spear = {
|
|
id = 260286,
|
|
duration = 10,
|
|
max_stack = 3,
|
|
},
|
|
trailblazer = {
|
|
id = 231390,
|
|
duration = 3600,
|
|
max_stack = 1,
|
|
},
|
|
vipers_venom = {
|
|
id = 268552,
|
|
duration = 8,
|
|
max_stack = 1,
|
|
},
|
|
volatile_bomb = {
|
|
id = 271049,
|
|
duration = 6,
|
|
max_stack = 1,
|
|
},
|
|
wildfire_bomb_dot = {
|
|
id = 269747,
|
|
duration = 6,
|
|
max_stack = 1,
|
|
},
|
|
wildfire_bomb = {
|
|
alias = { "wildfire_bomb_dot", "shrapnel_bomb", "pheromone_bomb", "volatile_bomb" },
|
|
aliasType = "debuff",
|
|
aliasMode = "longest"
|
|
},
|
|
wing_clip = {
|
|
id = 195645,
|
|
duration = 15,
|
|
max_stack = 1,
|
|
},
|
|
|
|
-- AZERITE POWERS
|
|
blur_of_talons = {
|
|
id = 277969,
|
|
duration = 6,
|
|
max_stack = 5,
|
|
},
|
|
|
|
latent_poison = {
|
|
id = 273286,
|
|
duration = 20,
|
|
max_stack = 10
|
|
},
|
|
|
|
primeval_intuition = {
|
|
id = 288573,
|
|
duration = 12,
|
|
max_stack = 5,
|
|
},
|
|
|
|
-- Legendaries
|
|
latent_poison_injection = {
|
|
id = 336903,
|
|
duration = 15,
|
|
max_stack = 10
|
|
},
|
|
|
|
nessingwarys_trapping_apparatus = {
|
|
id = 336744,
|
|
duration = 5,
|
|
max_stack = 1,
|
|
copy = { "nesingwarys_trapping_apparatus", "nesingwarys_apparatus", "nessingwarys_apparatus" }
|
|
},
|
|
|
|
-- Conduits
|
|
strength_of_the_pack = {
|
|
id = 341223,
|
|
duration = 4,
|
|
max_stack = 1
|
|
}
|
|
} )
|
|
|
|
|
|
spec:RegisterHook( "runHandler", function( action, pool )
|
|
if buff.camouflage.up and action ~= "camouflage" then removeBuff( "camouflage" ) end
|
|
if buff.feign_death.up and action ~= "feign_death" then removeBuff( "feign_death" ) end
|
|
end )
|
|
|
|
|
|
spec:RegisterStateExpr( "current_wildfire_bomb", function () return "wildfire_bomb" end )
|
|
|
|
spec:RegisterStateExpr( "check_focus_overcap", function ()
|
|
if settings.allow_focus_overcap then return true end
|
|
if not this_action then return focus.current + focus.regen * gcd.max <= focus.max end
|
|
return focus.current + cast_regen <= focus.max
|
|
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 pheromoneReset = false
|
|
local FindUnitDebuffByID = ns.FindUnitDebuffByID
|
|
|
|
spec:RegisterCombatLogEvent( function ( _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName )
|
|
if sourceGUID == state.GUID and spellID == 259489 and subtype == "SPELL_CAST_SUCCESS" then
|
|
pheromoneReset = FindUnitDebuffByID( "target", 270332 ) and true or false
|
|
end
|
|
end )
|
|
|
|
|
|
local ExpireNesingwarysTrappingApparatus = setfenv( function()
|
|
focus.regen = focus.regen * 0.5
|
|
forecastResources( "focus" )
|
|
end, state )
|
|
|
|
|
|
-- Tier 28
|
|
spec:RegisterSetBonuses( "tier28_2pc", 364490, "tier28_4pc", 363667 )
|
|
-- 2-Set - Mad Bombardier - When Kill Command resets, it has a 40% chance to make your next Wildfire Bomb incur no cooldown.
|
|
-- 4-Set - Mad Bombardier - Your Wildfire Bombs deal 30% additional damage. This bonus is increased to 80% for bombs empowered by Mad Bombardier.
|
|
spec:RegisterAura( "mad_bombardier", {
|
|
id = 363805,
|
|
duration = 20,
|
|
max_stack = 1,
|
|
} )
|
|
|
|
|
|
spec:RegisterHook( "reset_precast", function()
|
|
if talent.wildfire_infusion.enabled then
|
|
if IsActiveSpell( 270335 ) then current_wildfire_bomb = "shrapnel_bomb"
|
|
elseif IsActiveSpell( 270323 ) then current_wildfire_bomb = "pheromone_bomb"
|
|
elseif IsActiveSpell( 271045 ) then current_wildfire_bomb = "volatile_bomb"
|
|
else current_wildfire_bomb = "wildfire_bomb" end
|
|
else
|
|
current_wildfire_bomb = "wildfire_bomb"
|
|
end
|
|
|
|
if prev_gcd[1].kill_command and pheromoneReset and ( now - action.kill_command.lastCast < 0.25 ) then
|
|
setCooldown( "kill_command", 0 )
|
|
end
|
|
|
|
if now - action.harpoon.lastCast < 1.5 then
|
|
setDistance( 5 )
|
|
end
|
|
|
|
if debuff.tar_trap.up then
|
|
debuff.tar_trap.expires = debuff.tar_trap.applied + 30
|
|
end
|
|
|
|
if buff.nesingwarys_apparatus.up then
|
|
state:QueueAuraExpiration( "nesingwarys_apparatus", ExpireNesingwarysTrappingApparatus, buff.nesingwarys_apparatus.expires )
|
|
end
|
|
|
|
if now - action.resonating_arrow.lastCast < 6 then applyBuff( "resonating_arrow", 10 - ( now - action.resonating_arrow.lastCast ) ) end
|
|
end )
|
|
|
|
spec:RegisterHook( "specializationChanged", function ()
|
|
current_wildfire_bomb = nil
|
|
end )
|
|
|
|
spec:RegisterStateTable( "next_wi_bomb", setmetatable( {}, {
|
|
__index = function( t, k )
|
|
if k == "shrapnel" then return current_wildfire_bomb == "shrapnel_bomb"
|
|
elseif k == "pheromone" then return current_wildfire_bomb == "pheromone_bomb"
|
|
elseif k == "volatile" then return current_wildfire_bomb == "volatile_bomb" end
|
|
return false
|
|
end
|
|
} ) )
|
|
|
|
spec:RegisterStateTable( "bloodseeker", setmetatable( {}, {
|
|
__index = function( t, k )
|
|
if k == "count" then
|
|
return active_dot.kill_command
|
|
end
|
|
|
|
return debuff.kill_command[ k ]
|
|
end,
|
|
} ) )
|
|
|
|
|
|
spec:RegisterStateExpr( "bloodseeker", function () return debuff.bloodseeker end )
|
|
|
|
|
|
-- Abilities
|
|
spec:RegisterAbilities( {
|
|
a_murder_of_crows = {
|
|
id = 131894,
|
|
cast = 0,
|
|
cooldown = 60,
|
|
gcd = "spell",
|
|
|
|
spend = 30,
|
|
spendType = "focus",
|
|
|
|
toggle = "cooldowns",
|
|
|
|
startsCombat = true,
|
|
texture = 645217,
|
|
|
|
talent = "a_murder_of_crows",
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "a_murder_of_crows" )
|
|
end,
|
|
},
|
|
|
|
|
|
aspect_of_the_cheetah = {
|
|
id = 186257,
|
|
cast = 0,
|
|
cooldown = function () return ( 180 * ( legendary.call_of_the_wild.enabled and 0.75 or 1 ) * ( talent.born_to_be_wild.enabled and 0.8 or 1 ) ) + ( conduit.cheetahs_vigor.mod * 0.001 ) end,
|
|
gcd = "spell",
|
|
|
|
startsCombat = false,
|
|
texture = 132242,
|
|
|
|
handler = function ()
|
|
applyBuff( "aspect_of_the_cheetah_sprint" )
|
|
applyBuff( "aspect_of_the_cheetah" )
|
|
end,
|
|
},
|
|
|
|
|
|
aspect_of_the_eagle = {
|
|
id = 186289,
|
|
cast = 0,
|
|
cooldown = function () return 90 * ( legendary.call_of_the_wild.enabled and 0.75 or 1 ) * ( talent.born_to_be_wild.enabled and 0.8 or 1 ) end,
|
|
gcd = "off",
|
|
|
|
toggle = "cooldowns",
|
|
|
|
startsCombat = false,
|
|
texture = 612363,
|
|
|
|
handler = function ()
|
|
applyBuff( "aspect_of_the_eagle" )
|
|
end,
|
|
},
|
|
|
|
|
|
aspect_of_the_turtle = {
|
|
id = 186265,
|
|
cast = 0,
|
|
cooldown = function () return ( 180 * ( legendary.call_of_the_wild.enabled and 0.75 or 1 ) * ( talent.born_to_be_wild.enabled and 0.8 or 1 ) ) + ( conduit.harmony_of_the_tortollan.mod * 0.001 ) end,
|
|
gcd = "spell",
|
|
|
|
toggle = "defensives",
|
|
|
|
startsCombat = false,
|
|
texture = 132199,
|
|
|
|
handler = function ()
|
|
applyBuff( "aspect_of_the_turtle" )
|
|
setCooldown( "global_cooldown", 8 )
|
|
end,
|
|
},
|
|
|
|
|
|
binding_shot = {
|
|
id = 109248,
|
|
cast = 0,
|
|
cooldown = 45,
|
|
gcd = "spell",
|
|
|
|
startsCombat = false,
|
|
texture = 462650,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "binding_shot" )
|
|
end,
|
|
},
|
|
|
|
|
|
butchery = {
|
|
id = 212436,
|
|
cast = 0,
|
|
charges = 3,
|
|
cooldown = 9,
|
|
recharge = 9,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
spend = 30,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 999948,
|
|
|
|
aura = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
cycle = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
|
|
talent = "butchery",
|
|
|
|
usable = function () return charges > 1 or active_enemies > 1 or target.time_to_die < ( 9 * haste ) end,
|
|
handler = function ()
|
|
gainChargeTime( "wildfire_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "shrapnel_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "volatile_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "pheromone_bomb", min( 5, active_enemies ) )
|
|
|
|
if talent.birds_of_prey.enabled and buff.coordinated_assault.up and UnitIsUnit( "pettarget", "target" ) then
|
|
buff.coordinated_assault.expires = buff.coordinated_assault.expires + 1.5
|
|
end
|
|
|
|
if debuff.shrapnel_bomb.up then applyDebuff( "target", "internal_bleeding", 9, min( 3, debuff.internal_bleeding.stack + 1 ) ) end
|
|
|
|
removeBuff( "butchers_bone_fragments" )
|
|
|
|
if conduit.flame_infusion.enabled then
|
|
addStack( "flame_infusion", nil, 1 )
|
|
end
|
|
end,
|
|
},
|
|
|
|
|
|
camouflage = {
|
|
id = 199483,
|
|
cast = 0,
|
|
cooldown = 60,
|
|
gcd = "spell",
|
|
|
|
startsCombat = false,
|
|
texture = 461113,
|
|
|
|
talent = "camouflage",
|
|
|
|
usable = function () return time == 0 end,
|
|
handler = function ()
|
|
applyBuff( "camouflage" )
|
|
end,
|
|
},
|
|
|
|
|
|
carve = {
|
|
id = 187708,
|
|
cast = 0,
|
|
cooldown = 6,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
spend = 35,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 1376039,
|
|
|
|
-- aura = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
-- cycle = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
|
|
notalent = "butchery",
|
|
|
|
handler = function ()
|
|
gainChargeTime( "wildfire_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "shrapnel_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "volatile_bomb", min( 5, active_enemies ) )
|
|
gainChargeTime( "pheromone_bomb", min( 5, active_enemies ) )
|
|
|
|
if debuff.shrapnel_bomb.up then applyDebuff( "target", "internal_bleeding", 9, min( 3, debuff.internal_bleeding.stack + 1 ) ) end
|
|
|
|
if talent.birds_of_prey.enabled and buff.coordinated_assault.up and UnitIsUnit( "pettarget", "target" ) then
|
|
buff.coordinated_assault.expires = buff.coordinated_assault.expires + 1.5
|
|
end
|
|
|
|
removeBuff( "butchers_bone_fragments" )
|
|
|
|
if conduit.flame_infusion.enabled then
|
|
addStack( "flame_infusion", nil, 1 )
|
|
end
|
|
end,
|
|
|
|
auras = {
|
|
-- Conduit
|
|
flame_infusion = {
|
|
id = 341401,
|
|
duration = 8,
|
|
max_stack = 2,
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
chakrams = {
|
|
id = 259391,
|
|
cast = 0,
|
|
cooldown = 20,
|
|
gcd = "spell",
|
|
|
|
spend = 15,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 648707,
|
|
|
|
talent = "chakrams",
|
|
|
|
handler = function ()
|
|
end,
|
|
},
|
|
|
|
|
|
coordinated_assault = {
|
|
id = 266779,
|
|
cast = 0,
|
|
cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( legendary.call_of_the_wild.enabled and 0.75 or 1 ) * 120 end,
|
|
gcd = "spell",
|
|
|
|
toggle = "cooldowns",
|
|
|
|
startsCombat = false,
|
|
texture = 2065565,
|
|
|
|
nobuff = function ()
|
|
if settings.ca_vop_overlap then return end
|
|
return "coordinated_assault"
|
|
end,
|
|
|
|
usable = function () return pet.alive end,
|
|
handler = function ()
|
|
applyBuff( "coordinated_assault" )
|
|
end,
|
|
},
|
|
|
|
|
|
disengage = {
|
|
id = 781,
|
|
cast = 0,
|
|
cooldown = 20,
|
|
gcd = "off",
|
|
|
|
startsCombat = false,
|
|
texture = 132294,
|
|
|
|
handler = function ()
|
|
setDistance( 15 )
|
|
if talent.posthaste.enabled then applyBuff( "posthaste" ) end
|
|
if conduit.tactical_retreat.enabled and target.within8 then applyDebuff( "target", "tactical_retreat" ) end
|
|
end,
|
|
},
|
|
|
|
|
|
--[[ eagle_eye = {
|
|
id = 6197,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 132172,
|
|
|
|
handler = function ()
|
|
end,
|
|
}, ]]
|
|
|
|
|
|
exhilaration = {
|
|
id = 109304,
|
|
cast = 0,
|
|
cooldown = 120,
|
|
gcd = "spell",
|
|
|
|
toggle = "defensives",
|
|
|
|
startsCombat = false,
|
|
texture = 461117,
|
|
|
|
handler = function ()
|
|
gain( 0.3 * health.max, "health" )
|
|
if conduit.rejuvenating_wind.enabled then applyBuff( "rejuvenating_wind" ) end
|
|
end,
|
|
},
|
|
|
|
|
|
--[[ Using from BM module.
|
|
feign_death = {
|
|
id = 5384,
|
|
cast = 0,
|
|
cooldown = 30,
|
|
gcd = "off",
|
|
|
|
startsCombat = false,
|
|
texture = 132293,
|
|
|
|
handler = function ()
|
|
applyBuff( "feign_death" )
|
|
end,
|
|
}, ]]
|
|
|
|
|
|
flanking_strike = {
|
|
id = 269751,
|
|
cast = 0,
|
|
cooldown = 30,
|
|
gcd = "spell",
|
|
|
|
spend = -30,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 236184,
|
|
|
|
talent = "flanking_strike",
|
|
|
|
usable = function () return pet.alive end,
|
|
},
|
|
|
|
|
|
--[[ flare = {
|
|
id = 1543,
|
|
cast = 0,
|
|
cooldown = 20,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 135815,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "flare" )
|
|
end,
|
|
}, ]]
|
|
|
|
|
|
freezing_trap = {
|
|
id = 187650,
|
|
cast = 0,
|
|
cooldown = 30,
|
|
gcd = "spell",
|
|
|
|
spend = function ()
|
|
if legendary.nessingwarys_trapping_apparatus.enabled then
|
|
return -45, "focus"
|
|
end
|
|
end,
|
|
|
|
startsCombat = false,
|
|
texture = 135834,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "freezing_trap" )
|
|
end,
|
|
},
|
|
|
|
|
|
harpoon = {
|
|
id = 190925,
|
|
cast = 0,
|
|
charges = 1,
|
|
cooldown = 20,
|
|
recharge = 20,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 1376040,
|
|
|
|
usable = function () return settings.use_harpoon and target.distance > 8, "harpoon disabled or target too close" end,
|
|
handler = function ()
|
|
applyDebuff( "target", "harpoon" )
|
|
if talent.terms_of_engagement.enabled then applyBuff( "terms_of_engagement" ) end
|
|
setDistance( 5 )
|
|
end,
|
|
},
|
|
|
|
|
|
hunters_mark = {
|
|
id = 257284,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
startsCombat = false,
|
|
texture = 236188,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "hunters_mark" )
|
|
end,
|
|
},
|
|
|
|
|
|
intimidation = {
|
|
id = 19577,
|
|
cast = 0,
|
|
cooldown = 60,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 132111,
|
|
|
|
usable = function () return pet.alive, "requires a living pet" end,
|
|
handler = function ()
|
|
applyDebuff( "target", "intimidation" )
|
|
end,
|
|
},
|
|
|
|
|
|
kill_command = {
|
|
id = 259489,
|
|
cast = 0,
|
|
charges = function () return talent.alpha_predator.enabled and 2 or nil end,
|
|
cooldown = 6,
|
|
recharge = 6,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
spend = -15,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 132176,
|
|
|
|
cycle = function () return talent.bloodseeker.enabled and "kill_command" or nil end,
|
|
|
|
usable = function () return pet.alive, "requires a living pet" end,
|
|
handler = function ()
|
|
if talent.bloodseeker.enabled then
|
|
applyBuff( "predator", 8 )
|
|
applyDebuff( "target", "kill_command", 8 )
|
|
end
|
|
|
|
if talent.tip_of_the_spear.enabled then addStack( "tip_of_the_spear", 20, 1 ) end
|
|
|
|
if debuff.pheromone_bomb.up then
|
|
gainCharges( "kill_command", 1 )
|
|
end
|
|
|
|
if debuff.shrapnel_bomb.up then applyDebuff( "target", "internal_bleeding", 9, min( 3, debuff.internal_bleeding.stack + 1 ) ) end
|
|
end,
|
|
},
|
|
|
|
|
|
kill_shot = {
|
|
id = 320976,
|
|
cast = 0,
|
|
cooldown = 10,
|
|
gcd = "spell",
|
|
|
|
spend = function () return buff.flayers_mark.up and 0 or 10 end,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 236174,
|
|
|
|
usable = function () return buff.flayers_mark.up or target.health_pct < 20, "requires target health below 20 percent" end,
|
|
handler = function ()
|
|
if buff.flayers_mark.up and legendary.pouch_of_razor_fragments.enabled then
|
|
applyDebuff( "target", "pouch_of_razor_fragments" )
|
|
removeBuff( "flayers_mark" )
|
|
end
|
|
end,
|
|
},
|
|
|
|
|
|
masters_call = {
|
|
id = 272682,
|
|
cast = 0,
|
|
cooldown = 45,
|
|
gcd = "off",
|
|
|
|
startsCombat = false,
|
|
texture = 236189,
|
|
|
|
usable = function () return pet.alive, "requires a living pet" end,
|
|
handler = function ()
|
|
applyBuff( "masters_call" )
|
|
end,
|
|
},
|
|
|
|
|
|
misdirection = {
|
|
id = 34477,
|
|
cast = 0,
|
|
cooldown = 30,
|
|
gcd = "off",
|
|
|
|
startsCombat = false,
|
|
texture = 132180,
|
|
|
|
usable = function () return pet.alive or group, "requires a living pet or ally" end,
|
|
handler = function ()
|
|
applyBuff( "misdirection" )
|
|
end,
|
|
},
|
|
|
|
|
|
mongoose_bite = {
|
|
id = 259387,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
spend = 30,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 1376044,
|
|
|
|
aura = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
cycle = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
|
|
talent = "mongoose_bite",
|
|
|
|
handler = function ()
|
|
if buff.mongoose_fury.down then applyBuff( "mongoose_fury" )
|
|
else applyBuff( "mongoose_fury", buff.mongoose_fury.remains, min( 5, buff.mongoose_fury.stack + 1 ) ) end
|
|
if debuff.shrapnel_bomb.up then
|
|
if debuff.internal_bleeding.up then applyDebuff( "target", "internal_bleeding", 9, debuff.internal_bleeding.stack + 1 ) end
|
|
end
|
|
|
|
removeDebuff( "target", "latent_poison" )
|
|
removeDebuff( "target", "latent_poison_injection" )
|
|
|
|
if azerite.wilderness_survival.enabled then
|
|
gainChargeTime( "wildfire_bomb", 1 )
|
|
if talent.wildfire_infusion.enabled then
|
|
gainChargeTime( "shrapnel_bomb", 1 )
|
|
gainChargeTime( "pheromone_bomb", 1 )
|
|
gainChargeTime( "volatile_bomb", 1 )
|
|
end
|
|
end
|
|
|
|
if azerite.primeval_intuition.enabled then
|
|
addStack( "primeval_intuition", nil, 1 )
|
|
end
|
|
|
|
if azerite.blur_of_talons.enabled and buff.coordinated_assault.up then
|
|
addStack( "blur_of_talons", nil, 1)
|
|
end
|
|
|
|
if legendary.butchers_bone_fragments.enabled then
|
|
addStack( "butchers_bone_fragments", nil, 1 )
|
|
end
|
|
end,
|
|
|
|
copy = { 265888, "mongoose_bite_eagle" }
|
|
},
|
|
|
|
|
|
muzzle = {
|
|
id = 187707,
|
|
cast = 0,
|
|
cooldown = 15,
|
|
gcd = "off",
|
|
|
|
startsCombat = true,
|
|
texture = 1376045,
|
|
|
|
toggle = "interrupts",
|
|
|
|
debuff = "casting",
|
|
readyTime = state.timeToInterrupt,
|
|
|
|
handler = function ()
|
|
if conduit.reversal_of_fortune.enabled then
|
|
gain( conduit.reversal_of_fortune.mod, "focus" )
|
|
end
|
|
|
|
interrupt()
|
|
end,
|
|
},
|
|
|
|
|
|
pheromone_bomb = {
|
|
id = 270323,
|
|
known = 259495,
|
|
cast = 0,
|
|
charges = function () return talent.guerrilla_tactics.enabled and 2 or nil end,
|
|
cooldown = 18,
|
|
recharge = 18,
|
|
hasteCD = true,
|
|
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
|
|
bind = "wildfire_bomb",
|
|
talent = "wildfire_infusion",
|
|
velocity = 35,
|
|
|
|
usable = function () return current_wildfire_bomb == "pheromone_bomb" end,
|
|
start = function () end,
|
|
impact = function ()
|
|
if buff.mad_bombardier.up then
|
|
gainCharges( "wildfire_bomb", 1 )
|
|
removeBuff( "mad_bombardier" )
|
|
end
|
|
applyDebuff( "target", "pheromone_bomb" )
|
|
end,
|
|
|
|
copy = 270329,
|
|
|
|
unlisted = true,
|
|
},
|
|
|
|
|
|
raptor_strike = {
|
|
id = 186270,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
spend = 30,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 1376046,
|
|
|
|
aura = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
cycle = function () return debuff.shrapnel_bomb.up and "internal_bleeding" or nil end,
|
|
|
|
notalent = "mongoose_bite",
|
|
|
|
handler = function ()
|
|
removeBuff( "tip_of_the_spear" )
|
|
|
|
if debuff.shrapnel_bomb.up then
|
|
if debuff.internal_bleeding.up then applyDebuff( "target", "internal_bleeding", 9, debuff.internal_bleeding.stack + 1 ) end
|
|
end
|
|
|
|
if talent.birds_of_prey.enabled and buff.coordinated_assault.up and UnitIsUnit( "pettarget", "target" ) then
|
|
buff.coordinated_assault.expires = buff.coordinated_assault.expires + 1.5
|
|
end
|
|
|
|
removeDebuff( "target", "latent_poison" )
|
|
removeDebuff( "target", "latent_poison_injection" )
|
|
|
|
if azerite.wilderness_survival.enabled then
|
|
gainChargeTime( "wildfire_bomb", 1 )
|
|
if talent.wildfire_infusion.enabled then
|
|
gainChargeTime( "shrapnel_bomb", 1 )
|
|
gainChargeTime( "pheromone_bomb", 1 )
|
|
gainChargeTime( "volatile_bomb", 1 )
|
|
end
|
|
end
|
|
|
|
if azerite.primeval_intuition.enabled then
|
|
addStack( "primeval_intuition", nil, 1 )
|
|
end
|
|
|
|
if azerite.blur_of_talons.enabled and buff.coordinated_assault.up then
|
|
addStack( "blur_of_talons", nil, 1)
|
|
end
|
|
|
|
if legendary.butchers_bone_fragments.enabled then
|
|
addStack( "butchers_bone_fragments", nil, 1 )
|
|
end
|
|
end,
|
|
|
|
copy = { "raptor_strike_eagle", 265189 },
|
|
|
|
auras = {
|
|
butchers_bone_fragments = {
|
|
id = 336908,
|
|
duration = 12,
|
|
max_stack = 6,
|
|
},
|
|
}
|
|
},
|
|
|
|
|
|
serpent_sting = {
|
|
id = 259491,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
spend = function () return buff.vipers_venom.up and 0 or 20 end,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 1033905,
|
|
|
|
velocity = 60,
|
|
|
|
start = function ()
|
|
removeBuff( "vipers_venom" )
|
|
end,
|
|
|
|
impact = function ()
|
|
applyDebuff( "target", "serpent_sting" )
|
|
|
|
if azerite.latent_poison.enabled then
|
|
applyDebuff( "target", "latent_poison" )
|
|
end
|
|
|
|
if legendary.latent_poison_injectors.enabled then
|
|
applyDebuff( "target", "latent_poison_injection", nil, debuff.latent_poison_injection.stack + 1 )
|
|
end
|
|
end,
|
|
},
|
|
|
|
|
|
shrapnel_bomb = {
|
|
id = 270335,
|
|
known = 259495,
|
|
cast = 0,
|
|
charges = function () return talent.guerrilla_tactics.enabled and 2 or nil end,
|
|
cooldown = 18,
|
|
recharge = 18,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
|
|
bind = "wildfire_bomb",
|
|
talent = "wildfire_infusion",
|
|
velocity = 35,
|
|
|
|
usable = function () return current_wildfire_bomb == "shrapnel_bomb" end,
|
|
start = function () end,
|
|
impact = function ()
|
|
if buff.mad_bombardier.up then
|
|
gainCharges( "wildfire_bomb", 1 )
|
|
removeBuff( "mad_bombardier" )
|
|
end
|
|
applyDebuff( "target", "shrapnel_bomb" )
|
|
end,
|
|
|
|
copy = 270338,
|
|
|
|
unlisted = true,
|
|
},
|
|
|
|
|
|
steady_shot = {
|
|
id = 56641,
|
|
cast = 1.75,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 132213,
|
|
|
|
handler = function ()
|
|
end,
|
|
},
|
|
|
|
|
|
steel_trap = {
|
|
id = 162488,
|
|
cast = 0,
|
|
cooldown = 30,
|
|
gcd = "spell",
|
|
|
|
spend = function ()
|
|
if legendary.nessingwarys_trapping_apparatus.enabled then
|
|
return -45, "focus"
|
|
end
|
|
end,
|
|
|
|
startsCombat = false,
|
|
texture = 1467588,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "steel_trap" )
|
|
end,
|
|
},
|
|
|
|
|
|
summon_pet = {
|
|
id = 883,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
spend = 0,
|
|
spendType = "focus",
|
|
|
|
startsCombat = false,
|
|
texture = 'Interface\\ICONS\\Ability_Hunter_BeastCall',
|
|
|
|
essential = true,
|
|
nomounted = true,
|
|
|
|
usable = function () return not pet.exists end,
|
|
handler = function ()
|
|
summonPet( "made_up_pet", 3600, "ferocity" )
|
|
end,
|
|
},
|
|
|
|
|
|
tar_trap = {
|
|
id = 187698,
|
|
cast = 0,
|
|
cooldown = function () return level > 55 and 25 or 30 end,
|
|
gcd = "spell",
|
|
|
|
spend = function ()
|
|
if legendary.nessingwarys_trapping_apparatus.enabled then
|
|
return -45, "focus"
|
|
end
|
|
end,
|
|
|
|
startsCombat = false,
|
|
texture = 576309,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "tar_trap" )
|
|
end,
|
|
},
|
|
|
|
|
|
tranquilizing_shot = {
|
|
id = 19801,
|
|
cast = 0,
|
|
cooldown = 10,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
texture = 136020,
|
|
|
|
toggle = "interrupts",
|
|
|
|
usable = function () return buff.dispellable_enrage.up or buff.dispellable_magic.up, "requires dispellable_enrage or dispellable_magic" end,
|
|
handler = function ()
|
|
removeBuff( "dispellable_enrage" )
|
|
removeBuff( "dispellable_magic" )
|
|
if level > 53 then gain( 10, "focus" ) end
|
|
end,
|
|
},
|
|
|
|
|
|
volatile_bomb = {
|
|
id = 271045,
|
|
known = 259495,
|
|
cast = 0,
|
|
charges = function () return talent.guerrilla_tactics.enabled and 2 or nil end,
|
|
cooldown = 18,
|
|
recharge = 18,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
|
|
bind = "wildfire_bomb",
|
|
talent = "wildfire_infusion",
|
|
velocity = 35,
|
|
|
|
usable = function () return current_wildfire_bomb == "volatile_bomb" end,
|
|
|
|
start = function ()
|
|
end,
|
|
|
|
impact = function ()
|
|
if buff.mad_bombardier.up then
|
|
gainCharges( "wildfire_bomb", 1 )
|
|
removeBuff( "mad_bombardier" )
|
|
end
|
|
applyDebuff( "target", "volatile_bomb" )
|
|
if debuff.serpent_sting.up then applyDebuff( "target", "serpent_sting" ) end
|
|
end,
|
|
|
|
copy = 271048,
|
|
|
|
unlisted = true,
|
|
},
|
|
|
|
|
|
wildfire_bomb = {
|
|
id = function ()
|
|
if current_wildfire_bomb == "wildfire_bomb" then return 259495
|
|
elseif current_wildfire_bomb == "pheromone_bomb" then return 270323
|
|
elseif current_wildfire_bomb == "shrapnel_bomb" then return 270335
|
|
elseif current_wildfire_bomb == "volatile_bomb" then return 271045 end
|
|
return 259495
|
|
end,
|
|
flash = { 270335, 270323, 271045, 259495 },
|
|
known = 259495,
|
|
cast = 0,
|
|
charges = function () return talent.guerrilla_tactics.enabled and 2 or nil end,
|
|
cooldown = 18,
|
|
recharge = 18,
|
|
hasteCD = true,
|
|
gcd = "spell",
|
|
|
|
startsCombat = true,
|
|
|
|
bind = function () return current_wildfire_bomb end,
|
|
velocity = 35,
|
|
|
|
start = function ()
|
|
removeBuff( "flame_infusion" )
|
|
end,
|
|
|
|
impact = function ()
|
|
if not talent.wildfire_infusion.enabled and buff.mad_bombardier.up then
|
|
gainCharges( "wildfire_bomb", 1 )
|
|
removeBuff( "mad_bombardier" )
|
|
end
|
|
if current_wildfire_bomb == "wildfire_bomb" then applyDebuff( "target", "wildfire_bomb_dot" )
|
|
else class.abilities[ current_wildfire_bomb ].impact() end
|
|
current_wildfire_bomb = "wildfire_bomb"
|
|
end,
|
|
|
|
impactSpell = function ()
|
|
if not talent.wildfire_infusion.enabled then return "wildfire_bomb" end
|
|
if IsActiveSpell( 270335 ) then return "shrapnel_bomb" end
|
|
if IsActiveSpell( 270323 ) then return "pheromone_bomb" end
|
|
if IsActiveSpell( 271045 ) then return "volatile_bomb" end
|
|
return "wildfire_bomb"
|
|
end,
|
|
|
|
impactSpells = {
|
|
wildfire_bomb = true,
|
|
shrapnel_bomb = true,
|
|
pheromone_bomb = true,
|
|
volatile_bomb = true
|
|
},
|
|
|
|
copy = 259495, -- { 271045, 270335, 270323, 259495 }
|
|
},
|
|
|
|
|
|
wing_clip = {
|
|
id = 195645,
|
|
cast = 0,
|
|
cooldown = 0,
|
|
gcd = "spell",
|
|
|
|
spend = 20,
|
|
spendType = "focus",
|
|
|
|
startsCombat = true,
|
|
texture = 132309,
|
|
|
|
handler = function ()
|
|
applyDebuff( "target", "wing_clip" )
|
|
end,
|
|
},
|
|
} )
|
|
|
|
|
|
spec:RegisterOptions( {
|
|
enabled = true,
|
|
|
|
aoe = 2,
|
|
|
|
nameplates = true,
|
|
nameplateRange = 8,
|
|
|
|
damage = true,
|
|
damageExpiration = 8,
|
|
|
|
potion = "spectral_agility",
|
|
|
|
package = "Survival"
|
|
} )
|
|
|
|
|
|
spec:RegisterSetting( "use_harpoon", true, {
|
|
name = "|T1376040:0|t Use Harpoon",
|
|
desc = "If checked, the addon will recommend |T1376040:0|t Harpoon when you are out of range and Harpoon is available.",
|
|
type = "toggle",
|
|
width = 1.49
|
|
} )
|
|
|
|
--[[ spec:RegisterSetting( "ca_vop_overlap", false, {
|
|
name = "|T2065565:0|t Coordinated Assault Overlap (Vision of Perfection)",
|
|
desc = "If checked, the addon will recommend |T2065565:0|t Coordinated Assault even if the buff is already applied due to a Vision of Perfection proc.\n" ..
|
|
"This may be preferred when delaying Coordinated Assault would cost you one or more uses of Coordinated Assault in a given fight.",
|
|
type = "toggle",
|
|
width = "full"
|
|
} ) ]]
|
|
|
|
spec:RegisterSetting( "allow_focus_overcap", false, {
|
|
name = "Allow Focus Overcap",
|
|
desc = "The default priority tries to avoid overcapping Focus by default. In simulations, this helps to avoid wasting Focus. In actual gameplay, this can " ..
|
|
"result in trying to use Focus spenders when other important buttons (Wildfire Bomb, Kill Command) are available to push. On average, enabling this feature " ..
|
|
"appears to be DPS neutral vs. the default setting, but has higher variance. Your mileage may vary.\n\n" ..
|
|
"The default setting is |cFFFFD100unchecked|r.",
|
|
type = "toggle",
|
|
width = 1.49
|
|
})
|
|
|
|
|
|
spec:RegisterPack( "Survival", 20220605, [[Hekili:T3t)ZnUn293IMmHR0UE1krBT7MulDtUCTxZ200oXzM2FYs0suw8SePosk71z0O)27da8daW3dausE3CDUoDUSwK4H3x49fEa82H3(B3EZIG8WB)f)b((dE)GR677p8s)V72BYFEB4T3Sny(db3d)J4GnW)7n7sFm6XG1Sh886KGfmaKLSlDo8WV5WSv55BZ((39U7JYxT7U(Zt28USOn7whKhLeppnyzo7VN)UBV5UDrRZ)P4BVdhb(WT3eSlFvskmNrB(XBVzv0IfHIxpmBEnMCy2)(U48W0dF6t7Idpm7QlomJbQdF6WN(XK4hdtZpmBzY8DzhMLa)18GThMnFv48hGFip5WS0WSTHZHxko8j4jRdYGhKfMNhfFp8VE3Hz7YclFkBCt5qBAfWc)8wagzab2)2BwhLLNXykWVbu)Db5WF8lC(CyCWDRdxC7F(2Bs2cCTW8OL3EZ80ia7JcagEW6W48(BsIVpjjlC6DWd6xoiovNgTLXhV9MVce2JbPtf6aBUBAA205jz5GmAUaHGNgXqu2)A9UWPHRZclFA)0GT5jPtZYtJEiSVyG8xR6nuPz(BKdAemUw5mKTBd8wt3gMlZjH36s536UK8C4jtxUo45Wfpbu608KphfRnMRKhZY1HzR46MAV1inPwTOkfu1wMKEFyFq3Fn)FnnCZDHPz9d)77I2ULjXkHFoW5YbEadKVxHKYddxlEKYed4rCEqLEJTxxWNqXZohMD3ULl7)u06ftZ2gbpiRFA4MGOyqdy)EJp2dulsswVi5P4(peTEniY3SjiEr5BiXbtdd)DoVUGmV8RngjXZZzRDwgSBn6kr5LFGumVFYU8SOfHFKpBLRw6dRuMUkiDBssm)bCKmGV(AAYYP5Ra5FW9Rd7ZWTA0OyinuM3S73)D2ILMkYsOwfTKgedkvRJ4S4Svj5Awd(RWI9GvHblG)tm8)8BvdawE)l)3)iSsooCtuygyA8j4NwKe)QC2)bStSkkJzfj9WSTSLmPWFDx48aULHO8xTG9NmZjW7MTnyZMNlMdgCMhWHtkmZrRFUyEzVx48OLrZfCPS(AI)c(Cu2uXmwTEeH0)Bj57IVpmknDkqXGO4zWWtW61YGK9UpcSFbjEy24dZgYLrDletGkt6IOyWjZIPGnqMMq)DBfkBDK0OWEpvnZKmHsyE0MqWUY0frax46dZUCWHz9eVdmP6i0KseIJnGf1eyoyIYG00KNQqfJ4AVshWKCKs7vLSoMglWI2KPPL9EYfaZbd)XbGhOhEg(7y1LBgzoYVyd6tHfY53h30utAm6DQ4pMY83k86w4DcCYe)qi4dgO1pqOwzeaZxWh7hj5t6YxMcGqTq4a)UO0fzmRcG3ZNRDGZC)npNzbYn84UeUP0VR94rNZnQiChpCGZOcOY73(Pz(6WGhd5tLIJVaiCKy2cU0uGOA4RSyyig3R8CgMUfg5u26L7rc5A1ZlsdYuc4QEb7JrBbZItbL2KnkQ8gEkikUFoWON)mGCtfw8Yy4NnV1PbrlMg(idPcwSaIM4ZS4jfRD0Fw1SnHzYBG4LAijg3CGZtGiMpm71CHujps2JRvx4hnA(Xtel1TUG5848GPNmdfXuM5GkxUdwBaznSIPUmL5JPursYbXMGftVJLxba7W0ANhLUMwgD)Q8PYkIJuLXlJsd5qWMZGclYkJPVa5YMUmvatw(xWCOScpvSgw34BnS7YnrDCsgGEok5sLdA0mDegnRJQ)UG7zwn3SloIrvyr1VimiF1uGF8qAWgZomQHBmlDQ47FkifCBZIpDlxtE72G0G8D1tJqukYTdyVLzx1xo1R2ADLLsrP)KQbiqF9yemyPFrsE)SvaMhd5IWvjYJM)aqfLHCXEHiwc5GUXuy8HWAG77NLhm)boT4lednHJMXtEmpL45D7Yb5w6Z1(gocKRdpEE43JboDoS6X)Jt93ohr1DiTnASfamVD9hPgiJ6YgSL2t4rkd)EH7bEg5(e0mT1ye9zPeZwhe)apRbEU3CqrfRTCcv6m1TaIKaPFh2KRIXslz34wSWDloK2WihmlfPNmDtq6dCGOG38SIyqr3IMeN4zWqSi7j05N2EvhH6QQi1bnlCBzL25elxi0Ng23N)gibwDvPDmIbEf1aV0YaFFLnsdwN9maatEAgsBEu4oio8Z5tFksWClxexHofbQvb2O4L74fMQkCTEVOR)OJc)moJv2F81T)ABnkLtntHui0)osFtvuTsPFWZiSSwmnYe8yM7EebvRMWa45oDrykZh(CikrD)B(MSVBWCQuf4yqHQGnKPBKgcSRSvSbiNWiv6hfvkrPAdGo0hjybkf1uOlPr26Mypw1Q)FKEJsbzRDLOX4OkKGlsAIjw3EyjivkfoXy1TgvowLcTJo2CrDfoMCLnNmCxhYhUWFO8IakXYzsrLJsGsIjDKYuO6kvUxio6KN0Hh7LkIj)nSIFMXYZ6(Wyo5XFaeRZN5pC4GshsUIbo(QovHHlDrNMoR5JXzcD(PgIjGoIV2guRYQyLq9uOz6q8ogtkVyPOrhQKr(sJmsD1mH6sCQsq7zOe1YQLdzPc9AdQNnYUKY03xA8QvXq0ihr34U5rBl3WiiwWG0YmJhdXNtGwuHzqYUkcRiy92vbSk)UiaqiLilkTwxbIL7sFwHBQ(ez(yHo)74qbrT)WS3QADSxjBN0CFJCsTBmILtGAHhSzEYAwCMO7j4W)T8T251Tzw6yEIkYatFhMg(XYbtcDtjF5yGF6IghKdDBBezLAHsEtXnFY1wu2NZFA5HzpNSRAdmxf8iBdoRNXxLX3es(CEy2puoPxaE2J2SLTfLm9YdZ(paY(WSFuq3hMfvc3NeWTI(yB27)MahxMMSHnXCiNL0)WmjSXDuPyiGVPDRxygDsR4pSTO9UqiIe2(1Y23vo3jbET)ZcLOdZ(ZGGc(nyq)k3(ZHz3uxYhQIIC6I)JqW7qwatelOpfdn2sL4CnfDLlprD(HQ65gESmwk98ZlEQVq6)jkFLBARjXSvnKkOmCfERG0qXILssbwXLaQQPpfX0nZYt2YA2ioWjH18D8T3RIyd2iQEpt7hYMy39ReT1u2oWLzuCXAHY3ITAqytED4Y8IwAii(zXtuWwgqaLEgkVCznoBPiGTOWanQ1L1CR4fUw(H91lvqhhAMb7(9PGQECaeUPv27GgBfNwoZdKFzLDxu7fPRNVzIwkOA8TAZqzEiI(rnfpb4v70i5fztus7ZspCqf3MPcjzpF(IQ(GsJnJuqPQeKrlqwMOwuAacviwT3xKHv(HgrVc)1gERlegFFW9HBy)MSQCDSdvYGAmvVVRO1bSjSUBDsYcUcsvM1hpWcINhccZG1vTSdT0ZjaYKBCmSkD6YNSMTpWzt)B7wC)MgnnHl77RIwpr1S5PsvXPe7zklL3hq7(gNOnIWFVuAEaTSWuEeVL5kxTYcRT6OlDVHnn3FulwqVnH)FXsTTEY6kRY(HIMlWL(EsAdrlJ4G10P3fbYLTGVWDWISW0DCx7QHDu9ApMWAaB49Ysw)O(cjXIx93GHvkBbRCxYY3Fx2uoL3bZRcIJdxdceVoKywDc2U6Dvl(sYgTL)EndWtABoQd3CnePc6Rq22EyTAqvhgQxz(rkz6wY5K7)xYQgWrnx4ivu6UwYH0W1RQlgci6cNY(hGLFScouJu0CcKTQ4KQvGwskv7VlTbZVg4wdx5g2f7Vg4NAaeyPck73LJglIGWRb)uIoQ59soVA2TZcp6zwASAlLoWqBaH84sTETFEXUu(rmHh3M(dJeLOFuv1vCeOYjHD1GAorJcTsTOMmGPI64OgYVCvIi26VpiX4m1xgMAxmpT9AVcgvShSW5KCvyDhEiBhI6ky1Ekhp8xLT6GUW)hDlcsRb294uc9hGRcw0QAcJcNIAAHiKQv1hoWqgC5M2tMJMtDoztoWc8TXc8hqKxQXaJTq(vD1EmpwYLbHQHEqFEx6qoyCdKNax9YtNRsGq9SWZVCG1S1pYsVGSBGk5eyBFCOtpGydf8RdYZZuFFrz)1Mfsh2kddEuvmTxgvp)HMn7APcuSzLYRHhDDKkXQZZgR)w7LK5182CRNDfs(o0BOiiKBsjvliqkpT0)KDAzBsQSjLuBUVHgyfpnhpTTXj951bpabcU(HqE4MXlb)tlQxMH1r01TpR7jqCQZEtJSTTf88m1gM826LPhzOZIPAt5wTNMsXmQwkzQAX9pGB(RKYULt)jX8BkYvIvloUZx2S5xvjbmjNtDtmEgz61eZu3byrrKapO7LedqIo9wQwkXLgHZy490zEGtynAr26PKOtI9Q0ENqO6koNieodvoakQQ0MpvbnRVUIjCIJGrJ9UWMMRZQMn2TbjH1ryb2eHsDudm3OpN3TLH1Ig2nIxP8HzzIGpszA2LDTHopJJngotrO14zeRkgv12ITwRox6K3sFHxupETlmIcr)XC4OLVAkYEoE(0DBXQjJDma7GjtJvEoSHSYP2PduhiM80e2cUAAsFLR01icgvHbOAvA1fDyOJ4Umq(c9WL9Ry697cZYK4Qwpy4x)NCBNqkGms9CEHzec5YllBaR4lUswe0JMU3lpnagrATOKkcTcRjd1Sn2L1gh8N0pFy)vbztzx0bmjNwDyKwVPnGs8tAd1QchqDnx5Jjwh3rc0(oIlnhtn6WgJ0dLy3sbits9vOQrCsA4vWVU0rSs(JHb1VrpuSOMgSWw8oByqhxKAMWJU2qL3Yd1tU5eLxOjWcIhnXgSFN8rs2DS8SZm)dfFqtMHT82m1OqVOZxVgKSY6SGfpRYwrNgbdzcjv7r(KRTb63vDaP7ydhjjII5crS109NgYI9cff)9CPP0wCwhzTkAyv27nMKaMj3txBUjeKQqUdK)eBO4rkkOOwZa66gThJvnM3ydMtAatDnECNBVqYfT)FopbFp5jqGEoraerr01QdGUAE7krDR6ttk30BBSVYD3PTAN6CbegbojD(cd64De0tI1Ok6IY6ppy(QqwT4cM)33b55UyAoy6nBxAybcOxj7RllEeplIQr9eR6eLcltv)Myy9GW7xNWAA2c8Bi2ELPf0SVHGMDnqvsXZzmOzxdGV5yi0wgAxBXM24luuhiyrnnyHTy1RNZyq7cAg3iSzuXMhChDVAi4i8mqmGLNDM5FO4dFzY5JoKdKGMneqYPg0Sf37DSHJKeXxKGMpAnL2IZKbntjA(Ye0SLuESh0mn532GMDvuynOzuaDIbnJBxYAqZ4o3EHKlVebnJqaoe0mUdaNcAgtF64dA2rTthcA2ET9oTWGoEhbubn7)h6GM9RAlmPGMTCH6wfuTHRCx((E9yyk7QOQ4gSFeRv3EkinM1Vt3EZ)Zp8R)Yp9l)1V)WSdZ(n2bwmAZ2K0YdO4RkWVSxXoBEcYGDUnyTDqWU8KnSANZ7ofabY6F4t)CeB)8E)3ZobL8RaE2Jzxq(WOEooNTHNF7b(jC8N3fCy2IOhJY4IUKTHPb8ZfC33bcWUJ(CpkWvIu9h2))9vcG9kjnh2V11)khgVpY49lg)7Lg)hoVKZhocYXa64e5iyhh(KfXD1hfG2jVhQJrIE8PgDk(7Y28b(9ayo)x)V(za3g6gQL1wCA0Pl1Ce1MVOLRpgoqJHvDSKQyz1)IetRRVKAWWlpxeyb8U6mdVVCcG7s22sbW5M3PrRVQUtvQKOs)KSivbmNbdNxAaEUSWuvhthahjD9XJapCu2lUDTBP43)05ZMOVtgEF35cEh(0pX5wmO8XYwt6Wm(xbg4XSpdmjlJyBx)3attJpznWp28RwZ3uHBv9MtvRs)s99DHnVcKpRFLtQ3m(DLrTEblyPX1nl3fjBhZ7mHl49gW4IEYQ53XLlQ75GYxkTXNdMlMNeVGFtlpg7JGdoQv)bHb)5uFkyWF76J3k(Zlp2LxeTCSlh5sCuUQ3EL43JloS6mixKbv53GepSV)iEIGEj(2Jubwy6ehhAUcLZFIq(x(Q8jcrgRB(5oHXz6uWAQ(SHipKYV1fcTuQ41zGrnzIXd96Y5MZrB6N977uLee2BuKB1(9StzGNuAVxF5GE733vDYMmui5q6Mmac0yrpmkndKQGy9Vec8cq4emN3dGIR5Kfj7Ud45GjMO1f33qIRNOT7GF(xRM(dZ(b28ZgG4gBjvCDSuChdvMzzuwHWDDcBmmlplWM2)cBAlUxKI5TDyIayzCWvSapR42IHzuraSnWc4zpfbQzXfZnRyuzHSHKXUoxcFk45lkEuw0g(8YseuAAR8gfXe0p3xWDQzBGnqEdSoLX8x)yitvOkcq9hwOtGkNKYRgVfOMmCW(9nleY1dFVICu)AauO5wMnid90Q6HNlAIEwrpUkD7bSDuhIr3(lbXrEH4orC8WMRgV(sptF2sSdE4)Ae6DonWlIeYWumXxgiQF1sKDWEh35Pux8EHspclanxhe7S2wOEI9ORVF(I97LA5(EktkGuYnnn2SIeNGWQL1RWuWENPt51(98)8n1nQ91vnP9BgoONJZItVMe3aL(z(u0FGs)mtXjAE6qeCCos18O(PnfANurIjbzuLhQz9hHRMcbXQOJ2IROTIGx84i01vvSu6msOHbkNeEhjiLW)i18X9f6r(Ssz(W(JEnICxjEYVutAJJE6XXkWpuqJVS10OXJgwHzf9dFHhYVws2CX832frp5T1lZ7X4mnSd50YTofhUbVUul86qEByAaVN0eAVD4RTbVo0aeI1tXv)h9OHdpA8)5fzz7VilphEY62XzJHf(RWmc2Jld)N3HIi3HINdHKZIO6ixrVgrN0Tf2NQHvU2njv7at3onURpzPdO9t1ZwZR8ZwnFnSRwdph9gBnouJxmafwfPsFg1HJxZX34e)P7NulBgmVjLhAVgbj1e341tWaIB2XAPBzDKUmcxXyPoEItQI61ys)TksbRoxnEtq2AnIMPFStUEw9HubvRPLT7ZXI4nRp0MYGcWO67GrlrQPpq17BXwo4Q7wXwooTBEXgeJ81KOir)cBbwUXfNOeHzbWQUleTGKArOCPoGklvO6VkUyd5GMvHlL2p5A)roQbxWoRkW6fYxFGJD62dKHcc7Ix)HbsvHXuq5c7XKGC)EYRhrrSJOxjI90jl56cB2BgzTI90D5WqDjNBYxAH8h1OWI73R(lJhkxnYjJ0cbVuGaW9II7(VX(JOOG86lCq3OgPz(QxJO0wLdEZkOWq8M1oZDhInuR1TC)YoDQwPFXNoK9aqyWLphLxKFtg)EfRZ8QyzV(t0FBQ8OlnLXktPJdAoU5ELXVIT2VN4QPAYyw5w1womg9Uv71(iZVEGfhho8XtbfOIpP1yXPXjAeZq7Q1vXEGO6Hyeg5YUKGuC7PgysZlINRhIaMgfEQBRzyJCMDb53JwEch(EXIYb(6v1UAKO4whb5rLxIrvb)JDJz411W351R93VN87761A(IAOyqpNDqVJTmtbn1NM43FKhH2hsuxkxxuFl2sN2wx3QbAl7y6BompmorzYu01HwDMlDbZhL2NxvCYSSq00jGqBpXuP1WOMMlCflO96Iish233tBX8vSfTiV4v6V4LeV47HL9egv8qhaM5ozvXUDqVdwGzX2x30ENv9vBMGpkGAtx29TtXR7ry7ZCPGORUdte36zdZ8LHA9x9oTO4m1JXwCAYvtXqmBnd8CYhP0notI3)HuoISbHhLSaz4g3FgSGtnxZN6raXomwU1IK(DMDBzoj3sm3Gp2fDvr0DypYdVmf69hqXCkNv8lY0vpHz5JDzxi9OdqSXdyj6sC76(MM3SUxpQxtFviGOmUZRgiJ8UOw1H8A)cBz9hasLoYbQa49WV7W6v8(AL7ZCIEalfp(K2rhASj0ncN)KwLfhM0UBBe3(dAkU5jkmEyBveq6CSH6AhoNI8PQgJrxgWEFmS3xh7BB2TnVjSvd9PPjKoidP5A9wYlUS98cKPShANb2uTUvzpWhKHOnQuASLnVpRKsOjsqNKp(6AYTNh1om6TBOhTPbJBa1(942Ti2yjVJUhLERG)sTToV(YEys7Hd6PjzSfifkd2qIGwZ5REwrSCwLkGwordLlUH73fOAqxo5NZZeCS5bHM0OF)ry1POGZQl4ArW783)pWDJJN1qYqNbQqeAPgorwF25OgJhUQqguDlLbrTrjNPks12a5uZvRzep4bBzZ2oAvfevdCcI2WR9rnPwuuuH(H5cTjmD0OcIoj9TlMBqFhJHI2Uy8SSJ(VDOjdkgY2Pnk624wT1)kLhuTFxtVA0GEuAj1iyz7Spw9uevCu8lo5qCMsBptenNJ3OFwLuVEBkMm9EFNAYPB5ZItfccyolyAHcr9XRQ(KrPnPvuKLo()6)Kl7wU4(yv(WA1IrfzO1du7kSVs8Gxa6Ynj7ld5m5fxKIsBvN9Ol4xUcLNwfU9ZUDZRoL9YxDfsz0vSwr99krPEEDrVEuyHS3y5wN8QtKV55s7flNS97R)DjMDraq4ecRZ(iM16bubSYClNmgzMkFyp95Q8nOiqVtyM6qZEjMSUgMT3o6A07ZK97r)5jga1363twEqHcNf(WxuAQMXQVKWagwJ(iGTxn(RFJW6zaMVD0eukWd9xV2aK(wF2MvrHc4ihhOk82MM69m9Wj(dos5MJ4JmIyInoCWBW5yMW(Js7rFq8sjzIAMyK76m3dd9nm2RvA3dJcX3yAjRcyK0W0TaFE4K8)p0ZOjk87rJqnCm1LYow3o6OHj55Kr9OiwwLgDurqMg6PSU1OFT25KS1MW61Zt2WO5lnk9o05A)Id)U2n(uJo5zyrjo0FXETjWgF1aBSfSboB84cSXwquAVytzwZBamANSNF)u6Zv5BqrGMm7ABMCiWgD7igMTJniauNLncWddfol8HVO00lqKWOUOudSb131rfydHJIoKOaoYDEdSPvYnhXhSaBWyJVib2qe(OHaBWOghdSXg3ZuGniJ9ycSbBjlvGn6wGppCYtiWgFxdSr3oMPaBAkpDmWglkcub2qMW(X4KS1MWucSX2TH5x4aBmFV4C7nSZra7dA3i(fA5T)F)]] )
|
|
|
|
|
|
end
|