-- WarlockAffliction.lua -- June 2018 local addon, ns = ... local Hekili = _G[ addon ] local class = Hekili.Class local state = Hekili.State -- Conduits -- [-] cold_embrace -- [-] corrupting_leer -- [-] focused_malignancy -- [x] rolling_agony -- Covenants -- [x] soul_tithe -- [x] catastrophic_origin -- [-] prolonged_decimation -- [-] soul_eater -- Endurance -- [x] accrued_vitality -- [-] diabolic_bloodstone -- [-] resolute_barrier -- Finesse -- [x] demonic_momentum -- [x] fel_celerity -- [-] shade_of_terror if UnitClassBase( "player" ) == 'WARLOCK' then local spec = Hekili:NewSpecialization( 265, true ) spec:RegisterResource( Enum.PowerType.SoulShards, { -- regen effects. }, setmetatable( { actual = nil, max = 5, active_regen = 0, inactive_regen = 0, forecast = {}, times = {}, values = {}, fcount = 0, regen = 0, regenerates = false, }, { __index = function( t, k ) if k == "count" or k == "current" then return t.actual elseif k == "actual" then t.actual = UnitPower( "player", Enum.PowerType.SoulShards ) return t.actual else local amount = k:match( "time_to_(%d+)" ) amount = amount and tonumber( amount ) if amount then return state:TimeToResource( t, amount ) end end end } ) ) spec:RegisterResource( Enum.PowerType.Mana ) -- Talents spec:RegisterTalents( { nightfall = 22039, -- 108558 inevitable_demise = 23140, -- 334319 drain_soul = 23141, -- 198590 writhe_in_agony = 22044, -- 196102 absolute_corruption = 21180, -- 196103 siphon_life = 22089, -- 63106 demon_skin = 19280, -- 219272 burning_rush = 19285, -- 111400 dark_pact = 19286, -- 108416 sow_the_seeds = 19279, -- 196226 phantom_singularity = 19292, -- 205179 vile_taint = 22046, -- 278350 darkfury = 22047, -- 264874 mortal_coil = 19291, -- 6789 howl_of_terror = 23465, -- 5484 shadow_embrace = 23139, -- 32388 haunt = 23159, -- 48181 grimoire_of_sacrifice = 19295, -- 108503 soul_conduit = 19284, -- 215941 creeping_death = 19281, -- 264000 dark_soul_misery = 19293, -- 113860 } ) -- PvP Talents spec:RegisterPvpTalents( { amplify_curse = 5370, -- 328774 bane_of_fragility = 11, -- 199954 bane_of_shadows = 17, -- 234877 casting_circle = 20, -- 221703 deathbolt = 12, -- 264106 demon_armor = 3740, -- 285933 essence_drain = 19, -- 221711 gateway_mastery = 15, -- 248855 nether_ward = 18, -- 212295 rampant_afflictions = 5379, -- 335052 rapid_contagion = 5386, -- 344566 rot_and_decay = 16, -- 212371 shadow_rift = 5392, -- 353294 } ) -- Auras spec:RegisterAuras( { agony = { id = 980, duration = function () return ( 18 + conduit.rolling_agony.mod * 0.001 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end, type = "Curse", max_stack = function () return ( talent.writhe_in_agony.enabled and 18 or 10 ) end, meta = { stack = function( t ) if t.down then return 0 end if t.count >= 10 then return t.count end local app = t.applied local tick = t.tick_time local last_real_tick = now + ( floor( ( now - app ) / tick ) * tick ) local ticks_since = floor( ( query_time - last_real_tick ) / tick ) return min( talent.writhe_in_agony.enabled and 18 or 10, t.count + ticks_since ) end, } }, burning_rush = { id = 111400, duration = 3600, max_stack = 1, }, corruption = { id = 146739, duration = function () return ( talent.absolute_corruption.enabled and ( target.is_player and 24 or 3600 ) or 14 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end, type = "Magic", max_stack = 1, }, curse_of_exhaustion = { id = 334275, duration = 8, max_stack = 1, }, curse_of_tongues = { id = 1714, duration = 60, type = "Curse", max_stack = 1, }, curse_of_weakness = { id = 702, duration = 120, type = "Curse", max_stack = 1, }, dark_pact = { id = 108416, duration = 20, max_stack = 1, }, dark_soul_misery = { id = 113860, duration = 20, max_stack = 1, }, decimating_bolt = { id = 325299, duration = 3600, max_stack = 1, }, demonic_circle = { id = 48018, duration = 900, max_stack = 1, }, demonic_circle_teleport = { id = 48020, }, drain_life = { id = 234153, duration = function () return 5 * haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end, max_stack = 1, tick_time = function () return haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end, }, drain_soul = { id = 198590, duration = function () return 5 * haste end, max_stack = 1, tick_time = function () if not settings.manage_ds_ticks then return nil end return haste end, }, eye_of_kilrogg = { id = 126, duration = 45, max_stack = 1, }, fear = { id = 118699, duration = 20, type = "Magic", max_stack = 1, }, fel_domination = { id = 333889, duration = 15, type = "Magic", max_stack = 1, }, grimoire_of_sacrifice = { id = 196099, duration = 3600, max_stack = 1, }, haunt = { id = 48181, duration = 18, type = "Magic", max_stack = 1, }, howl_of_terror = { id = 5484, duration = 20, max_stack = 1, }, inevitable_demise = { id = 334320, duration = 20, type = "Magic", max_stack = 50, copy = 273525 }, mortal_coil = { id = 6789, duration = 3, type = "Magic", max_stack = 1, }, nightfall = { id = 264571, duration = 12, max_stack = 1, }, phantom_singularity = { id = 205179, duration = 16, max_stack = 1, }, ritual_of_summoning = { id = 698, }, seed_of_corruption = { id = 27243, duration = 12, type = "Magic", max_stack = 1, }, shadow_embrace = { id = 32390, duration = 16, type = "Magic", max_stack = 3, }, shadowfury = { id = 30283, duration = 3, type = "Magic", max_stack = 1, }, siphon_life = { id = 63106, duration = function () return 15 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 3 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, }, soul_leech = { id = 108366, duration = 15, max_stack = 1, }, soul_shards = { id = 246985, }, soulstone = { id = 20707, duration = 900, max_stack = 1, }, summon_darkglare = { id = 205180, }, unending_breath = { id = 5697, duration = 600, max_stack = 1, }, unending_resolve = { id = 104773, duration = 8, max_stack = 1, }, unstable_affliction = { id = function () return pvptalent.rampant_afflictions.enabled and 342938 or 316099 end, duration = function () return level > 55 and 21 or 16 end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) * haste end, type = "Magic", max_stack = 1, copy = { 342938, 316099 } }, --[[ OLD UAs: unstable_affliction = { id = 233490, duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, copy = "unstable_affliction_1" }, unstable_affliction_2 = { id = 233496, duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, }, unstable_affliction_3 = { id = 233497, duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, }, unstable_affliction_4 = { id = 233498, duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, }, unstable_affliction_5 = { id = 233499, duration = function () return ( pvptalent.endless_affliction.enabled and 14 or 8 ) * ( talent.creeping_death.enabled and 0.85 or 1 ) end, tick_time = function () return 2 * ( talent.creeping_death.enabled and 0.85 or 1 ) end, type = "Magic", max_stack = 1, }, active_uas = { alias = { "unstable_affliction_1", "unstable_affliction_2", "unstable_affliction_3", "unstable_affliction_4", "unstable_affliction_5" }, aliasMode = "longest", aliasType = "debuff", duration = 8 }, ]] vile_taint = { id = 278350, duration = 10, type = "Magic", max_stack = 1, }, -- PvP Talents casting_circle = { id = 221705, duration = 3600, max_stack = 1, }, curse_of_fragility = { id = 199954, duration = 10, max_stack = 1, }, curse_of_shadows = { id = 234877, duration = 10, type = "Curse", max_stack = 1, }, demon_armor = { id = 285933, duration = 3600, max_stack = 1, }, essence_drain = { id = 221715, duration = 10, type = "Magic", max_stack = 5, }, nether_ward = { id = 212295, duration = 3, type = "Magic", max_stack = 1, }, soulshatter = { id = 236471, duration = 8, max_stack = 5, }, -- Conduit diabolic_bloodstone = { id = 340563, duration = 8, max_stack = 1 }, -- Legendaries malefic_wrath = { id = 337125, duration = 8, max_stack = 1 }, relic_of_demonic_synergy = { id = 337060, duration = 15, max_stack = 1 }, wrath_of_consumption = { id = 337130, duration = 20, max_stack = 5 } } ) spec:RegisterHook( "TimeToReady", function( wait, action ) local ability = action and class.abilities[ action ] if ability and ability.spend and ability.spendType == "soul_shards" and ability.spend > soul_shard then wait = 3600 end return wait end ) spec:RegisterStateExpr( "soul_shard", function () return soul_shards.current end ) state.sqrt = math.sqrt spec:RegisterStateExpr( "time_to_shard", function () local num_agony = active_dot.agony if num_agony == 0 then return 3600 end return 1 / ( 0.16 / sqrt( num_agony ) * ( num_agony == 1 and 1.15 or 1 ) * num_agony / debuff.agony.tick_time ) end ) spec:RegisterHook( "COMBAT_LOG_EVENT_UNFILTERED", function( _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName, _, amount, interrupt, a, b, c, d, offhand, multistrike, ... ) if sourceGUID == GUID and spellName == class.abilities.seed_of_corruption.name then if subtype == "SPELL_CAST_SUCCESS" then action.seed_of_corruption.flying = GetTime() elseif subtype == "SPELL_AURA_APPLIED" or subtype == "SPELL_AURA_REFRESH" then action.seed_of_corruption.flying = 0 end end end, false ) spec:RegisterGear( "tier28", 188884, 188887, 188888, 188889, 188890 ) -- Tier 28 spec:RegisterSetBonuses( "tier28_2pc", 364437, "tier28_4pc", 363953 ) -- 2-Set - Deliberate Malice - Malefic Rapture's damage is increased by 15% and each cast extends the duration of Corruption, Agony, and Unstable Affliction by 2 sec. -- 4-Set - Calamitous Crescendo - While Agony, Corruption, and Unstable Affliction are active, your Drain Soul has a 10% chance / Shadow Bolt has a 20% chance to make your next Malefic Rapture cost no Soul Shards and cast instantly. spec:RegisterAura( "calamitous_crescendo", { id = 364322, duration = 10, max_stack = 1, } ) spec:RegisterGear( "tier21", 152174, 152177, 152172, 152176, 152173, 152175 ) spec:RegisterGear( "tier20", 147183, 147186, 147181, 147185, 147182, 147184 ) spec:RegisterGear( "tier19", 138314, 138323, 138373, 138320, 138311, 138317 ) spec:RegisterGear( "class", 139765, 139768, 139767, 139770, 139764, 139769, 139766, 139763 ) spec:RegisterGear( "amanthuls_vision", 154172 ) spec:RegisterGear( "hood_of_eternal_disdain", 132394 ) spec:RegisterGear( "norgannons_foresight", 132455 ) spec:RegisterGear( "pillars_of_the_dark_portal", 132357 ) spec:RegisterGear( "power_cord_of_lethtendris", 132457 ) spec:RegisterGear( "reap_and_sow", 144364 ) spec:RegisterGear( "sacrolashs_dark_strike", 132378 ) spec:RegisterGear( "soul_of_the_netherlord", 151649 ) spec:RegisterGear( "stretens_sleepless_shackles", 132381 ) spec:RegisterGear( "the_master_harvester", 151821 ) --[[ spec:RegisterStateFunction( "applyUnstableAffliction", function( duration ) for i = 1, 5 do local aura = "unstable_affliction_" .. i if debuff[ aura ].down then applyDebuff( "target", aura, duration or 8 ) break end end end ) ]] spec:RegisterHook( "reset_preauras", function () if class.abilities.summon_darkglare.realCast and state.now - class.abilities.summon_darkglare.realCast < 20 then target.updated = true end end ) local SUMMON_DEMON_TEXT spec:RegisterHook( "reset_precast", function () soul_shards.actual = nil local icd = 25 if debuff.drain_soul.up then local ticks = debuff.drain_soul.ticks_remain if pvptalent.rot_and_decay.enabled then if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 1 end if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 1 end if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 1 end end if pvptalent.essence_drain.enabled and health.pct < 100 then addStack( "essence_drain", debuff.drain_soul.remains, debuff.essence_drain.stack + ticks ) end end -- Can't trust Agony stacks/duration to refresh. local name, _, count, _, duration, expires, caster = FindUnitDebuffByID( "target", 980 ) if name then debuff.agony.expires = expires debuff.agony.duration = duration debuff.agony.applied = max( 0, expires - duration ) debuff.agony.count = expires > 0 and max( 1, count ) or 0 debuff.agony.caster = caster else debuff.agony.expires = 0 debuff.agony.duration = 0 debuff.agony.applied = 0 debuff.agony.count = 0 debuff.agony.caster = "nobody" end if buff.casting.up and buff.casting.v1 == 234153 then removeBuff( "inevitable_demise" ) removeBuff( "inevitable_demise_az" ) end if buff.casting_circle.up then applyBuff( "casting_circle", action.casting_circle.lastCast + 8 - query_time ) end class.abilities.summon_pet = class.abilities.summon_felhunter if not SUMMON_DEMON_TEXT then SUMMON_DEMON_TEXT = GetSpellInfo( 180284 ) class.abilityList.summon_pet = "|T136082:0|t |cff00ccff[" .. ( SUMMON_DEMON_TEXT or "Summon Demon" ) .. "]|r" end end ) spec:RegisterHook( "spend", function( amt, resource ) if resource == "soul_shards" and amt > 0 then if legendary.wilfreds_sigil_of_superior_summoning.enabled then reduceCooldown( "summon_darkglare", amt * 2 ) end end end ) spec:RegisterStateExpr( "target_uas", function () return active_dot.unstable_affliction end ) spec:RegisterStateExpr( "contagion", function () return active_dot.unstable_affliction > 0 end ) spec:RegisterStateExpr( "can_seed", function () local seed_targets = min( active_enemies, Hekili:GetNumTTDsAfter( action.seed_of_corruption.cast + ( 6 * haste ) ) ) if active_dot.seed_of_corruption < seed_targets - ( state:IsInFlight( "seed_of_corruption" ) and 1 or 0 ) then return true end return false end ) local Glyphed = IsSpellKnownOrOverridesKnown -- Fel Imp 58959 spec:RegisterPet( "imp", function() return Glyphed( 112866 ) and 58959 or 416 end, "summon_imp", 3600 ) -- Voidlord 58960 spec:RegisterPet( "voidwalker", function() return Glyphed( 112867 ) and 58960 or 1860 end, "summon_voidwalker", 3600 ) -- Observer 58964 spec:RegisterPet( "felhunter", function() return Glyphed( 112869 ) and 58964 or 417 end, "summon_felhunter", 3600 ) -- Fel Succubus 120526 -- Shadow Succubus 120527 -- Shivarra 58963 spec:RegisterPet( "sayaad", function() if Glyphed( 240263 ) then return 120526 elseif Glyphed( 240266 ) then return 120527 elseif Glyphed( 112868 ) then return 58963 elseif Glyphed( 365349 ) then return 184600 end return 1863 end, "summon_sayaad", 3600, "incubus", "succubus" ) -- Wrathguard 58965 spec:RegisterPet( "felguard", function() return Glyphed( 112870 ) and 58965 or 17252 end, "summon_felguard", 3600 ) -- Abilities spec:RegisterAbilities( { agony = { id = 980, cast = 0, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 136139, handler = function () applyDebuff( "target", "agony", nil, max( ( talent.writhe_in_agony.enabled or azerite.sudden_onset.enabled ) and 4 or 1, debuff.agony.stack ) ) end, }, --[[ banish = { id = 710, cast = 1.5, cooldown = 0, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, handler = function () end, }, ]] burning_rush = { id = 111400, cast = 0, cooldown = 0, gcd = function () return buff.burning_rush.up and "off" or "spell" end, startsCombat = true, talent = "burning_rush", texture = 538043, handler = function () if buff.burning_rush.down then applyBuff( "burning_rush" ) else removeBuff( "burning_rush" ) end end, }, casting_circle = { id = 221703, cast = 0.5, cooldown = 60, gcd = "spell", spend = 0.02, spendType = "mana", pvptalent = "casting_circle", startsCombat = false, texture = 1392953, handler = function () applyBuff( "casting_circle", 8 ) end, }, --[[ command_demon = { id = 119898, cast = 0, cooldown = 0, gcd = "spell", startsCombat = true, handler = function () end, }, ]] corruption = { id = 172, cast = 0, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 136118, handler = function () applyDebuff( "target", "corruption" ) end, }, --[[ create_healthstone = { id = 6201, cast = 3, cooldown = 0, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, handler = function () end, }, create_soulwell = { id = 29893, cast = 3, cooldown = 120, gcd = "spell", spend = 0.05, spendType = "mana", toggle = "cooldowns", startsCombat = true, handler = function () end, }, ]] curse_of_exhaustion = { id = 334275, cast = 0, cooldown = 0, gcd = "spell", startsCombat = true, texture = 136162, handler = function () applyDebuff( "target", "curse_of_exhaustion" ) removeDebuff( "target", "curse_of_tongues" ) removeDebuff( "target", "curse_of_weakness" ) end, }, curse_of_fragility = { id = 199954, cast = 0, cooldown = 45, gcd = "spell", spend = 0.01, spendType = "mana", pvptalent = "curse_of_fragility", startsCombat = true, texture = 132097, usable = function () return target.is_player end, handler = function () applyDebuff( "target", "curse_of_fragility" ) setCooldown( "curse_of_tongues", max( 6, cooldown.curse_of_tongues.remains ) ) setCooldown( "curse_of_weakness", max( 6, cooldown.curse_of_weakness.remains ) ) end, }, curse_of_tongues = { id = 1714, cast = 0, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", pvptalent = "curse_of_tongues", startsCombat = true, texture = 136140, handler = function () applyDebuff( "target", "curse_of_tongues" ) removeDebuff( "target", "curse_of_exhaustion" ) removeDebuff( "target", "curse_oF_weakness" ) setCooldown( "curse_of_fragility", max( 6, cooldown.curse_of_fragility.remains ) ) setCooldown( "curse_of_weakness", max( 6, cooldown.curse_of_weakness.remains ) ) end, }, curse_of_weakness = { id = 702, cast = 0, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 615101, handler = function () applyDebuff( "target", "curse_of_weakness" ) removeDebuff( "target", "curse_of_exhaustion" ) removeDebuff( "target", "curse_oF_tongues" ) setCooldown( "curse_of_fragility", max( 6, cooldown.curse_of_fragility.remains ) ) setCooldown( "curse_of_tongues", max( 6, cooldown.curse_of_tongues.remains ) ) end, }, dark_pact = { id = 108416, cast = 0, cooldown = 60, gcd = "spell", toggle = "defensives", startsCombat = false, texture = 538538, talent = "dark_pact", handler = function () spend( 0.2 * health.current, "health" ) applyBuff( "dark_pact" ) end, }, dark_soul = { id = 113860, cast = 0, cooldown = 120, gcd = "off", toggle = "cooldowns", spend = 0.01, spendType = "mana", startsCombat = false, texture = 463286, talent = "dark_soul_misery", handler = function () applyBuff( "dark_soul_misery" ) stat.haste = stat.haste + 0.3 end, copy = "dark_soul_misery" }, deathbolt = { id = 264106, cast = 1, cooldown = 30, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, pvptalent = "deathbolt", handler = function () end, }, demon_armor = { id = 285933, cast = 0, cooldown = 0, gcd = "spell", pvptalent = "demon_armor", startsCombat = false, texture = 136185, handler = function () applyBuff( "demon_armor" ) end, }, --[[ demonic_circle = { id = 48018, cast = 0.5, cooldown = 10, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, handler = function () end, }, demonic_circle_teleport = { id = 48020, cast = 0, cooldown = 30, gcd = "spell", spend = 0.03, spendType = "mana", startsCombat = true, handler = function () end, -- Conduit in WarlockDemonology.lua }, demonic_gateway = { id = 111771, cast = 2, cooldown = 10, gcd = "spell", spend = 0.2, spendType = "mana", startsCombat = true, handler = function () end, }, ]] devour_magic = { id = 19505, cast = 0, cooldown = 15, gcd = "off", spend = 0, spendType = "mana", startsCombat = true, toggle = "interrupts", usable = function () if buff.dispellable_magic.down then return false, "no dispellable magic aura" end return true end, handler = function() removeBuff( "dispellable_magic" ) end, }, drain_life = { id = 234153, cast = function () return 5 * haste * ( legendary.claw_of_endereth.enabled and 0.5 or 1 ) end, channeled = true, breakable = true, cooldown = 0, gcd = "spell", spend = function () return active_dot.soul_rot == 1 and 0 or 0.03 end, spendType = "mana", startsCombat = true, texture = 136169, tick_time = function () return class.auras.drain_life.tick_time end, start = function () removeBuff( "inevitable_demise" ) removeBuff( "inevitable_demise_az" ) end, finish = function () if conduit.accrued_vitality.enabled then applyBuff( "accrued_vitality" ) end end, auras = { -- Conduit accrued_vitality = { id = 339298, duration = 10, max_stack = 1 }, -- Azerite inevitable_demise_az = { id = 273525, duration = 20, max_stack = 50 } } }, drain_soul = { id = 198590, cast = 5, channeled = true, cooldown = 0, gcd = "spell", prechannel = true, breakable = true, breakchannel = function () removeDebuff( "target", "drain_soul" ) end, spend = 0.01, spendType = "mana", startsCombat = true, talent = "drain_soul", texture = 136163, break_any = function () if not settings.manage_ds_ticks then return true end return nil end, tick_time = function () if not talent.shadow_embrace.enabled or not settings.manage_ds_ticks then return nil end return class.auras.drain_soul.tick_time end, start = function () applyDebuff( "target", "drain_soul" ) applyBuff( "casting", 5 * haste ) channelSpell( "drain_soul" ) removeStack( "decimating_bolt" ) removeBuff( "malefic_wrath" ) if talent.shadow_embrace.enabled then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end end, tick = function () if not settings.manage_ds_ticks or not talent.shadow_embrace.enabled then return end applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end, }, --[[ enslave_demon = { id = 1098, cast = 3, cooldown = 0, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, handler = function () end, }, eye_of_kilrogg = { id = 126, cast = 2, cooldown = 0, gcd = "spell", spend = 0.03, spendType = "mana", startsCombat = true, handler = function () end, }, ]] fear = { id = 5782, cast = 1.7, cooldown = 0, gcd = "spell", spend = 0.05, spendType = "mana", startsCombat = true, handler = function () applyDebuff( "target", "fear" ) end, }, fel_domination = { id = 333889, cast = 0, cooldown = function () return 180 + conduit.fel_celerity.mod * 0.001 end, gcd = "spell", startsCombat = false, texture = 237564, essential = true, nomounted = true, nobuff = "grimoire_of_sacrifice", handler = function () applyBuff( "fel_domination" ) end, }, grimoire_of_sacrifice = { id = 108503, cast = 0, cooldown = 30, gcd = "spell", startsCombat = false, texture = 538443, usable = function () return pet.exists and buff.grimoire_of_sacrifice.down end, handler = function () applyBuff( "grimoire_of_sacrifice" ) end, }, haunt = { id = 48181, cast = 1.5, cooldown = 15, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, texture = 236298, talent = "haunt", handler = function () applyDebuff( "target", "haunt" ) if level > 51 then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end end, }, health_funnel = { id = 755, cast = 5, channeled = true, breakable = true, cooldown = 0, gcd = "spell", startsCombat = false, texture = 136168, start = function () end, }, howl_of_terror = { id = 5484, cast = 0, cooldown = 40, gcd = "spell", startsCombat = true, texture = 607852, talent = "howl_of_terror", handler = function () applyDebuff( "target", "howl_of_terror" ) end, }, malefic_rapture = { id = 324536, cast = function () return buff.calamitous_crescendo.up and 0 or 1.5 end, cooldown = 0, gcd = "spell", spend = function () return buff.calamitous_crescendo.up and 0 or 1 end, spendType = "soul_shards", startsCombat = true, texture = 236296, handler = function () if legendary.malefic_wrath.enabled then addStack( "malefic_wrath", nil, 1 ) end if set_bonus.tier28_2pc > 0 then if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 2 end if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 2 end if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 2 end end if buff.calamitous_crescendo.up then removeBuff( "calamitous_crescendo" ) end end, }, mortal_coil = { id = 6789, cast = 0, cooldown = 45, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, texture = 607853, talent = "mortal_coil", handler = function () applyDebuff( "target", "mortal_coil" ) gain( 0.2 * health.max, "health" ) end, }, nether_ward = { id = 212295, cast = 0, cooldown = 45, gcd = "spell", pvptalent = "nether_ward", startsCombat = false, texture = 135796, handler = function () applyBuff( "nether_ward" ) end, }, phantom_singularity = { id = 205179, cast = 0, cooldown = 45, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 132886, talent = "phantom_singularity", handler = function () applyDebuff( "target", "phantom_singularity" ) end, }, --[[ ritual_of_summoning = { id = 698, cast = 0, cooldown = 120, gcd = "spell", spend = 0, spendType = "mana", toggle = "cooldowns", startsCombat = true, handler = function () end, }, ]] seed_of_corruption = { id = 27243, cast = 2.5, cooldown = 0, gcd = "spell", spend = 1, spendType = "soul_shards", startsCombat = true, texture = 136193, velocity = 30, usable = function () return dot.seed_of_corruption.down end, impact = function () applyDebuff( "target", "seed_of_corruption" ) if active_enemies > 1 and talent.sow_the_seeds.enabled then active_dot.seed_of_corruption = min( active_enemies, active_dot.seed_of_corruption + 2 ) end end, }, shadow_bolt = { id = 686, cast = 2, cooldown = 0, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, texture = 136197, velocity = 20, notalent = "drain_soul", cycle = function () return talent.shadow_embrace.enabled and "shadow_embrace" or nil end, handler = function () removeBuff( "malefic_wrath" ) end, impact = function () if talent.shadow_embrace.enabled then applyDebuff( "target", "shadow_embrace", nil, debuff.shadow_embrace.stack + 1 ) end end, }, shadowfury = { id = 30283, cast = 1.5, cooldown = 60, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 607865, handler = function () applyDebuff( "target", "shadowfury" ) end, }, siphon_life = { id = 63106, cast = 0, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 136188, talent = "siphon_life", handler = function () applyDebuff( "target", "siphon_life" ) end, }, soulstone = { id = 20707, cast = 3, cooldown = 600, gcd = "spell", startsCombat = false, handler = function () applyBuff( "soulstone" ) end, }, spell_lock = { id = 19647, known = function () return IsSpellKnownOrOverridesKnown( 119910 ) or IsSpellKnownOrOverridesKnown( 132409 ) end, cast = 0, cooldown = 24, gcd = "off", spend = 0.02, spendType = "mana", startsCombat = true, texture = 136174, toggle = "interrupts", debuff = "casting", readyTime = state.timeToInterrupt, handler = function () interrupt() end, }, summon_darkglare = { id = 205180, cast = 0, cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( level > 57 and 120 or 180 ) end, gcd = "spell", spend = 0.02, spendType = "mana", toggle = "cooldowns", startsCombat = true, texture = 1416161, handler = function () summonPet( "darkglare", 20 ) if debuff.agony.up then debuff.agony.expires = debuff.agony.expires + 8 end if debuff.corruption.up then debuff.corruption.expires = debuff.corruption.expires + 8 end -- if debuff.impending_catastrophe.up then debuff.impending_catastrophe.expires = debuff.impending_catastrophe.expires + 8 end if debuff.scouring_tithe.up then debuff.scouring_tithe.expires = debuff.scouring_tithe.expires + 8 end if debuff.siphon_life.up then debuff.siphon_life.expires = debuff.siphon_life.expires + 8 end if debuff.soul_rot.up then debuff.soul_rot.expires = debuff.soul_rot.expires + 8 end if debuff.unstable_affliction.up then debuff.unstable_affliction.expires = debuff.unstable_affliction.expires + 8 end end, }, summon_imp = { id = 688, cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end, cooldown = 0, gcd = "spell", spend = function () return buff.fel_domination.up and 0 or 1 end, spendType = "soul_shards", usable = function () return not pet.alive end, handler = function () summonPet( "imp" ) end, }, summon_voidwalker = { id = 697, cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end, cooldown = 0, gcd = "spell", spend = function () return buff.fel_domination.up and 0 or 1 end, spendType = "soul_shards", usable = function () return not pet.alive end, handler = function () summonPet( "voidwalker" ) end, }, summon_felhunter = { id = 691, cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end, cooldown = 0, gcd = "spell", spend = function () return buff.fel_domination.up and 0 or 1 end, spendType = "soul_shards", essential = true, nomounted = true, bind = "summon_pet", usable = function () if pet.alive then return false, "pet is alive" elseif buff.grimoire_of_sacrifice.up then return false, "grimoire_of_sacrifice is up" end return true end, handler = function () removeBuff( "fel_domination" ) summonPet( "felhunter" ) end, copy = { "summon_pet", 112869 } }, summon_sayaad = { id = 366222, cast = function () return ( buff.fel_domination.up and 0.5 or 6 ) * haste end, cooldown = 0, gcd = "spell", spend = function () return buff.fel_domination.up and 0 or 1 end, spendType = "soul_shards", usable = function () return not pet.alive end, handler = function () summonPet( "sayaad" ) end, copy = { "summon_incubus", "summon_succubus" } }, unending_breath = { id = 5697, cast = 0, cooldown = 0, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = false, texture = 136148, handler = function () applyBuff( "unending_breath" ) end, }, unending_resolve = { id = 104773, cast = 0, cooldown = 180, gcd = "spell", spend = 0.02, spendType = "mana", toggle = "defensives", startsCombat = true, handler = function () applyBuff( "unending_resolve" ) end, }, unstable_affliction = { id = function () return pvptalent.rampant_afflictions.enabled and 342938 or 316099 end, cast = 1.5, cooldown = 0, gcd = "spell", spend = 0.01, spendType = "mana", startsCombat = true, texture = 136228, handler = function () if azerite.cascading_calamity.enabled and debuff.unstable_affliction.up then applyBuff( "cascading_calamity" ) end applyDebuff( "target", "unstable_affliction" ) if azerite.dreadful_calling.enabled then gainChargeTime( "summon_darkglare", 1 ) end end, copy = { 342938, 316099 }, auras = { -- Azerite cascading_calamity = { id = 275378, duration = 15, max_stack = 1 } } }, vile_taint = { id = 278350, cast = 1.5, cooldown = 20, gcd = "spell", spend = 1, spendType = "soul_shards", startsCombat = true, texture = 1391774, handler = function () applyDebuff( "target", "vile_taint" ) end, }, -- Warlock - Kyrian - 312321 - scouring_tithe (Scouring Tithe) scouring_tithe = { id = 312321, cast = 2, cooldown = 40, gcd = "spell", spend = 0.02, spendType = "mana", startsCombat = true, texture = 3565452, toggle = "essences", handler = function () applyDebuff( "target", "scouring_tithe" ) end, auras = { scouring_tithe = { id = 312321, duration = 18, max_stack = 1, }, -- Conduit soul_tithe = { id = 340238, duration = 10, max_stack = 1 }, -- Legendary languishing_soul_detritus = { id = 356255, duration = 8, max_stack = 1, }, }, }, -- Warlock - Necrolord - 325289 - decimating_bolt (Decimating Bolt) decimating_bolt = { id = 325289, cast = 2.5, cooldown = 45, gcd = "spell", spend = 0.04, spendType = "mana", startsCombat = true, texture = 3578232, toggle = "essences", indicator = function() if active_enemies > 1 and settings.cycle and target.time_to_die > shortest_ttd then return "cycle" end end, handler = function () applyBuff( "decimating_bolt", nil, 3 ) if legendary.shard_of_annihilation.enabled then applyBuff( "shard_of_annihilation" ) end if soulbind.kevins_oozeling.enabled then applyBuff( "kevins_oozeling" ) end end, auras = { decimating_bolt = { id = 325299, duration = 3600, max_stack = 3, }, shard_of_annihilation = { id = 356342, duration = 44, max_stack = 1, } } }, -- Warlock - Night Fae - 325640 - soul_rot (Soul Rot) soul_rot = { id = 325640, cast = 1.5, cooldown = 60, gcd = "spell", spend = 0.005, spendType = "mana", startsCombat = true, texture = 3636850, toggle = "essences", handler = function () applyDebuff( "target", "soul_rot" ) active_dot.soul_rot = min( 4, active_enemies ) if legendary.decaying_soul_satchel.enabled then applyBuff( "decaying_soul_satchel", nil, active_dot.soul_rot ) end end, auras = { soul_rot = { id = 325640, duration = 8, max_stack = 1 }, decaying_soul_satchel = { id = 356369, duration = 8, max_stack = 4, } } }, -- Warlock - Venthyr - 321792 - impending_catastrophe (Impending Catastrophe) impending_catastrophe = { id = 321792, cast = 2, cooldown = 60, gcd = "spell", spend = 0.04, spendType = "mana", startsCombat = true, texture = 3565726, toggle = "essences", velocity = 30, impact = function () applyDebuff( "target", "impending_catastrophe" ) end, auras = { impending_catastrophe = { id = 322170, duration = function () return 12 * ( 1 + conduit.catastrophic_origin.mod * 0.01 ) end, max_stack = 1, copy = "impending_catastrophe_dot" }, } }, } ) spec:RegisterSetting( "manage_ds_ticks", false, { name = "Model |T136163:0|t Drain Soul Ticks", desc = "If checked, the addon will expend |cFFFF0000more CPU|r determining when to break |T136163:0|t Drain Soul channels in favor of " .. "other spells. This is generally not worth it, but is technically more accurate.", type = "toggle", width = "full" } ) spec:RegisterSetting( "agony_macro", nil, { name = "|T136139:0|t Agony Macro", desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.", type = "input", width = "full", multiline = true, get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.agony.name end, set = function () end, } ) spec:RegisterSetting( "corruption_macro", nil, { name = "|T136118:0|t Corruption Macro", desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.", type = "input", width = "full", multiline = true, get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.corruption.name end, set = function () end, } ) spec:RegisterSetting( "sl_macro", nil, { name = "|T136188:0|t Siphon Life Macro", desc = "Using a macro makes it easier to apply your DOT effects to other targets without switching targets.", type = "input", width = "full", multiline = true, get = function () return "#showtooltip\n/use [@mouseover,harm,nodead][] " .. class.abilities.siphon_life.name end, set = function () end, } ) spec:RegisterOptions( { enabled = true, aoe = 3, nameplates = false, nameplateRange = 8, damage = true, damageExpiration = 6, potion = "spectral_intellect", package = "Affliction", } ) spec:RegisterPack( "Affliction", 20220821, [[Hekili:v33cZTnosd(BX7uLI1ehhRhotM5IDvzsM92mFZRko7MVQU6SmffKf3qrQLpSJ3kN(TFD3aKeaeaeusE28vvQyBsGgan63DdWRhD9hU(QfbfSR)TXNnE8zVC8Oth9IZMmEY1xv8Wg21xTji8tb3c)ssWA4)F9YLXrHfrPj4REionybcI80YSq41Rkk2K)dp)53gvSQC(PHPRFEE06Y4aShHzbllW)o85xF18YO4I3LC9CJJ)OxaWCdleE8lohaB0IfmEBz5HYZIT38XGS40WpT9NFD5TL5fBVz8OtG)dG22FE7p)Mvbj3YY)HT)8Z2EZRbOSy7nxTHfhV9MFb61PYp)TS7GLX2B(1GBJcvEZ8mwWNcbqLWGogNcVF7nltH2(2SGiysCvAzmVhF4EOPimIzlXw9(GnfLzS6EvKU9M7tZGMeTC7npKw(e8LRJYZJsUD7nbqlGUMaRdeUfRcGFll9EoW)PKG5XmeOR3eGTPbrKV9M)4U)OQ3sZLC(ygCxAeUsItVNgO3gK9PBJdWbhhiypQi6zfbz3YaWE)ZHE82F)dqFl3WH1BstGTGCO55PRzk9)pYyB2EtyqCSySYylkdHxaB)Bklc47tfrRzCqDfoeCOGDAwaTaMfhH7EWKplIjauo87HfklGWvSWprRaS95vOO7ttEc8J5mC0dGgbn94GBHnNJgYh1Fpj(bCSX3a0Iqd3KXE2MY44QT6)jr(8xMxMbt3382CeCWMmdNuyNG9RLr3UQ4VOSzgSzdc4uc84dMNMNlAj8ZJtsXfqwq(kyebMPCX85VgZYxXzj(hPidcUXEvA8D0MFyamfJNH0iHej8coWJskyzzLBkGxXHZ7GNCBgWcT9MFJfMbT5x)iU2IsZIkEGJM4T8TcCugrHkr5cOpGFfzacJwdZee7(JPXyBlxU8uGtplDjm)U(QV5BKP5Ky(OxyIbeFrdti(x2yevFNoZO6B9LHu0RhpMsXa0hgt550HG5uaVdfdQaC)hGjvmYozuRjd(tKzvmMhegwbS8KPv06DLXf5)47B5Nc4qy3EEqXflHP5I01rj0((jrlVa35V8SbhTHvCAqC0DSbhr9)2SO1PrzSzPlNLheMfbmpStl3yaQp9INNxUEnqHaaX87lZzZIkyRpbTK4IcG0cHl0fGakTmFwi9BLcMgparEAmlyv(SCadYkMvWcxLe9VkzM7RXfdT65mMMxSmIXEHzqUSMIW87Vlilc7oF6UiTiFgSfU4HtUliUKDb2L7yWErbyOerJaqa2hKEEWTPjpO(OsalHaDwqTigObhFKyzKhTzfXNUSEY)LVi1DP3F5zdhCm(SnablSFmdL2b2QHKGNwerCWF5lva2uJedWqleealmInBwCNehLWMfU4IrNHy(Cu()mUCT8tB38zbPSlVyIzOVkOmXgLwBuuLQOF6ZSWYcK5KDhl7bUupu(e8FaOqnir5OCSGOyeeNwpcIzlxDN4zWyTG0tnBnQMs(56cn50aWc6eU8YlgHyaXgdlHTgKNE5eziSMRTAwgxzf2CIReGCW6OcILjdmhgK3LsmLOM2auHAoBtax4sGqpnxSnPGKK3eNMTGlZHeL8HtHUwMLb7ZnIhtH9G1r)BexrDSe1TWL38hxDQ8mnRmP9snbhNzRVxz9gMcslb6OttQMfdGoJcUVLDA1c(EyUVAGkQ5IrdSthsl9xlTuZftzyKt(eJu5Sk4oq4kSoVc03H7WOQI8G7QxEvQp4YvFFAXZF36naULeQ(MGIaum1MvSN)h8ja0YMzayWtkqdLDFeIKWPryAA8I07toTBIcXSCw(M4OIzKUZU70cwCWdadJOZ5D3dGNOOU5k7kKqaWfU4zzWVuZ5JpnQchmlSbfqcsuAMdjidhqqoFvq2IlNWB(DGUtGVh0n2aMk5xP3pdWKZqPbESOweaCESMLLcngQvF2YagiDSsu8Pki7V8L6TP6LFgBnmXYVC8zF5lh3QBPjSbw7ZReT60rNw3gXRgAcyf3N6bWg3gydXjUyvIMFS6HmFwJg3m7Zc2ja2RvVFq2mQ442svKWpF6byCtKEqcSKg6d6YerDpqwo6(EHQ8bUMruEOk3h8IWqVfvoy0hKIT(UxyKobQj0bP04hj3hYjr(KeQCUlGKdbctbIxNIkpbYNSUupdotmG66SQzaJBVXm0mJVTrq4alwYvjoKMCVd9Lqq1U9gOhgv9WNLGw0e4zNiutl58h6ec7ZfKxrKzoHCf9Ozcf(iGvaPzGfwBiTfTe94LIcp2UgB3C0AsmNuXAsdQL)Bs)2FAZNDs8uhkvT((6PoN((9SLGjIRiQhGkHfKHw2Hu43Msg2aQGtPaCqKLWpQn5bGEoZd6J0cdugnO(J6a3RR1BQYwyff2r9KeZT6KP782I9TA(u01wMxcWNoSM13oZUaIaZEKqivEWsbREn7VWswzxvGNodr44EvhZwR9Zb1(G9Xos(6(QhscTTY5UE8p4uep)34sO)RbmnHKQMIx22ECc5(tR38a4loi2)3ZwKeqHzc9UIJoJscXaKGy4vq3aWKuefJO7NKtXUAbmFoE0lrzOHPjOwJGLfmUtsdLXDgqtwSrLccZ5o4mgn44k9zmXSFwQyY3s)2Rg9cu0e7FvgTzdBr7E0RzzfBO(C0nB2bFc)nkEVYPhQJP7hrVgX4WrU)TPIekxH5H8pmHznUz9aN0ThS6yRf1J2S5WGvVYN8iGN(DKfOHZaJTjquhxYLTdcZEg68pHnhYrAOx9QSkEGno2TatJ2Mp4iliSHdp0iIoN)gSyB0l6Pe4NKxhfPk5VPCS)6G)jgzbs3BNksRqukEM3LofdACB7AOcIGIO4jHpesEGtrERzOOx2OlsUFIWTHYOtVxyj5vKp6enZembhe04MxWvmrHToSjWsi)hyQlj5gXmuAhqiX7liB(JeF5vuqk3EZVeHQ14O4G4CmE9ScsoBnQwKNG7447Ksa3(Gio)eP(emZivbumxjAmgIpz7qYnEGPatimRPfaQ3yokkzMyLU7JytOA7X4rMgk1cJ7MnbGH4ILIqZO6OfxpFg2TPYxoASm4n4zJ0c1IVpxaEpkBERj3JmUyKWt2iSLJkUry0dEYJAlsJhasEULAO2KjiX)A0ZgxZLCsddWKkTrVEEEACjg2wjyiphBOAmSmv31E10NDSjc3M4S1GrgAJKzmFDXTSH4ttb99SSte(ji74W9RyWAbZY358Lv7KTkLGqKFneys1S00Gp1sKMt5AuhpIMwFKgqkHD5GvJeZUzb24422SryrCfrnRMU1LOKM4khMONHctIKYb0E5RSl7N9YqzNmJGHPwCbURXTxUhlgMDYfQUGlT5(318IH2xK2MuZKmAnoLgzbxf2yudmzNhUzITdjnJzKHoaB4Akw)sqeuMKB1PhYmHUfcQyirtk5mGY9mkJkaCO7PNRn4oN6p1ElwuMrjk(vktgr2Mkcx9mIDbZklIedULjYNsqYdfRewBwqcmcJwgrzEloNDpT90jhfbwkXD1rY4Qvblqlq(P1ZZci32ejUPj0fvrYZOyOohZC5ScNtJ2mgFWAIs6cgLloTxdkSc)0RoE8Z4aT61K1(1kObohZ9U2FajEG2sr5cALnTKlLQCJlQ)8OBtWmAtEjZTwv4tljxpH95cZIpf(lxcTn6FtyxvpUQDrUrvaVcteBxe4jpRDlNNIDGP8c5LqrEZ0LHHr53IVgF5l0oGYZeBFt(YxKThY5MbUuXnnColwRRRA09Chs5rvqGSROmtyv1hcU5ClQunOOovKsBjZlZqjw3hLqe9hp(mPyoGEIWfKva7CWlGHkkmIcUlc7k4s2yWh6HDSnyZxwRHL4YXNnWaQuYiRVbrCvOiD31rPYKaeKMmxE9l5Pp(S)lsBIuSE2T1HpQSg29cYc5akWXSniuyjobPo41fvEn5dMdADUhIqSnYc5Sl5LKwuxiGUctNdVk9u504ZbMiuZdU1nRiD2Ii2R8PNhk2sFw)APt(BQlFkHRL5vv7aSb8wmai3sVLBq(7sy3fvWRSV3cMvNtSLbKNMFwSlLleqkNXO5PLcoqYi5fPcDGybfkRNIOZ5qrr3ood5UZejQ5JO6zYSf0eHJuUC6zcmw7guUzGHOB0dNE8kQbc58eo6q6aOf42HREw6LBhNK60G9Wjk5bSPWWQCHzoia)07eLniy4gv1GNixCG8nA9MixTD1KgC7(A1x94lI8HsfgMrlzSzlcN86IjdCAQYLtuw2sM7ix6HbPSlmioqPbpTvbDXFOVoA9iKtsWTI9o)FYE)S7zJ8Wmt8r13HppK6BOMdbMXySbgRs)MFG4O9moDTdcsBzjIjGvPHsY3O28QP8japUQ6PwRVq7YlMklxCqNq(rrkSdyBynCufO2C3gXgugVg5L6yETFvUNAVAI(SqnoMY2h4NGe)dWNpqZN4)CCNjpd4290RNodMYEl1amvBNeB0zahoq1wHbPRhBYvLACABxe)tzQQt)81C0L29P4oefjFyR4bbYNwATOy7GTvPgs9Rt2RM2o9UYXoN(yBWXgZXjXZo2YSdJAn9ayv9RzM4rNKJLFlL6UTSxsXGulFfyGQSgXJ0EVnStpug0TUGE4U2fNFMWNz7oTP6V25w9VRYc9ZnApP(K8XXJefmWxLELurDz2ZKQn3lmQQvMo3yCu6uG4RgDMp1n75E1QXyPKKSOmQXmvy(gZysj4VEfbRzRRPoYeKdzxghhTnyottxlMZRdHo52x9ZN2iEKEH5Lwf1(byh6CFq9poBqYRId8EsEyAzgo6fryqMKi51u2DH(rQdMsyQckKk2z9(8u9dI3c0aRL4zN7owEol2)EEB8dBwHUMfKNhToIFpb4F3ltcxbOEqJpStSikOinlhvWe(PyPS51jyyZHwHR87Icz(3nqTtkIVbH15SS7sJ6bklilCf8xHf5ZGTjwcq08a6FApgE8aloJfghTjVh9QiLn7tjmwo4JskfstV766SmymdYbZSVlThR1W081GHasBrCmhEA7uOmL9E6ctwwO2ezJuD0MnP6evAnaPCNhNMUWrBO3pBzz2dUAeldieuzkB1OEy7HthrBbyD5sk4wndJVWoPKQBRn(vzndqV6fglz7o9Z1uN93ft7RT2S36vgy)xIJpBFwJA9(rzrMxMWPrH)aMB5f9Fr(1((ioHJzfKw1SY5p0)v4l3Nv4l)tyfsMPIbRmBoQveKqUMLSdBLMpffEUqNUZluPLQ4yHCbp6MrMQV0x2DefUSvVApeAopgzVI)8Dan0xJdRL4RAj6L9EA4aggNoQXdVv4S73G3URYBVijBToeL3uDSVVWWLFqvvtZV(dmpkxoEqR9CXZCGpGwy6gqqeZV2BNxkoFuFOkMp3eedM92C(2fvIGwXgDY2BE7pkE1FJ8BP9c)P637dvhzrI7xS29j(C8ModRwQM2B5meCs6MlYzfrlpb9ajcNrMRGjBH0WXzHKYsTi92nfuuDTwLMMyglykP8svkW(CYiFdvgF8egQwUrvfd2sWkRu6kqXWmJ6yfpII)NVA8tLNx0G93GLoDnS0C9SGNDI6HeXrn50pfpDj3gNohpBr3dll86WjOKFwKefmevgaI6PDtAwrzsuvDQwd1F9J9cRE535QOvUnCb8Mp3ET9xJqKLqV02BQdbkvP(ajsuy0gX1deEJ6OFEzmpf9W6RwNNxAkagk5banAPJfa(cFGNbZkSaUx6d4SRd3cuNwFGtiAIn4MH4EiruTpKSMtqUq66Cs)C6G9dpzfPan)91NTPF04K1GahP4pqmddQNNYsTncndX(rbs(iN7YZ6C9F1pvV4r5V2x8uRRLH3VzSQGYEGeCJs1aBxsYV0clWUzQHz6Fh2Kn1yh80(kZD2lZsMQECLrbSbTo3bCzTQo(6wiBGQS6dMa1XFRvrQ8RGh9jzKZJtM0rKYfHMxzDUhPIIxkJuL9YOc2U(KRHz3srDGpNgUEmN35SNXpbAMlpsCBFIOiOR1JYlx6B5Y3X7coSkAJwW4hlhqpcVEm5LSoDx3fcdjvlUjLRNth2L5y58n90ZPZ(lsaqDjQsjomqL4DUgQHSGLxije6dJ)UH9KQ7yxvaPRct90Z520(6fCdardq(13lSnjVctW(CrwqJbEb0bCP62UcjcWc0pItf05oUazlBHi(wUTqEB)s31J6ouHP9Oos1Wzk3VE8tglh1H6D7ICxovy(rm)lifPI1LlWAfvJawklNMXR1Y0nwZoDRjPRUPkfVRwRPWOTNzQLw03iF7kUvRQ6BDzlAgb4BgoRVOgnNEZzRkxhKKgTO6kvd2FEwZEJWNdXSV3UxmHlYnPonPrex3BVIFRrs3MPOS27z4qDhtWBHg9iUrh7KMZysxLZzR1EA2GLooRkotv7RM81xcHTS8)kEAAj515Sl0kz28V2tgFUJCXRysGw(jWktbm)pVaKIEBuSLo12vSWGSC0hSL4PGjdKUpdn1yjZxaaZ)WSsU4Y)vjihVCn4ZMAwc7ec0DAkM1Rfr3Hx)LZXl9yp7E6DSSLC)AMfKaBDZcXtyNN9gTmCDkgIpw4NMTPSGFDr6)SFDqyWCWWY8vmWB11G3yH(21LXb8l415bffXEpI3h8j0s)CyllnzHV9I2HkWrBblFtGCIyD3rPCsopyH)y2uytmk)tK)9aTjDOM9SRRsZsW(DxqCQ3ZtCxeVCibfr5R9TtGfzGfwRyblQMNjb3gVmWXOAknN6TXq6sBbgPeHYpS2yuM4Nz38skMxBVz7)pWCtWCQ)7F)984n9lLb4jlhu()UNGQ(cttaYFYu8Ivrc)6qdOwTMvqxk4vJFv8uKUbn1I)mD8tb()QRlerCyp(4rFRJBqKNk)A7cduBNE8K0ERE0Rgo8Iroxjp1waLttyvldXJoDeyVbLz)WbQpQYQ5H72qvCFQ(qnU9qnEFgk1QiOA0oQhlnmTvh1J5h0(6TLokefFwakTPA(B82qSj0skRzRx0HoA)OV10iqKC1VqN2hi4m3tyS6SNxFfWtMdifXxSJxm67U(Q7dYqFIZV(Qp(63)BV73(F)da79nFanDnAnNBNCW(jgWJpbTMgGFgYNZVW5dkbhM4(GZVl1X7TLFHU3Mg)d0nDFLCHN0qk8F)eUaI6hvWF2XJ)8W6UpXs3hBO7JB39P73OBR7Do6B)5oWRALGt)WPF)pGUKiKlJnOsnY267p6)p40tRWH()()I)Haa9ynkNmvSgKJoZlyQwrrMbyNRDfLp9BLpASxttdA7DU4p3lOAv98oIhQsRxprb60KCxbAiif)DL3air5ijAA9(xvbK1aO(b2Gqlw6EodAXt3Z(3IRCp7F)XaNVZZGojkwWwgug3tAIDy(GHl(N(9FPJfwZP(UgwspYg65LhQPZ33FX3t9O7oeFl39r7cRMS6Jr7lNYO9LuFulkdX6nyEy9f0xdzViqTWlBbOxCOa03DqiXAbMDE(OtSUJZNw08748z8(kDC8(sZmUfBJhaqXMT9LVzY(Y3mzFrIt0j33nQIjhgI9jhgA0j7YgRtaSBZJPN1)5Hz9dtBjvQBiPAGV(guDAiQbrZtCmD6uTEqk7j9sL(Uqb701fp6)HXeN9q33ezaSlya3IK7gaMjZgFWiyhVdIgTajDs)hlk3Q8A0pY3DyDQU86F)nJNgTd7DQayFxk7eNWOdjNW4wgl1xaOZkTJeB7H9bvuRVBDLp6JMSv5ZLfs8D9v0VrFHBLJYa8GFJ(05kG41)y13hxTmvD9vCq2(ffx)BJncbRjTQbw2Bca1jgHQ9Gx3awhTbG7uBW1u(TuaQXgaq8CJq0CkVAaOL3dW7fgHN1KG1as7nbG63zeQgYmwd8m9sasV0iK0suwdu0FbaHV3ieuZzwda0Eo0)rNzMOf)B50Njr226viymt7RNmTgO06niqmt(BiwBuRntwRKmTMXt9Xy3nt9QKwnP9pLhJD3mPQ1i4r9HihRaztI1KHd2SVtUz15wtVvVuby1PxtTzfW(v7aSBsyv6gqkcRObKvH8h)T4s4hhdcjbHIBV5B3EJ9mKT9MHBV5PMAQJuNBTp6zoZrl1ZIg1u4FxanL)vcplAdFPzk3J0cEMqGRwsomjA2l8LuSJQs902Bg065nvU8q5PHu6BmjgVFZGXwMbJ9zguCFQjb(EndoI2T6pMG(3x(c1Bny49APggUZQN8swnVjMuk51Q2uo4OjRLm3jVAnLfoF7lNRW8ORX6ynNE1SnDbvAE1BOAIaJeoXLxPL4k7gwjFZeizjK8tTAsL(9tGKMF93y1aklKsnA4m9ARMn58IlObQUBMvtOuUpdAGM6JTAWu7R1Ggqy4DwnrY6vCqd4S3eRMljFu1Lq)Yp1QHsTsHPdBIutnPdRECC7g0m)C1ioFG2rd2eJGXf7vGIoG4pkGee1(qctIsSEqH3EZR2EZlKfPOFOHv7VZdoSdGrE9ZVmNXxPDqI1Eycx(LXDCd841K36gNCiWn49T9Hd5ybA7d2P9Q2GiSAXL6MnDiqrFLt(0EnBqQSS(ezlqpe4NxEiXpMb2EHF0xYguRuJEmF2gpeyPPhsSKzGTxyjlRCHrmYNaRAr31wmwFt2O5v3y5wvFv2O1OjYnIFx2O1IP(4b55E5n6l8XnZw67B29pYe6gdEgEaVq0sJgrTZfgpuBZQ0PYHrTzancWuVYcUw3)36EAq)PY0ueuqtNohrxiIUJLPBTCFjqKCJoRIaQZwF52BoVxTE85cgaJxUynZ3HnikJ8iM0E2Gu8eJ0XzAYJPGU2PMPGFOJZR2zmDdYrTykh72SnZBIjeL2jIWKYHhv6MZ7dHWJoztLOztkbE8OuKhvfjqQxJDTy2RU7tCZS3(kKrOiDGViYwqqYdg8XU5RSDJYSlZcdWrcB18s3SzDD5YSlZmhWt2F2wnYndNLBIMDzc2gmYUNv9UkVXOQMRLM88nmqRvCA4NCQjNDhq2oBDWTysbARm34kf7CZxEcAwpP)kodsnMRMMHHeycGiyDurAz(SqEQowKEA5MMXq7q6AsAGsiw5N59C2Ma(NBioC45rtK4xPpNp4jYNoHTF40T38MMJ(o)dXskaZ1r)Bugc1r6u9xDLoCAZCmRmrfniHRK1O024Vb0NlFtF(zueFPVJWJr2aFubOSNuLX7RneXffS4RLWA5vFkKQc63C2QG7IsZoLo(71F1VWVEqvyQQ7(g(jx(9Pfp)DRRVxAEtJo4NB6CDR(zZw5lMTN0EMs9GbJf9cwTchIH4bP4ZbjCmv7oqM0vIVPZBs)MM664AJovmGFfjXp(4C20MoB4E5MENGIr5s2UHwPVm5QPIUOD0Umr(R4kgpi7TIWlTZPBHrlN1UKhhdH3vwd9TB39KYeqDdRFVhbh3tOp2m0hQ5SNSBM9a30HJO9fr1TFThmSwpgk3OW91)6(IYDCPp0FeUtGDir3EpqUr29Y9dFXOUDHOpOtN(5CWWL(nk2qKEkIvpTufgYtGnJLuvQB7w1t(7fx86u0ojG1itXwTu8kmAGOTZKxNk36qyI4K1jnWUf5vUEvyiDgktB824QIxLaNrJg4ZFWyk80)DIWwnPpQUy5xX(Cb9vWJUilex0rOTIfU2kmhprzX0EQw3BkNX1bvWIrakSf9IF0I0sfnYMTF5RUz)brCFNMz5OnAl6HACTkXHTWqrgPqKxFDJTG(m6YcYqhqqUZBtPjcyix6wPVnNnxZJWCto)J(sbRUPFKx777w0YpANyr62UGPhCYbFicBwqDr44To3PTOEQIMuHHYnR23(MO03sEPpxxwrcz(5blfYhlv)uNRh9dxbqRWqHTTJbRCV9FAOjCuHHsNRQvgMuA40REij0gwLhqG2Fv)10AP6vBzlxB5x7K)KihQBV53RRRnmqj8TQOKW018Dp(x6AX3Y5OINKx)5N)4rVCBZhMzXvximEd9WBmUs86aB7MZFu1owDZALby12)IgX9oRJpAZsp(egM7YczSnZ7wmYJ3YWjbwrvbxUteKsXWIt)PFdesFLNjLdCs2CfbbuODsQJML(LP7bkSv22tSCFJsy3jpA7gfv1U6oHW)D(9qyf2ag8JbUX4sUoyqjYZWyjsBld3kUR(0VDCTPk2HEjho2Yve15(WqjxBFuWP2d5JdVga27U4ogR7LZoQL7j5vuI164exTORd(NyWkrtUCz)KXO56Jbawm3YC8EgAnTZJTv9v8m(0z(LMcnr(ZyhUsqWQKPakTK6PsWAX706RyRU(s8MKKCZ6k6R4hXgmbTcGMbClB5gGqvdT0TolkBI)zWLFJEI9KGeVVGEYpsYSUIsXu9xpDABoigVYMMZkiDE1B34CG7tlUNNuYVWvd2Sj(bARAcEODQwj5N2rUqglBQOX4OQyrT1p4VvTQ(Z(lHYTBevNtfPeYTFtKA3ESKVRPoPeWvH9e2ECRGwlQ2xZlVHA2H4kcrGhw1ZlPcDbNp2nMqmSwIsbLQfrGN09jSR0wkHLSKSXX20)lN(uptFRnMC7PQ4rOazgRRlOgcsckAnnDqJZDo6zKOu3CC0oKdgHHDrupwpfyO4bzbdYYoW)A0Zgxlq7KgzvtQmQ61ZZtJlXCq(gfMJj7w07EDR7G8terbqoSa8ROx80jEoF6uBx475qLlwmGUMajrIHGCq0doPDbng0PQgZnMiSM4mMDFKMgj4ThCo46eX2ywBnoBA77eS0UIy1vIHhQ0GFLMNwN1rukEeBr)J)Hwek80)upDbTdzwKFADgiU(nR6Di70MehKaO0941ruYMyRKQTfTJ)UAml4ejs0m3ZpUv43jgXui4wGNxWWk(OYqnS(7jdY9eZil4bo81uISLGiysrUrRC9tlLMTWdQYqIpB19k)tAdezS(e7v9r9YWZ5IFl4N6QvvFjUj5VktxlrWzIU1rAL(rr4QNrciIOB4SYC8gQvCH6N8qXkHVAfKGZWOLr4cb)QgDpsd4Pcpe20KPZQsZ8LyC1EUJRYycHCmr(9SQsy5uPlR4tLmvtWb78MpUYZAFZ5e)0nmr3Qj)uurCKTv7W1mj5YLqaE5gx8I54jQcaeffnUkirmVifHjSpxywZIiEAL0NucAFxncj1HqRr3jQkQ(UUNapIsVUD1DyR2k8u5qvtBlXwoh0D6ypcgBFAbQ2WX202CBUOaBgFUt7UiUdj143t(eYBDvJUNhrkEymf7Ev5FmHCnRiLVBFlAwd)A3yz9xZb(E88Ym6ZFquYc67MbMo46GCIU8ZLtxSc1pLddvuyeR6BYvfCjCcFOvIgAN46boJfQi70dmUFOAKoI4Tfek3i(FTg7QhQpuFfj1d5pYLrDsrjeF2)Lq9DTj79ef0hteg6p(WMtd7eHiQnXSLMuerpbPl5mB51eU50N3avbb5M)WUGcPeFjOIkmiYVlvMoYlQI8bV1Ypwu121QVL(aLq4y)G0FMsEMQ7auBfNMRonBegimTfJm(3GaUN0k0pIVTkIWhLxvZNavWBX42El9wUNCVlHDxe5apgQC6lvnivkGIM0NfKk5cfoYftX80sHaiYlTfPcJp4FqOAYGlXRYHIIfzikoQESNTGg6k0m6y2zs7fTBy5gopO9OWs8FtTzYT3U9p1wCcBfGsPp1kMJxX0oJ)vpJuJYi2r8yMA9WMzoEmDVASzbLs8qmbpAU)ignelZxB2e08fTrpobg)Y20WYk)D)qqr3QXLKNFtj1IgA))r(qHOlaXWPHB63lh)CjRZvBh8NGZTHPRNh0XrbRoclNv5h2g8A2mo6ow1dOjnEkKtXlkG0LZYdG(dYczkfn)swmWNSokP(S)ReRFHJyBy6b8389naO0GglOpO9SyP6NkUkLaWj5RwxnSW2DqaqjWcwLduXHzyH2XcxLe9VkL4yT2IcpoDqMryTuRySz4aOCqGKzfuqE68oDFDDijrlukmJ1uasVNKKA(vgfgw3qLGlyuwGuW31cWCfyg2ltx8m(bk33lO)GZO4ZGysBgiBkTtssJOteJqGMH0DmlifxrxqNMfm73ZcHn)rNHJOcRSPuHXl5sx6p0z6XZ)I(H2XyAMvgNoZjNRtSOHiB6PlP(e6o3Kak2K2pcb94jU)vJ4FgZ3(4mK14L2jdLJ2OL8cVSARDaxTBVvNz4mmiHEQtguNYNpQl7ygC4sFPbZanpDTzZwlJzBlE(vvjlrmP55IVQg5mAYLnlU8y0qrzt1nYTEX7XyBp3GDPEz)T12Mt)gfTQsXinIBUBJGakly9gGhrQBQKrDTIEfPwWewQv12RAaSSdUs66vY)CRcCxzbDOZcBRknwjaMgvtixBq2QyosOApcZPNze6rumDTDlhez1EKTJ)el)DlQlp2CGkv27Sf35VkwGEsVBO(69i1wESc)pAg6AC6uPULDCgQ7Xk7WMkoRftTx5oRv196vVnDuCTwdT9(qvzxByNwP5nnE)fS36e26OElX5z7Ct1mqgIBARISufAgT8UdR2CpE(Ct4iTg8cM213PxjlUHJ1YD0C4)KmPqXP5xDrvzmRBxwLTSsUH70anhvd4H2ObhLSxhXH(IMldMAXrUJiD7arFUZazlnsto3QxHscQAI5FHHI)RQz)jeutEf(9)GcQ5y174khb1KeLRhGJQVUC5TAEE7OHySKJ)Fy4Rj(IUQV6n2PRa7wEZQyILIhFMFNZIv9sjR68iyH6IW0Gt7a7jDiXSCBwhTSlzBk5U7dc9HyEVJUnP5szrK87ROnc80urBPNW)S1tV6Vrx)wMUkGjRlSUhmdltORVQRZWs9oMpgbETH45zt)KFhLBktIIuq2uenv5zmpnnrP621Zv8b4SCB76SuWSRvWwyjDW)YXRw9nv3Fmlb1xPalQUDjA3ZAC3sEQ6c4AdHEYpS7FdqGuE22KfLMrfpaE4EQNDiMUj7TKlI3gNohp1E3diSfyOXk5NYp(6INWxrP7Ix77Ljrvf)Anu)1p2AVHyP(UgnQ2RKIBdxCkLmAdibN30p)1ieplSSEB1Twqo)CyauUrHrBeEgKUS9jf7u7x(RsRLwxLc04X33oRzxX4fiR1AK31fiRJb8foVnwTM6Hu73gRogSx66Qn1wiWY7(Qn1XqoT77ju7xGeDFo4ExLuMniftgVshevedjB9euaestPF63O(LGIHbE67Rp6HkMAku9ODhjoq(gOxtHIJqRzfy(iBMN7ljlaAF5m2koB2AR)yWR(PA0hQXYo6JADLwpdlAZwe1bQ0Eeu6gQDPyuhFAIsZDSo60mgoZDTPOMJ7CR4wOoagp9CvGS(gw0XHt2QXrANBk1liXwrXqfGDFoSutHH1Z5QB9EVVrvu9bhx68MWv8Pg5n3A8cuuCU7A3gtgJ4shxROIy4sbuFMh58iKkDKeB5G5H5mI2ranDF(x)7uHnZOcBV(aTIblsrhUphs2h1LvRWxz9WS6M08kZLJjsQnru)41gsXR08B5AB3EdPS54Ofm(r3cu5ZJKf)ybGuUXHWsGQ64KY1ZPdw1CSY9ME655iCrcrQlrvwXbduzCb3KOcwEHK44pm(7g6Gs)y)kDYUkC2tpxumLTc(LF4ZxVyre(BOnR)67fMZMxH7yFUilOXZc(bT6UGOyCuqsoavXI40CDsFj2EKDnbFl38zftE9Tct2ZsC1h8VLsx1AicLdqGveTOKt5Ntj(veahFJMkPWr6pZMPOeQQVsD(8li3GIRnlWssvJ5rkWLk7qYz41Dqd7tUGDC8CncgTdBSDDNUIKXal5RwtZCRdqBv7KJEOhbeC2QY1bjPrlOc1Rzk6r4gv9xREy3QDOl(hcaGeyCiqZFBEzyYHCG44znegchZfyjp8bFcfqdB(wyLf5VNuJ)Ii5lVfyhWp7QjmX557EgoBWYGKKIGMgti5R1JsTUXN8OW26SQAAk1hJD96WwrHkRJZ41KVIc2zr1PV8RMzKX9PMTXIQZZOQJZgJ)kgC1YIv4hcPRIw)g6jx)))d]] ) end