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.

1776 lines
65 KiB

4 years ago
-- PriestShadow.lua
-- June 2018
local addon, ns = ...
local Hekili = _G[ addon ]
local class = Hekili.Class
local state = Hekili.State
local FindUnitBuffByID, FindUnitDebuffByID = ns.FindUnitBuffByID, ns.FindUnitDebuffByID
local PTR = ns.PTR
-- Conduits
-- [x] dissonant_echoes
-- [-] haunting_apparitions
-- [x] mind_devourer
-- [x] rabid_shadows
-- Covenant
-- [-] courageous_ascension
-- [x] shattered_perceptions
-- [x] festering_transfusion
-- [x] fae_fermata
-- Endurance
-- [x] charitable_soul
-- [x] lights_inspiration
-- [x] translucent_image
-- Finesse
-- [x] clear_mind
-- [x] mental_recovery
-- [-] move_with_grace
-- [x] power_unto_others
if UnitClassBase( "player" ) == "PRIEST" then
local spec = Hekili:NewSpecialization( 258, true )
spec:RegisterResource( Enum.PowerType.Insanity, {
mind_flay = {
channel = "mind_flay",
last = function ()
local app = state.buff.casting.applied
local t = state.query_time
return app + floor( ( t - app ) / class.auras.mind_flay.tick_time ) * class.auras.mind_flay.tick_time
end,
interval = function () return class.auras.mind_flay.tick_time end,
value = function () return ( state.talent.fortress_of_the_mind.enabled and 1.2 or 1 ) * 3 end,
},
mind_sear = {
channel = "mind_sear",
last = function ()
local app = state.buff.casting.applied
local t = state.query_time
return app + floor( ( t - app ) / class.auras.mind_sear.tick_time ) * class.auras.mind_sear.tick_time
end,
interval = function () return class.auras.mind_sear.tick_time end,
value = function () return state.active_enemies end,
},
void_torrent = {
channel = "void_torrent",
last = function ()
local app = state.buff.casting.applied
local t = state.query_time
return app + floor( ( t - app ) / class.abilities.void_torrent.tick_time ) * class.abilities.void_torrent.tick_time
4 years ago
end,
interval = function () return class.abilities.void_torrent.tick_time end,
value = 15,
},
mindbender = {
aura = "mindbender",
last = function ()
local app = state.buff.mindbender.expires - 15
local t = state.query_time
return app + floor( ( t - app ) / ( 1.5 * state.haste ) ) * ( 1.5 * state.haste )
end,
interval = function () return 1.5 * state.haste * ( state.conduit.rabid_shadows.enabled and 0.85 or 1 ) end,
value = function () return ( state.buff.surrender_to_madness.up and 12 or 6 ) end,
},
shadowfiend = {
aura = "shadowfiend",
last = function ()
local app = state.buff.shadowfiend.expires - 15
local t = state.query_time
return app + floor( ( t - app ) / ( 1.5 * state.haste ) ) * ( 1.5 * state.haste )
end,
interval = function () return 1.5 * state.haste * ( state.conduit.rabid_shadows.enabled and 0.85 or 1 ) end,
value = function () return ( state.buff.surrender_to_madness.up and 6 or 3 ) end,
},
death_and_madness = {
aura = "death_and_madness",
last = function ()
local app = state.buff.death_and_madness.applied
local t = state.query_time
return app + floor( t - app )
end,
interval = 1,
value = 10,
}
} )
spec:RegisterResource( Enum.PowerType.Mana )
-- Talents
spec:RegisterTalents( {
fortress_of_the_mind = 22328, -- 193195
death_and_madness = 22136, -- 321291
unfurling_darkness = 22314, -- 341273
body_and_soul = 22315, -- 64129
sanlayn = 23374, -- 199855
intangibility = 21976, -- 288733
twist_of_fate = 23125, -- 109142
misery = 23126, -- 238558
searing_nightmare = 23127, -- 341385
last_word = 23137, -- 263716
mind_bomb = 23375, -- 205369
psychic_horror = 21752, -- 64044
auspicious_spirits = 22310, -- 155271
psychic_link = 22311, -- 199484
shadow_crash = 21755, -- 205385
damnation = 21718, -- 341374
mindbender = 21719, -- 200174
void_torrent = 21720, -- 263165
ancient_madness = 21637, -- 341240
hungering_void = 21978, -- 345218
-- legacy_of_the_void = 21978, -- 193225
surrender_to_madness = 21979, -- 319952
} )
-- PvP Talents
spec:RegisterPvpTalents( {
4 years ago
driven_to_madness = 106, -- 199259
greater_fade = 3753, -- 213602
improved_mass_dispel = 5380, -- 341167
megalomania = 5446, -- 357701
mind_trauma = 113, -- 199445
psyfiend = 763, -- 211522
thoughtsteal = 5381, -- 316262
void_origins = 739, -- 228630
void_shield = 102, -- 280749
void_shift = 128, -- 108968
void_volley = 5447, -- 357711
} )
spec:RegisterTotem( "mindbender", 136214 )
spec:RegisterTotem( "shadowfiend", 136199 )
local thought_harvester_consumed = 0
local unfurling_darkness_triggered = 0
local swp_applied = 0
spec:RegisterHook( "COMBAT_LOG_EVENT_UNFILTERED", function( _, subtype, _, sourceGUID, sourceName, _, _, destGUID, destName, destFlags, _, spellID, spellName )
4 years ago
if sourceGUID == GUID then
if subtype == "SPELL_AURA_REMOVED" then
if spellID == 288343 then
thought_harvester_consumed = GetTime()
elseif spellID == 341207 then
Hekili:ForceUpdate( subtype, true )
end
elseif subtype == "SPELL_AURA_APPLIED" then
if spellID == 341273 then
unfurling_darkness_triggered = GetTime()
elseif spellID == 341207 then
Hekili:ForceUpdate( subtype, true )
end
end
end
end, false )
4 years ago
local ExpireVoidform = setfenv( function()
applyBuff( "shadowform" )
if Hekili.ActiveDebug then Hekili:Debug( "Voidform expired, Shadowform applied. Did it stick? %s.", buff.voidform.up and "Yes" or "No" ) end
end, state )
spec:RegisterHook( "reset_precast", function ()
if buff.voidform.up or time > 0 then
applyBuff( "shadowform" )
end
if unfurling_darkness_triggered > 0 and now - unfurling_darkness_triggered < 15 then
applyBuff( "unfurling_darkness_icd", now - unfurling_darkness_triggered )
end
if pet.mindbender.active then
applyBuff( "mindbender", pet.mindbender.remains )
buff.mindbender.applied = action.mindbender.lastCast
buff.mindbender.duration = 15
buff.mindbender.expires = action.mindbender.lastCast + 15
elseif pet.shadowfiend.active then
applyBuff( "shadowfiend", pet.shadowfiend.remains )
buff.shadowfiend.applied = action.shadowfiend.lastCast
buff.shadowfiend.duration = 15
buff.shadowfiend.expires = action.shadowfiend.lastCast + 15
end
if talent.mindbender.enabled then
cooldown.fiend = cooldown.mindbender
pet.fiend = pet.mindbender
else
cooldown.fiend = cooldown.shadowfiend
pet.fiend = pet.mindbender
end
if buff.voidform.up then
state:QueueAuraExpiration( "voidform", ExpireVoidform, buff.voidform.expires )
end
if IsActiveSpell( 356532 ) then
applyBuff( "direct_mask", class.abilities.fae_guardians.lastCast + 20 - now )
end
-- If we are channeling Mind Sear, see if it started with Thought Harvester.
local _, _, _, start, finish, _, _, spellID = UnitChannelInfo( "player" )
if spellID == 48045 then
start = start / 1000
finish = finish / 1000
if start - thought_harvester_consumed < 0.1 then
applyBuff( "mind_sear_th", finish - start )
buff.mind_sear_th.applied = start
buff.mind_sear_th.expires = finish
else
removeBuff( "mind_sear_th" )
end
else
removeBuff( "mind_sear_th" )
end
if settings.pad_void_bolt and cooldown.void_bolt.remains > 0 then
reduceCooldown( "void_bolt", latency * 2 )
end
if settings.pad_ascended_blast and cooldown.ascended_blast.remains > 0 then
reduceCooldown( "ascended_blast", latency * 2 )
end
end )
spec:RegisterHook( "pregain", function( amount, resource, overcap )
if amount > 0 and resource == "insanity" and state.buff.memory_of_lucid_dreams.up then
amount = amount * 2
end
return amount, resource, overcap
end )
spec:RegisterStateTable( "priest", {
self_power_infusion = true
} )
-- Auras
spec:RegisterAuras( {
body_and_soul = {
id = 65081,
duration = 3,
type = "Magic",
max_stack = 1,
},
dark_thought = {
id = 341207,
duration = 10,
max_stack = 1,
copy = "dark_thoughts"
},
death_and_madness = {
id = 321973,
duration = 4,
max_stack = 1,
},
desperate_prayer = {
id = 19236,
duration = 10,
max_stack = 1,
},
devouring_plague = {
id = 335467,
duration = 6,
type = "Disease",
max_stack = 1,
},
dispersion = {
id = 47585,
duration = 6,
max_stack = 1,
},
fade = {
id = 586,
duration = 10,
max_stack = 1,
},
focused_will = {
id = 45242,
duration = 8,
max_stack = 2,
},
levitate = {
id = 111759,
duration = 600,
type = "Magic",
max_stack = 1,
},
mind_bomb = {
id = 226943,
duration = 6,
type = "Magic",
max_stack = 1,
},
mind_flay = {
id = 15407,
duration = function () return 4.5 * haste end,
max_stack = 1,
tick_time = function () return 0.75 * haste end,
},
mind_sear = {
id = 48045,
duration = function () return 4.5 * haste end,
max_stack = 1,
tick_time = function () return 0.75 * haste end,
},
mind_sear_th = {
duration = function () return 4.5 * haste end,
max_stack = 1,
},
mind_vision = {
id = 2096,
duration = 60,
max_stack = 1,
},
mindbender = {
duration = 15,
max_stack = 1,
},
power_infusion = {
id = 10060,
duration = 20,
max_stack = 1
},
power_word_fortitude = {
id = 21562,
duration = 3600,
type = "Magic",
max_stack = 1,
shared = "player", -- use anyone's buff on the player, not just player's.
},
power_word_shield = {
id = 17,
duration = 15,
type = "Magic",
max_stack = 1,
},
psychic_horror = {
id = 64044,
duration = 4,
type = "Magic",
max_stack = 1,
},
psychic_scream = {
id = 8122,
duration = 8,
type = "Magic",
max_stack = 1,
},
shackle_undead = {
id = 9484,
duration = 50,
type = "Magic",
max_stack = 1,
},
shadow_crash_debuff = {
id = 342385,
duration = 15,
max_stack = 2
},
shadow_mend = {
id = 342992,
duration = 15,
max_stack = 2
},
shadow_word_pain = {
id = 589,
duration = 16,
type = "Magic",
max_stack = 1,
tick_time = function () return 2 * haste end,
},
shadowfiend = {
duration = 15,
max_stack = 1
},
shadowform = {
id = 232698,
duration = 3600,
max_stack = 1,
},
shadowy_apparitions = {
id = 78203,
},
silence = {
id = 15487,
duration = 4,
type = "Magic",
max_stack = 1,
},
surrender_to_madness = {
id = 319952,
duration = 25,
max_stack = 1,
},
twist_of_fate = {
id = 123254,
duration = 8,
max_stack = 1,
},
unfurling_darkness = {
id = 341282,
duration = 15,
max_stack = 1,
},
unfurling_darkness_icd = {
id = 341291,
duration = 15,
max_stack = 1
},
vampiric_embrace = {
id = 15286,
duration = 15,
max_stack = 1,
},
vampiric_touch = {
id = 34914,
duration = 21,
type = "Magic",
max_stack = 1,
tick_time = function () return 3 * haste end,
},
void_bolt = {
id = 228266,
},
void_torrent = {
id = 263165,
duration = 3,
max_stack = 1,
tick_time = 1,
},
voidform = {
id = 194249,
duration = 15, -- function () return talent.legacy_of_the_void.enabled and 3600 or 15 end,
max_stack = 1,
},
weakened_soul = {
id = 6788,
duration = function () return 7.5 * haste end,
max_stack = 1,
},
-- Azerite Powers
chorus_of_insanity = {
id = 279572,
duration = 120,
max_stack = 120,
},
death_denied = {
id = 287723,
duration = 10,
max_stack = 1,
},
depth_of_the_shadows = {
id = 275544,
duration = 12,
max_stack = 30
},
--[[ harvested_thoughts = {
id = 273321,
duration = 15,
max_stack = 1,
}, ]]
searing_dialogue = {
id = 288371,
duration = 1,
max_stack = 1
},
thought_harvester = {
id = 288343,
duration = 20,
max_stack = 1,
copy = "harvested_thoughts" -- SimC uses this name (carryover from Legion?)
},
-- Legendaries (Shadowlands)
mind_devourer = {
id = 338333,
duration = 15,
max_stack = 1,
},
measured_contemplation = {
id = 341824,
duration = 3600,
max_stack = 4
},
-- Conduits
dissonant_echoes = {
id = 343144,
duration = 10,
max_stack = 1,
},
} )
--[[ spec:RegisterHook( "advance_end", function ()
if buff.voidform.up and talent.legacy_of_the_void.enabled and insanity.current == 0 then
insanity.regen = 0
removeBuff( "voidform" )
applyBuff( "shadowform" )
end
end ) ]]
4 years ago
-- Tier 28
spec:RegisterGear( "tier28", 188881, 188880, 188879, 188878, 188875 )
spec:RegisterSetBonuses( "tier28_2pc", 364424, "tier28_4pc", 363469 )
-- 2-Set - Darkened Mind - Casting Devouring Plague has a 40% chance to grant Dark Thought. Casting Searing Nightmare has a 25% chance to grant Dark Thought.
-- 4-Set - Living Shadow - Consuming a Dark Thought causes your shadow to animate after a moment, dealing [(34%20.9% of Spell power) * 6] Shadow damage over 6 sec to all enemies within 10 yards of your target.
spec:RegisterAura( "living_shadow", {
id = 363574,
duration = 8,
max_stack = 1,
copy = "your_shadow",
meta = {
summonTime = function( t ) return t.applied end,
},
} )
rawset( state.pet, "your_shadow", state.buff.living_shadow )
4 years ago
spec:RegisterGear( "tier21", 152154, 152155, 152156, 152157, 152158, 152159 )
spec:RegisterGear( "tier20", 147163, 147164, 147165, 147166, 147167, 147168 )
spec:RegisterAura( "empty_mind", {
id = 247226,
duration = 12,
max_stack = 10,
} )
spec:RegisterGear( "tier19", 138310, 138313, 138316, 138319, 138322, 138370 )
spec:RegisterGear( "anunds_seared_shackles", 132409 )
spec:RegisterAura( "anunds_last_breath", {
id = 215210,
duration = 15,
max_stack = 50,
} )
spec:RegisterGear( "heart_of_the_void", 151814 )
spec:RegisterGear( "mangazas_madness", 132864 )
spec:RegisterGear( "mother_shahrazs_seduction", 132437 )
spec:RegisterGear( "soul_of_the_high_priest", 151646 )
spec:RegisterGear( "the_twins_painful_touch", 133973 )
spec:RegisterGear( "zenkaram_iridis_anadem", 133971 )
spec:RegisterGear( "zeks_exterminatus", 144438 )
spec:RegisterAura( "zeks_exterminatus", {
id = 236546,
duration = 15,
max_stack = 1,
} )
spec:RegisterStateExpr( "current_insanity_drain", function ()
return buff.voidform.up and ( 6 + ( 0.8 * buff.voidform.stacks ) ) or 0
end )
-- Abilities
spec:RegisterAbilities( {
damnation = {
id = 341374,
cast = 0,
cooldown = 45,
gcd = "spell",
talent = "damnation",
startsCombat = true,
texture = 236295,
-- TODO: Set up cycle.
-- cycle = function ()
handler = function ()
applyDebuff( "target", "shadow_word_pain" )
applyDebuff( "target", "vampiric_touch" )
applyDebuff( "target", "devouring_plague" )
if talent.unfurling_darkness.enabled and debuff.unfurling_darkness_icd.down then
applyBuff( "unfurling_darkness" )
applyDebuff( "player", "unfurling_darkness_icd" )
end
end,
},
desperate_prayer = {
id = 19236,
cast = 0,
cooldown = 90,
gcd = "spell",
toggle = "defensives",
startsCombat = true,
texture = 237550,
handler = function ()
health.max = health.max * 1.25
gain( 0.8 * health.max, "health" )
if conduit.lights_inspiration.enabled then applyBuff( "lights_inspiration" ) end
end,
auras = {
-- Conduit
lights_inspiration = {
id = 337749,
duration = 5,
max_stack = 1
}
}
},
devouring_plague = {
id = 335467,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return buff.mind_devourer.up and 0 or 50 end,
spendType = "insanity",
startsCombat = true,
texture = 252997,
cycle = "devouring_plague",
handler = function ()
removeBuff( "mind_devourer" )
applyDebuff( "target", "devouring_plague" )
end,
},
dispel_magic = {
id = 528,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = function () return 0.016 * ( 1 + conduit.clear_mind.mod * 0.01 ) end,
spendType = "mana",
startsCombat = false,
texture = 136066,
usable = function () return buff.dispellable_magic.up end,
handler = function ()
removeBuff( "dispellable_magic" )
if time > 0 then gain( 6, "insanity" ) end
end,
},
dispersion = {
id = 47585,
cast = 0,
cooldown = function () return talent.intangibility.enabled and 90 or 120 end,
gcd = "spell",
toggle = "defensives",
defensive = true,
startsCombat = false,
texture = 237563,
handler = function ()
applyBuff( "dispersion" )
setCooldown( "global_cooldown", 6 )
end,
},
fade = {
id = 586,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = true,
texture = 135994,
handler = function ()
applyBuff( "fade" )
if conduit.translucent_image.enabled then applyBuff( "translucent_image" ) end
end,
auras = {
-- Conduit
translucent_image = {
id = 337661,
duration = 5,
max_stack = 1
}
}
},
leap_of_faith = {
id = 73325,
cast = 0,
cooldown = 90,
charges = function () return legendary.vault_of_heavens.enabled and 2 or nil end,
recharge = function () return legendary.vault_of_heavens.enabled and 90 or nil end,
gcd = "spell",
spend = 0.03,
spendType = "mana",
startsCombat = false,
texture = 463835,
handler = function ()
if azerite.death_denied.enabled then applyBuff( "death_denied" ) end
if legendary.vault_of_heavens.enabled then setDistance( 5 ) end
end,
},
levitate = {
id = 1706,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 135928,
handler = function ()
applyBuff( "levitate" )
end,
},
mass_dispel = {
id = 32375,
cast = function () return pvptalent.improved_mass_dispel.enabled and 0.5 or 1.5 end,
cooldown = function () return pvptalent.improved_mass_dispel.enabled and 30 or 45 end,
gcd = "spell",
spend = function () return 0.08 * ( 1 + ( conduit.clear_mind.mod * 0.01 ) ) end,
spendType = "mana",
startsCombat = true,
texture = 135739,
usable = function () return buff.dispellable_magic.up or debuff.dispellable_magic.up end,
handler = function ()
removeBuff( "dispellable_magic" )
removeDebuff( "player", "dispellable_magic" )
if time > 0 then gain( 6, "insanity" ) end
end,
},
mind_blast = {
id = 8092,
cast = function () return buff.dark_thought.up and 0 or ( 1.5 * haste ) end,
charges = function () return 1 + ( buff.voidform.up and 1 or 0 ) + ( buff.dark_thought.up and 1 or 0 ) end,
cooldown = function ()
return 7.5 * haste
end,
recharge = function ()
return 7.5 * haste
end,
gcd = "spell",
3 years ago
dual_cast = function ()
4 years ago
if buff.dark_thought.up and ( buff.casting.v1 == class.abilities.mind_flay.id or buff.casting.v1 == class.abilities.mind_sear.id or buff.casting.v1 == class.abilities.void_torrent.id ) then return true end
return nil
end,
velocity = 15,
spend = function () return ( talent.fortress_of_the_mind.enabled and 1.2 or 1 ) * ( -8 - buff.empty_mind.stack ) * ( buff.surrender_to_madness.up and 2 or 1 ) end,
spendType = "insanity",
startsCombat = true,
texture = 136224,
handler = function ()
4 years ago
if buff.dark_thought.up and set_bonus.tier28_4pc > 0 then
applyBuff( "living_shadow" )
end
4 years ago
removeBuff( "dark_thought" )
removeBuff( "harvested_thoughts" )
removeBuff( "empty_mind" )
end,
},
mind_bomb = {
id = 205369,
cast = 0,
cooldown = 30,
gcd = "spell",
startsCombat = true,
texture = 136173,
talent = "mind_bomb",
handler = function ()
applyDebuff( "target", "mind_bomb" )
end,
},
mind_flay = {
id = 15407,
cast = 4.5,
cooldown = 0,
gcd = "spell",
spend = 0,
spendType = "insanity",
channeled = true,
breakable = true,
breakchannel = function ()
removeDebuff( "target", "mind_flay" )
end,
prechannel = true,
tick_time = function () return class.auras.mind_flay.tick_time end,
startsCombat = true,
texture = 136208,
aura = "mind_flay",
nobuff = "boon_of_the_ascended",
bind = "ascended_blast",
start = function ()
applyDebuff( "target", "mind_flay" )
channelSpell( "mind_flay" )
forecastResources( "insanity" )
end,
},
mind_sear = {
id = 48045,
cast = 4.5,
cooldown = 0,
gcd = "spell",
spend = 0,
spendType = "insanity",
channeled = true,
breakable = true,
breakchannel = function ()
removeDebuff( "target", "mind_sear" )
removeBuff( "mind_sear_th" )
end,
prechannel = true,
tick_time = function () return class.auras.mind_flay.tick_time end,
startsCombat = true,
texture = 237565,
aura = "mind_sear",
start = function ()
applyDebuff( "target", "mind_sear" )
channelSpell( "mind_sear" )
if azerite.searing_dialogue.enabled then applyDebuff( "target", "searing_dialogue" ) end
if buff.thought_harvester.up then
removeBuff( "thought_harvester" )
applyBuff( "mind_sear_th" )
end
forecastResources( "insanity" )
end,
},
-- SimulationCraft module: Mindbender and Shadowfiend are interchangeable.
mindbender = {
id = function () return talent.mindbender.enabled and 200174 or 34433 end,
cast = 0,
cooldown = function () return ( essence.vision_of_perfection.enabled and 0.87 or 1 ) * ( talent.mindbender.enabled and 60 or 180 ) end,
gcd = "spell",
toggle = function () return not talent.mindbender.enabled and "cooldowns" or nil end,
startsCombat = true,
texture = function () return talent.mindbender.enabled and 136214 or 136199 end,
-- talent = "mindbender",
handler = function ()
summonPet( talent.mindbender.enabled and "mindbender" or "shadowfiend", 15 )
applyBuff( talent.mindbender.enabled and "mindbender" or "shadowfiend" )
end,
copy = { "shadowfiend", 200174, 34433, 132603 }
},
power_infusion = {
id = 10060,
cast = 0,
cooldown = function () return 120 - ( conduit.power_unto_others.mod and group and conduit.power_unto_others.mod or 0 ) end,
gcd = "off",
toggle = "cooldowns",
startsCombat = false,
texture = 135939,
indicator = function () return group and legendary.twins_of_the_sun_priestess.enabled and "cycle" or nil end,
handler = function ()
applyBuff( "power_infusion" )
stat.haste = stat.haste + 0.25
end,
},
power_word_fortitude = {
id = 21562,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.04,
spendType = "mana",
startsCombat = false,
texture = 135987,
usable = function () return buff.power_word_fortitude.down end,
handler = function ()
applyBuff( "power_word_fortitude" )
end,
},
power_word_shield = {
id = 17,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = 0.02,
spendType = "mana",
nodebuff = "weakened_soul",
startsCombat = false,
texture = 135940,
handler = function ()
applyBuff( "power_word_shield" )
applyDebuff( "weakened_soul" )
if talent.body_and_soul.enabled then applyBuff( "body_and_soul" ) end
if time > 0 then gain( 6, "insanity" ) end
-- charitable_soul triggered by casting on others; not modeled.
end,
auras = {
-- Conduit
charitable_soul = {
id = 337716,
duration = 10,
max_stack = 1
}
}
},
psychic_horror = {
id = 64044,
cast = 0,
cooldown = 45,
gcd = "spell",
startsCombat = true,
texture = 237568,
talent = "psychic_horror",
handler = function ()
applyDebuff( "target", "psychic_horror" )
end,
},
psychic_scream = {
id = 8122,
cast = 0,
cooldown = 60,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136184,
notalent = "mind_bomb",
handler = function ()
applyDebuff( "target", "psychic_scream" )
end,
auras = {
-- Conduit
mental_recovery = {
id = 337956,
duration = 5,
max_stack = 1
}
}
},
purify_disease = {
id = 213634,
cast = 0,
cooldown = 8,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 135935,
usable = function () return debuff.dispellable_disease.up end,
handler = function ()
removeBuff( "dispellable_disease" )
if time > 0 then gain( 6, "insanity" ) end
end,
},
searing_nightmare = {
id = 341385,
cast = 0,
cooldown = 0,
gcd = "spell",
3 years ago
dual_cast = true,
4 years ago
talent = "searing_nightmare",
spend = 30,
spendType = "insanity",
startsCombat = true,
texture = 1022950,
channeling = "mind_sear",
handler = function ()
applyDebuff( "target", "shadow_word_pain" )
active_dot.shadow_word_pain = max( active_enemies, active_dot.shadow_word_pain )
end,
},
shackle_undead = {
id = 9484,
cast = 1.275,
cooldown = 0,
gcd = "spell",
spend = 0.01,
spendType = "mana",
startsCombat = true,
texture = 136091,
handler = function ()
applyDebuff( "target", "shackle_undead" )
end,
},
shadow_crash = {
id = 205385,
cast = 0,
cooldown = 30,
gcd = "spell",
spend = -20,
spendType = "insanity",
startsCombat = true,
texture = 136201,
},
shadow_mend = {
id = 186263,
cast = 1.5,
cooldown = 0,
gcd = "spell",
spend = 0.04,
spendType = "mana",
startsCombat = true,
texture = 136202,
handler = function ()
removeBuff( "depth_of_the_shadows" )
if level > 55 then addStack( "shadow_mend", nil, 1 ) end
removeBuff( "measured_contemplation" )
end,
},
shadow_word_death = {
id = 32379,
cast = 0,
cooldown = 20,
hasteCD = true,
gcd = "spell",
startsCombat = true,
texture = 136149,
usable = function ()
if settings.sw_death_protection == 0 then return true end
return health.percent >= settings.sw_death_protection, "health percent [ " .. health.percent .. " ] is below user setting [ " .. settings.sw_death_protection .. " ]"
end,
handler = function ()
removeBuff( "zeks_exterminatus" )
if legendary.painbreaker_psalm.enabled then
local power = 0
if debuff.shadow_word_pain.up then
power = power + 15 * min( debuff.shadow_word_pain.remains, 8 ) / 8
if debuff.shadow_word_pain.remains < 8 then removeDebuff( "shadow_word_pain" )
else debuff.shadow_word_pain.expires = debuff.shadow_word_pain.expires - 8 end
end
if debuff.vampiric_touch.up then
power = power + 15 * min( debuff.vampiric_touch.remains, 8 ) / 8
if debuff.vampiric_touch.remains <= 8 then removeDebuff( "vampiric_touch" )
else debuff.vampiric_touch.expires = debuff.vampiric_touch.expires - 8 end
end
if power > 0 then gain( power, "insanity" ) end
end
if legendary.shadowflame_prism.enabled then
if pet.fiend.active then pet.fiend.expires = pet.fiend.expires + 1 end
end
end,
},
shadow_word_pain = {
id = 589,
cast = 0,
cooldown = 0,
gcd = "spell",
spend = -4,
spendType = "insanity",
startsCombat = true,
texture = 136207,
cycle = "shadow_word_pain",
handler = function ()
applyDebuff( "target", "shadow_word_pain" )
end,
},
shadowform = {
id = 232698,
cast = 0,
cooldown = 0,
gcd = "spell",
startsCombat = false,
texture = 136200,
essential = true,
nobuff = function () return buff.voidform.up and "voidform" or "shadowform" end,
handler = function ()
applyBuff( "shadowform" )
end,
},
silence = {
id = 15487,
cast = 0,
cooldown = 45,
gcd = "off",
startsCombat = true,
texture = 458230,
toggle = "interrupts",
interrupt = true,
debuff = "casting",
readyTime = state.timeToInterrupt,
handler = function ()
interrupt()
applyDebuff( "target", "silence" )
end,
},
surrender_to_madness = {
id = 319952,
cast = 0,
cooldown = 90,
gcd = "spell",
toggle = "cooldowns",
startsCombat = true,
texture = 254090,
usable = function () return target.time_to_die < settings.stm_timer, format( "time_to_die %.2f > %.2f", target.time_to_die, settings.stm_timer ) end,
handler = function ()
applyBuff( "voidform" )
applyBuff( "surrender_to_madness" )
applyDebuff( "target", "surrender_to_madness" )
end,
},
vampiric_embrace = {
id = 15286,
cast = 0,
cooldown = 120,
gcd = "spell",
startsCombat = false,
texture = 136230,
handler = function ()
applyBuff( "vampiric_embrace" )
if time > 0 then gain( 6, "insanity" ) end
end,
},
vampiric_touch = {
id = 34914,
cast = function () return buff.unfurling_darkness.up and 0 or 1.5 * haste end,
cooldown = 0,
gcd = "spell",
spend = -5,
spendType = "insanity",
startsCombat = true,
texture = 135978,
cycle = function () return talent.misery.enabled and "shadow_word_pain" or "vampiric_touch" end,
handler = function ()
applyDebuff( "target", "vampiric_touch" )
if talent.misery.enabled then
applyDebuff( "target", "shadow_word_pain" )
end
if talent.unfurling_darkness.enabled then
if buff.unfurling_darkness.up then
removeBuff( "unfurling_darkness" )
elseif debuff.unfurling_darkness_icd.down then
applyBuff( "unfurling_darkness" )
applyDebuff( "player", "unfurling_darkness_icd" )
end
end
-- Thought Harvester is a 20% chance to proc, consumed by Mind Sear.
-- if azerite.thought_harvester.enabled then applyBuff( "harvested_thoughts" ) end
end,
},
void_bolt = {
id = 205448,
known = 228260,
cast = 0,
cooldown = function ()
return haste * 4.5
end,
gcd = "spell",
spend = function ()
return buff.surrender_to_madness.up and -24 or -12
end,
spendType = "insanity",
startsCombat = true,
texture = 1035040,
velocity = 40,
buff = function () return buff.dissonant_echoes.up and "dissonant_echoes" or "voidform" end,
bind = "void_eruption",
--[[ cooldown_ready = function ()
return buff.dissonant_echoes.up or buff.voidform.up
end, ]]
handler = function ()
removeBuff( "dissonant_echoes" )
if debuff.shadow_word_pain.up then debuff.shadow_word_pain.expires = debuff.shadow_word_pain.expires + 3 end
if debuff.vampiric_touch.up then debuff.vampiric_touch.expires = debuff.vampiric_touch.expires + 3 end
if talent.legacy_of_the_void.enabled and debuff.devouring_plague.up then debuff.devouring_plague.expires = query_time + debuff.devouring_plague.duration end
removeBuff( "anunds_last_breath" )
end,
impact = function ()
if talent.hungering_void.enabled then
if debuff.hungering_void.up then buff.voidform.expires = buff.voidform.expires + 1 end
applyDebuff( "target", "hungering_void", 6 )
end
end,
copy = 343355,
auras = {
hungering_void = {
id = 345219,
duration = 6,
max_stack = 1
}
}
},
void_eruption = {
id = 228260,
cast = function ()
if pvptalent.void_origins.enabled then return 0 end
return haste * 1.5
end,
cooldown = 90,
gcd = "spell",
startsCombat = true,
texture = 1386548,
nobuff = function () return buff.dissonant_echoes.up and "dissonant_echoes" or "voidform" end,
bind = "void_bolt",
toggle = "cooldowns",
cooldown_ready = function ()
return cooldown.void_eruption.remains == 0 and buff.voidform.down
end,
handler = function ()
applyBuff( "voidform" )
end,
},
void_torrent = {
id = 263165,
cast = 3,
channeled = true,
fixedCast = true,
cooldown = 30,
gcd = "spell",
spend = -15,
spendType = "insanity",
startsCombat = true,
texture = 1386551,
aura = "void_torrent",
talent = "void_torrent",
tick_time = function ()
return class.auras.void_torrent.tick_time
end,
breakchannel = function ()
removeDebuff( "target", "void_torrent" )
end,
start = function ()
applyDebuff( "target", "void_torrent" )
applyDebuff( "target", "devouring_plague" )
if debuff.vampiric_touch.up then applyDebuff( "target", "vampiric_touch" ) end -- This should refresh/pandemic properly.
if debuff.shadow_word_pain.up then applyDebuff( "target", "shadow_word_pain" ) end -- This should refresh/pandemic properly.
end,
tick = function ()
if debuff.vampiric_touch.up then applyDebuff( "target", "vampiric_touch" ) end -- This should refresh/pandemic properly.
if debuff.shadow_word_pain.up then applyDebuff( "target", "shadow_word_pain" ) end -- This should refresh/pandemic properly.
end,
},
-- Priest - Kyrian - 325013 - boon_of_the_ascended (Boon of the Ascended)
boon_of_the_ascended = {
id = 325013,
cast = 1.5,
cooldown = 180,
gcd = "spell",
startsCombat = false,
texture = 3565449,
toggle = "essences",
handler = function ()
applyBuff( "boon_of_the_ascended" )
end,
auras = {
boon_of_the_ascended = {
id = 325013,
duration = 10,
max_stack = 20 -- ???
}
}
},
ascended_nova = {
id = 325020,
known = 325013,
cast = 0,
cooldown = 0,
gcd = "spell", -- actually 1s and not 1.5s...
startsCombat = true,
texture = 3528287,
buff = "boon_of_the_ascended",
bind = "boon_of_the_ascended",
handler = function ()
addStack( "boon_of_the_ascended", nil, active_enemies )
end
},
ascended_blast = {
id = 325283,
known = 15407,
cast = 0,
cooldown = 3,
hasteCD = true,
gcd = "totem", -- actually 1s and not 1.5s...
startsCombat = true,
texture = 3528286,
buff = "boon_of_the_ascended",
bind = "mind_flay",
handler = function ()
addStack( "boon_of_the_ascended", nil, 5 )
if state.spec.shadow then gain( 6, "insanity" ) end
end,
},
-- Priest - Necrolord - 324724 - unholy_nova (Unholy Nova)
unholy_nova = {
id = 324724,
cast = 0,
cooldown = 60,
gcd = "spell",
spend = 0.05,
spendType = "mana",
startsCombat = true,
texture = 3578229,
toggle = "essences",
handler = function ()
applyDebuff( "target", "unholy_transfusion" )
active_dot.unholy_transfusion = active_enemies
if legendary.pallid_command.enabled then applyBuff( "pallid_command" ) end
if soulbind.kevins_oozeling.enabled then applyBuff( "kevins_oozeling" ) end
end,
range = 15,
auras = {
unholy_transfusion = {
id = 324724,
duration = function () return conduit.festering_transfusion.enabled and 17 or 15 end,
max_stack = 1,
},
pallid_command = {
id = 356418,
duration = 20,
max_stack = 1
}
}
},
-- Priest - Night Fae - 327661 - fae_guardians (Fae Guardians)
fae_guardians = {
id = 327661,
cast = 0,
cooldown = 90,
gcd = "spell",
spend = 0.02,
spendType = "mana",
toggle = "essences",
nobuff = "direct_mask",
handler = function ()
applyBuff( "fae_guardians" )
summonPet( "wrathful_faerie" )
applyDebuff( "target", "wrathful_faerie" )
summonPet( "guardian_faerie" )
applyBuff( "guardian_faerie" )
summonPet( "benevolent_faerie" )
applyBuff( "benevolent_faerie" )
if legendary.bwonsamdis_pact.enabled then
applyBuff( "direct_mask" )
applyDebuff( "target", "haunted_mask" )
end
-- TODO: Check totem/guardian API re: faeries.
end,
bind = "direct_mask",
auras = {
fae_guardians = {
id = 327661,
duration = 20,
max_stack = 1,
},
wrathful_faerie = {
id = 342132,
duration = 20,
max_stack = 1,
},
wrathful_faerie_fermata = {
id = 345452,
duration = function () return conduit.fae_fermata.enabled and ( conduit.fae_fermata.mod * 0.001 ) or 3 end,
max_stack = 1
},
guardian_faerie = {
id = 327694,
duration = 20,
max_stack = 1,
},
guardian_faerie_fermata = {
id = 345451,
duration = function () return conduit.fae_fermata.enabled and ( conduit.fae_fermata.mod * 0.001 ) or 3 end,
max_stack = 1
},
benevolent_faerie = {
id = 327710,
duration = 20,
max_stack = 1,
},
benevolent_faerie_fermata = {
id = 345453,
duration = function () return conduit.fae_fermata.enabled and ( conduit.fae_fermata.mod * 0.001 ) or 3 end,
max_stack = 1
},
haunted_mask = {
id = 356968,
duration = 20,
max_stack = 1,
},
direct_mask = {
duration = 20,
max_stack = 1,
}
}
},
direct_mask = {
id = 356532,
cast = 0,
cooldown = 0,
gcd = "off",
buff = "direct_mask",
bind = "fae_guardians",
handler = function ()
applyDebuff( "target", "haunted_mask" )
end,
},
-- Priest - Venthyr - 323673 - mindgames (Mindgames)
mindgames = {
id = 323673,
cast = 1.5,
cooldown = 45,
gcd = "spell",
spend = 0.002,
spendType = "mana",
toggle = "essences",
handler = function ()
applyDebuff( "target", "mindgames" )
end,
auras = {
mindgames = {
id = 323673,
duration = function () return ( conduit.shattered_perceptions.enabled and 7 or 5 ) + ( legendary.shadow_word_manipulation.enabled and 3 or 0 ) end,
max_stack = 1,
},
shadow_word_manipulation = {
id = 357028,
duration = 10,
max_stack = 1,
},
},
},
} )
spec:RegisterOptions( {
enabled = true,
aoe = 3,
nameplates = false,
nameplateRange = 8,
damage = true,
damageExpiration = 6,
potion = "potion_of_spectral_intellect",
package = "Shadow",
} )
spec:RegisterSetting( "pad_void_bolt", true, {
name = "Pad |T1035040:0|t Void Bolt Cooldown",
desc = "If checked, the addon will treat |T1035040:0|t Void Bolt's cooldown as slightly shorter, to help ensure that it is recommended as frequently as possible during Voidform.",
type = "toggle",
width = "full"
} )
spec:RegisterSetting( "pad_ascended_blast", true, {
name = "Pad |T3528286:0|t Ascended Blast Cooldown",
desc = "If checked, the addon will treat |T3528286:0|t Ascended Blast's cooldown as slightly shorter, to help ensure that it is recommended as frequently as possible during Boon of the Ascended.",
type = "toggle",
width = "full"
} )
spec:RegisterSetting( "sw_death_protection", 50, {
name = "|T136149:0|t Shadow Word: Death Health Threshold",
desc = "If set above 0, the addon will not recommend |T136149:0|t Shadow Word: Death while your health percentage is below this threshold. This setting can help keep you from killing yourself.",
type = "range",
min = 0,
max = 100,
step = 0.1,
width = "full",
} )
spec:RegisterSetting( "ignore_solvent", true, {
name = "Ignore Volatile Solvent for Void Eruption",
desc = "If disabled, when you have the Volatile Solvent conduit enabled, the addon will not use Void Eruption unless you currently have a Volatile Solvent buff applied (from casting Fleshcraft).",
type = "toggle",
width = "full",
} )
spec:RegisterSetting( "stm_timer", 20, {
name = "|T254090:0|t Surrender to Madness Time",
desc = "|T254090:0|t Surrender to Madness will kill you if your targeted enemy does not die within 25 seconds. The addon is able to estimate time-to-die, but " ..
"these values are estimates and fight circumstances can change quickly. This setting allows you to reserve a little extra time, so you are less likely to cause your own death.\n\n" ..
"Custom priorities can reference |cFFFFD100settings.stm_timer|r for their decisions.",
type = "range",
min = 5,
max = 25,
step = 0.1,
width = "full",
} )
3 years ago
spec:RegisterPack( "Shadow", 20220821, [[Hekili:T3xEZTTrwI)zr1uldPLcdj1HDYkYP8r8KKnXr)I8eV)LOabbjXyqaU4qkAlv8Z((EV(Ur3aqs2zsMFtv7MXIOpF97(O7RgF17V6YLbLrx9UjJMmz0lMmE44VE0zJF(vxwE3UORUCxq4hdwd)J0GTW)9YnblZUf)57sYcwIDViRkpe(0MYYDfFZx9vRJl3uTyyy22VQiEBvsqzCwAyEWQs8Vd)QRUCrvCs53NE1c3Z9KRUmOQCtwomDXBFnmYXlxgXAEurOyrS)6lYJJkk3)dVSADf8)E9KXhb)hyS2)d7)HxVjiDDuX3S)h(Y9x)(BJc(4(R)1S4LWFKLNhLcT)2nrP7VUmiFDe8xHzvPLf7VoipA)1RYG90YHuNVipQmkf64Ym53R2z2DXVhMKva)pLzqRVloDnSGkG)D5MaygsR(yKOHfLXjj7VopcGtBHrhMSRUmjUOSaHP7OFFrqj8hVJoKIsdwKeT8QxD1LH5XLr5XbxDzE02G4uyipF)1hpAea3crGn0)SBJYNFBw(Y5WoPmUSAz0vLaG27qbNIjlItxoChakRsIMhLxTdhSH8MV)67Vh3m8MDtgEWcTRil5gaAkAMAnSkjQydDUJZ8XEN5d2F9IQvRgwqNQWYD7WQDQHr9Z4WCI3HbGdbPXL3nCz0Q4WyaCpB)1Jpvnqb5HbPrZlzN(4GDQ1GXqXzty0Y5z5lMNTc7WwSdwRO6nagXZSgXmyJueP13BcGfl8v8FLub)ptOFBoBQ3cq25frWFhwvMTAfoKpVjaxzqcc7xgSnnq)WsFc3UlopoewLvHBWb8fEhW2hnAbUijOa3TW2cr)AgfLoAxKLLsqQnrZdkczO74HCrjS0kX(lNIWGKK5S)yospWOk4aiCGAgp(abf5W4I57scUlkxn2lJl2fLmFBW64qxiLsGgWNqsaW46KhZ)J)osFZyK8T8wS)A8)pmllbWlG)1o4Fb0(aLoGfMefq8MoD)1cu09x3plF)1NmI4ZS)6xLKLHdxYk2iLTlknkFasxGCnYG)tm8P7YQaMoeBJSBIaS5D6dzm0XF9Td3F9pf8rK)sfYLHXPCvmaX)QFco7wGGEygdq2z4pGtoT(IlS3flIGfhUx)w20ZhRe4GG18O)NQ4D7qUKx)9RtP2k355rSJwa6uW6Evb9bJrbyGxSLVAEfFPrlKQYH6hQcQMH44JC0MhUeAwpaqQdcMnLbNpK(9XW)6z0)kpimA4ceippcHXq)kJX5NyBU)6b0)hYEBhG3qqRHiQWnruBZRsrqX6iblkCXpFhU2hkGbudpqb(gQOugIYkS(kBGymOxgfuUHA0G6BPZHT0loLT44KNi)bauopnE9MYTGWefhAO3sqvTMX5PiMg9LdBlZxN9PV1kJE2AIiVR1eCKiPfrLLWAOyymHFi(oSeCXl3K)kd4SdzWysaQJFtKe7qQeCkV8dFZf7V(Lx(Yly4Ya7gL4Deh8d5aOEvfqa92aaZIWJt)c4JItBMi9viiJWwh)LhlLWpSgBTvbrZxxfKVmoiTq7yEze95B5Z28v0KjAaYckzUyqLS8jSXtCjwYG5l2uh8SBgPW7uotdHXw4JC3Kvo0(izyzC4hjiutys(N2P4w9YW7cbKg(3rHaoKG2jXca3axIkDb4SNY)4dkTq))oyzrCoZYjoemU4xsRb2gMP(zE0kGjm003K9(cuUr5gKG0AV5sHaP0sHEand26Z2xMkAmKp94GY4f4CVxRvmMpe5dbexgDdyEruUaLsJZ4(RpvY7MX2I62YG8pckAKvb7WHfLG5luBR)TTb)2C(3Xz(aID18fzPvfWzsu(KxmFYUqKxL5bayoWkuqfcKRqLbEJaoj49qsljErO09F99mHAKCCCBG)iX4c0hL(XqscCa2K8Tba3P3q7AcP4IKG1vWK0ponmPAj9BSJ83WbnadW8SWIbC5OAAjWh8D4smh2MVNTZlqRpG9TPG53p5fG0ZDHdruIVUdSMj5wUuosyE2hGwHlZaeZRlQai0oHT6J(naFcAXsoKG4MNg9BWEAD4sdUXpnX2QERSNAknjTWVgA0ZrO14rnX4HPUSjC6Lj3gCxbh)bBf1i(bcCIrlncMSPcSILbaUHu6erLqSi6RDfIY6eOOgGIUCzmUia(P3DKa3tUe010e0aGgcORPmkueLNeMsNf5XRG)5cGw82GyM8YG6Nn9DRuu4geGwWSstqaZfCk3ZZXTSuBcL9ownqYFUMwCghO4wDotXVd5hVdSqa(eH(mZyYAfhstvkdouCEECDSIxYTnUMKcYCLfzjLMQW1TDahYwhgWGn14jEYoY0PX2M8zy7eUy8B30RGVYmoAdihIXbtioJjN67uy9SUGBme77eP6yhXyKMvsdadXGBdZLVFOlpdO0MUxRys96O62nEWEMuMw)UmHh0L5KJI7DENsKtK(1JTTswkyxiEbnqEn6fcJtkGDAyShXqSJNlzRV9x)oXcuO6CvrWAnE2VMJIwyXrWfwLHronqH31JMNgvTtIUMpTjyUpxk0cm)nzKDim9jQd2LmLbvg4SGJtr6HFLVcjnJkJcwYjlivqCCkHccyqpPegM02nOhZIsrgpUT4PVuLsL2AAMEdSXmntL4dWD2MX5IjBlrlm4uFmz5UghAgdnpUbWALWPX17y74lC602BypZvsJwzZOc9zMBZmkFfJv2RFJ2H)sgssAeUqWtFMW7A4lhXpzrwJrC)nNevuq(HovNjk5QfyNFQGYomlDzvC5aJJ(MSyTpnChk75WLXffG2fPLZJc3Kfvyt72e34woG6WjjbX9zaTdTxBXWgURe3efKuUz4UWsAppzulCdiyYajw1tJtuB6oyBFsnDW)gdLWnDkcgoIfeoafYc0LisZt2eCtKBDlvRpgwJURfXUR52rHVviZkg7Z6(IkKla0FGFW8TbltbS12mwNozqnSW(qRC1rJj3BKBJtGKywz7(FInVmcVafqIf8geuToJzjIaufOufgWd3tEvKTr95kcDEEnVbLSyWOonxPyx9TMHN44)UEKHCONO8ZK6Y5r3mhvBFSQfcgDm33JUonPQa7xqyzRi)hlO1L7HBGTayvtsCR400Eu6d3ZibbCI(YBrp(KTA(QGstnICscyfSVS0K70nnN4qI2MtShfeMc(MQt)BzmDPZBdtrblystJsyN3(dQsxLQ8iDSKxxRiDRK)JctdvzeW0U5Pz()h(M3iymCbSswainFePXUOiizlAmPqwKouMucbT1CrucY4AYO)dviiyWBzKjcZ2IwoUii8JgYPuSu3PM357WP1KLQtAllokaZ(5i3KzeIydEUhqk4E)rAvjfIkFofGpcH5bfn6(KxJnqPfGgytkupyjQ)tCkaqGJAtyragclYB8yRgIHhcn1EeT28hVUhjAyp32V6A)P7WssjMS0Iku4ITtQi3AXaaV8N)2HWN(538ZOnfPRIjnEjOb(FjXyUSMKPVtEeCoZCqbFWuGZL0KwkNuljIml4H)0fZAqf8OCmgGZJxbsKacUIztpX433UnAzmMJdxIm33qrZySlptJNk22R5d292KG76oS7Y3tBGI4L4ozffLWAHYWLFhCsLCGF)r4pkDUCa0QkaplpI5hiUNsMXC7g6AwFq3Eh4gp7bcZb9zUJG5(SxZRR70ohELLhZQPFUHp4be4llZ2X0ApweE4tyAmTLXNtOvUFZSTmEJMx6dm3l73FGzeh47c3edwA)JXPFCOhs9z)1tjtmfSOHpeVTAld35uDrKPvBxqQ8TsU0Hn5ltkYocbg81eOEbsOP5IXQ0YyGBFaYYxULPnbsNQuReLolCRaTVk03x7y7le6R7MZGBcIti0Ww1MsJh52SBIWK4qWN00xHJgEAxuBHzi0eDDw2gxeLFNsq)HcvnMxpMj69Bh7KAEcEqP37(nPPWFLoGgiI79tWUJbMgq3ToXTrZDWa7(q4wRrMqvVgtBMMlnQzTHBmQl4N00d5en(fciGJ4BjvVIVP9SOnzKIHC6MsMdIhz70bBuLEDjMzd0u(VkDvvoM(fZrUJOPm1La)lcos)kF7GAit4EGY
4 years ago
end