-- 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 ( event , _ , 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 )
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 )
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
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 ( " succubus " ,
function ( )
if Glyphed ( 240263 ) then return 120526
elseif Glyphed ( 240266 ) then return 120527
elseif Glyphed ( 112868 ) then return 58963 end
return 1863
end ,
3600 )
-- 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 = 2.5 ,
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 = 2.5 ,
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_succubus = {
id = 712 ,
cast = 2.5 ,
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 ( " succubus " ) end ,
} ,
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 " , 20220226 , [ [ dq1FFdqikPSikPQIhbj0MarFIankiPtbPSkvbPxPkYSOKClqa7sIFPkQHbjYXGuTmkv9mjHMMQaxJsQSnqG ( gLuLXbjOZraH1bjQ3rjvvQ5bs5Ess7JaCqciTqvHEiiKjQkOUiivXgvfe9rciIrQki4KeqzLGKxsarQzcsLBccQDsPYpbPknuqqwkbu9uiMQKORsjvLTsar9vibgRKG3sjvvYDjGiXEf8xv1Gv5WuTyvPhtXKvQlJSzH8zLy0sQtlA1Qcc9AcA2qDBqTBs ) wXWvshhKQA5apNOPJ66eA7uIVlunEqOoVqz9usvvZNs5 ( eqK0 ( L6a6HkdiBNPGD2Js2BpkzV9qWc6qq7RyfHGbeo2kfqwDJqFHciQdtbebAueonCoAaz1JHhFhQmGihrGHci1mVkr5NFEj5AX3IzGFwMWIyNZrnapIFwMWMNdiVIjMfyA4nGSDMc2zpkzV9OK92dblOdbTVIvmGixjtWo7HGwxaPo3BsdVbKnjnbebAueonCoAFOahGhJWgQhs6fi6Gy9zV1zvF2Js2BFdvdfev76cjr5gkiqFc09M29HSsyCFq3yewAOGa9jq3BA33dtwgrqFqyFjnLgkiqFc09M299cixOP2vLW9HNL00x0a67HbEQ9HmI4sdfeOVkJtUW ( GWoMIstFcCFLfbuF4zjn9XtFXhGW ( YO ( InIccO ( GtPm1L ( 8 ( yhtk3xQ9X1o3hyIxAOGa9b9O ( lM6tG7WRUY9jqJIWPHZrL9bHSaH6JDmPCPHcc0xLXjxOSpE6ZTm5UVx8ep1L ( EyhiCb7aQVu7dweZjeGDWcX9f ) 5 PVhg6TszFIRLgkiqFq0OBsLuFYbM67HDGWfSdO ( GqaATpJJXY ( 4 PpaTfnuFMbEvKDohTpoHPsdfeOpeI7toWuFghJ ) UHZr ) 4 uY9rkdss2hp9jzqA4 ( 4 Pp3YK7 ( m1KryQl9Htjl7JRDUV4Jki33l1hGCtnT7dvFXt1AOvAOGa9b9Q4y9Hq0UVrnuFRaccSkIXLgkiqFc09drrj3N1pVIaTpi6HL99srdG6J0DFtuFr5snB9tF4zjn9XtF ( 6 kowFJIJ1hp99oszFr5snl7dvD4 ( yGlR7B1ncLOvAOGa99qIjzTb4r8ZcKhSZjM6dzWwiL7Z4QHW ) mQptTRl0UpE6lvMaaXv ( NrLgkiqFcmLPfGZuF2rgW0hegf03kihqYX6dNsUeqwbtuIPackII9jqJIWPHZr7df4a8ye2qHIOyFpK0lq0bX6ZERZQ ( ShLS3 ( gQgkuef7dIQDDHKOCdfkII9bb6tGU30UpKvcJ7d6gJWsdfkII9bb6tGU30UVhMSmIG ( GW ( sAknuOik2heOpb6Et7 ( EbKl0u7Qs4 ( WZsA6lAa99Wap1 ( qgrCPHcfrX ( Ga9vzCYf2he2XuuA6tG7RSiG6dplPPpE6l ( ae2xg1xSruqa1hCkLPU0N3h7ys5 ( sTpU25 ( at8sdfkII9bb6d6r9xm1Na3HxDL7tGgfHtdNJk7dczbc1h7ys5sdfkII9bb6RY4Klu2hp95wMC33lEIN6sFpSdeUGDa1xQ9blI5ecWoyH4 ( I ) 803 dd9wPSpX1sdfkII9bb6dIgDtQK6toWuFpSdeUGDa1hecqR9zCmw2hp9bOTOH6ZmWRISZ5O9XjmvAOqruSpiqFie3NCGP ( mog ) DdNJ ( XPK7JugKKSpE6tYG0W9XtFULj39zQjJWux6dNsw2hx7CFXhvqUVxQpa5MAA3hQ ( INQ1qR0qHIOyFqG ( GEvCS ( qiA33OgQVvabbwfX4sdfkII9bb6tGUFikk5 ( S ( 5 veO9brpSSVxkAauFKU7BI6lkxQzRF6dplPPpE6ZxxXX6BuCS ( 4 PV3rk7lkxQzzFOQd3hdCzDFRUrOeTsdfkII9bb67HetYAdWJ4NfipyNtm1hYGTqk3NXvdH ) zuFMAxxODF80xQmbaIR8pJknuOik2heOpbMY0cWzQp7idy6dcJc6BfKdi5y9HtjxAOAOCdNJklRaYmWVoxnIW ) 9 aNQZ5OwLrv5eMeakbP1wjU440cbP1EfJIklGeEsa9NOV0nGmknurCTHYnCoQSSciZa ) 68 tvFwkcdp6FL4gk3W5OYYkGmd8RZpv9zrj9tMGTsDyQkpW0FI ( WJkzWik ) MrLmq0W5OYgk3W5OYYkGmd8RZpv9zrj9tMGTsDyQQCWKxl ) sYai ( ZKPwtOVi1q5gohvwwbKzGFD ( PQpVas4jb0FI ( s3aYO0qwLrvzhtkxwaj8Ka6prFPBazuAOcP ( lM2nuUHZrLLvazg4xNFQ6ZryswBaEe3q5gohvwwbKzGFD ( PQpBXbP ) IjRuhMQUhw ( bKVJzLfhlsvDdNwO ) E4IzaaXvohvaOeKUHtl0FpCXxgnMaqjiDdNwO ) E4IOkz ) ftFpkcNgohvaOeKOAn2XKYfzUwp6hNruHu ) ftBB2CdNwO ) E4ImxRh9JZisaOeAqI6E4YATR8a ) LPUiIDqYXkCAeM6InBwJDmPCzT2vEG ) YuxeXoi5yfs9xmTrRHYnCoQSSciZa ) 68 tvFws0 ( prFZaaIRCoQv4uPVzxfDuYQmQQCLW4p7GfILfjr7 ) e9ndaiUY5OFFibuTInuUHZrLLvazg4xNFQ6Z1UOYnuUHZrLLvazg4xNFQ6ZIQK9xm99OiCA4C0gQgkuef7d6bIjJit7 ( ileiwFCct9X1uFUHhqFPSp3INy ) ftLgk3W5OYQYvcJ ) 4 XiSHYnCoQ8PQpVjlJi4d7lPPHYnCoQ8PQpBCm ( 7 goh9JtjBL6WuvFiRKminCv0TkJQ6goTqFsj4KKcOInuUHZrLpv9zyhtrP5d8vweqwLrvFfJIkgh7WjpIYVbqsdP7PiU2qHI9brog3NKwDGZuFUHZr7dNsUVOb0NDKbm4bS7dcJc6l1 ( qQS0hejcaKY4y9nkowFZkNWP1FA3x0a6tus9fp56 ( GqiLgk3W5OYNQ ( mqu ) UHZr ) 4 uYwPomvvjdy ( WXTsYG0Wvr3QmQQzSqQRCrjdyWdydjquPObSqfyhtrP5hh4CnKUHtl0Nucojzv0HKDmPCzT2vEG ) YuxeXoi5ynuOyFcudNJ2hoLSSVOb0hdsviX99s1ULCaL ( qyNL95aQpPBH29fnG ( EPObq9HmI4 ( e4d ) SadEL0DQl9bro7sgmR10ZqOAx5bUpKuxeXoi5yw13W1eiEkP ( gTpZm49exlnuUHZrLpv9zJJXF3W5OFCkzRuhMQYGufs8xUIt ( BQjJWgk3W5OYNQ ( SXX4VB4C0poLSvQdtv3e2Jr7pdsviXYgk3W5OYNQ ( SXX4VB4C0poLSvQdtvLSZFgKQqILwjzqA4QOBvgvf19Wf5iI ) GHlCAeM6InB7Hlj8kP7ux ( gNDjdM1A6VhUWPryQl2SThUSw7kpWFzQlIyhKCScNgHPUGgKYre ) L1oylGkAZ2E4ILetF2tLlCAeM6InBSJjLlYj ( NRPVKOTSHYnCoQ8PQpBCm ( 7 goh9JtjBL6Wu1Td7l0NbPkKyPvzuvZyHux5IMl18pYjir1AwCq6VyQWGufs8xUIt2MnZm49exlYre ) bdxaeSNQua2Js2SHQfhK ( lMkmivHe ) hLG0mdEpX1ICeXFWWfab7PkHgdsviXf0lMzW7jUwaeSNQenB2q1Ids ) ftfgKQqI ) C8bsZm49exlYre ) bdxaeSNQeAmivHexSVyMbVN4AbqWEQs0qZMnZyHux5Ifs56yair1AwCq6VyQWGufs8xUIt2MnZm49exlj8kP7ux ( gNDjdM1AQaiypvPaShLSzdvloi9xmvyqQcj ( pkbPzg8EIRLeEL0DQlFJZUKbZAnvaeSNQeAmivHexqVyMbVN4AbqWEQs0Szdvloi9xmvyqQcj ( ZXhinZG3tCTKWRKUtD5BC2LmywRPcGG9uLqJbPkK4I9fZm49exlac2tvIgA2SHQzSqQRCrjdyWdyBZMzSqQRCrymq6QnBMXcPUYfDucnir1AwCq6VyQWGufs8xUIt2MnZm49exlR1UYd8xM6Ii2bjhRaiypvPaShLSzdvloi9xmvyqQcj ( pkbPzg8EIRL1Ax5b ( ltDre7GKJvaeSN
end