-- DeathKnightBlood.lua
-- June 2018
local addon , ns = ...
local Hekili = _G [ addon ]
local class = Hekili.Class
local state = Hekili.State
local PTR = ns.PTR
local FindUnitDebuffByID = ns.FindUnitDebuffByID
-- Conduits
-- [-] Withering Plague
-- [x] Debilitating Malady
-- [-] Kyrian: Proliferation
-- [x] Venthyr: Impenetrable Gloom
-- [-] Necrolord: Brutal Grasp
-- [-] Night Fae: Withering Ground
-- Endurance
-- [x] hardened_bones
-- [-] insatiable_appetite
-- [x] reinforced_shell
-- Finesse
-- [x] chilled_resilience
-- [x] fleeting_wind
-- [x] spirit_drain
-- [x] unending_grip
if UnitClassBase ( " player " ) == " DEATHKNIGHT " then
local spec = Hekili : NewSpecialization ( 250 )
spec : RegisterResource ( Enum.PowerType . Runes , {
rune_regen = {
last = function ( )
return state.query_time
end ,
interval = function ( time , val )
local r = state.runes
if val == 6 then return - 1 end
return r.expiry [ val + 1 ] - time
end ,
stop = function ( x )
return x == 6
end ,
value = 1
} ,
} , setmetatable ( {
expiry = { 0 , 0 , 0 , 0 , 0 , 0 } ,
cooldown = 10 ,
regen = 0 ,
max = 6 ,
forecast = { } ,
fcount = 0 ,
times = { } ,
values = { } ,
resource = " runes " ,
reset = function ( )
local t = state.runes
for i = 1 , 6 do
local start , duration , ready = GetRuneCooldown ( i )
start = start or 0
duration = duration or ( 10 * state.haste )
t.expiry [ i ] = ready and 0 or start + duration
t.cooldown = duration
end
table.sort ( t.expiry )
t.actual = nil
end ,
gain = function ( amount )
local t = state.runes
for i = 1 , amount do
t.expiry [ 7 - i ] = 0
end
table.sort ( t.expiry )
t.actual = nil
end ,
spend = function ( amount )
local t = state.runes
for i = 1 , amount do
t.expiry [ 1 ] = ( t.expiry [ 4 ] > 0 and t.expiry [ 4 ] or state.query_time ) + t.cooldown
table.sort ( t.expiry )
end
-- TODO: Rampant Transference
state.gain ( amount * 10 * ( state.buff . rune_of_hysteria.up and 1.2 or 1 ) , " runic_power " )
if state.talent . rune_strike.enabled then state.gainChargeTime ( " rune_strike " , amount ) end
if state.buff . dancing_rune_weapon.up and state.azerite . eternal_rune_weapon.enabled then
if state.buff . dancing_rune_weapon.expires - state.buff . dancing_rune_weapon.applied < state.buff . dancing_rune_weapon.duration + 5 then
state.buff . eternal_rune_weapon.expires = min ( state.buff . dancing_rune_weapon.applied + state.buff . dancing_rune_weapon.duration + 5 , state.buff . dancing_rune_weapon.expires + ( 0.5 * amount ) )
end
end
t.actual = nil
end ,
timeTo = function ( x )
return state : TimeToResource ( state.runes , x )
end ,
} , {
__index = function ( t , k , v )
if k == " actual " then
local amount = 0
for i = 1 , 6 do
if t.expiry [ i ] <= state.query_time then
amount = amount + 1
end
end
return amount
elseif k == " current " then
-- If this is a modeled resource, use our lookup system.
if t.forecast and t.fcount > 0 then
local q = state.query_time
local index , slice
if t.values [ q ] then return t.values [ q ] end
for i = 1 , t.fcount do
local v = t.forecast [ i ]
if v.t <= q then
index = i
slice = v
else
break
end
end
-- We have a slice.
if index and slice then
t.values [ q ] = max ( 0 , min ( t.max , slice.v ) )
return t.values [ q ]
end
end
return t.actual
elseif k == " deficit " then
return t.max - t.current
elseif k == " time_to_next " then
return t [ " time_to_ " .. t.current + 1 ]
elseif k == " time_to_max " then
return t.current == 6 and 0 or max ( 0 , t.expiry [ 6 ] - state.query_time )
elseif k == " add " then
return t.gain
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 . RunicPower , {
swarming_mist = {
aura = " swarming_mist " ,
last = function ( )
local app = state.buff . swarming_mist.applied
local t = state.query_time
return app + floor ( ( t - app ) / class.auras . swarming_mist.tick_time ) * class.auras . swarming_mist.tick_time
end ,
interval = function ( ) return class.auras . swarming_mist.tick_time end ,
value = function ( ) return min ( 15 , state.true_active_enemies * 3 ) end ,
} ,
} )
local spendHook = function ( amt , resource )
if amt > 0 and resource == " runic_power " and talent.red_thirst . enabled then
cooldown.vampiric_blood . expires = max ( 0 , cooldown.vampiric_blood . expires - amt / 10 )
elseif resource == " rune " and amt > 0 and active_dot.shackle_the_unworthy > 0 then
reduceCooldown ( " shackle_the_unworthy " , 4 * amt )
end
end
spec : RegisterHook ( " spend " , spendHook )
-- Talents
spec : RegisterTalents ( {
heartbreaker = 19165 , -- 221536
blooddrinker = 19166 , -- 206931
tombstone = 23454 , -- 219809
rapid_decomposition = 19218 , -- 194662
hemostasis = 19219 , -- 273946
consumption = 19220 , -- 274156
foul_bulwark = 19221 , -- 206974
relish_in_blood = 22134 , -- 317610
blood_tap = 22135 , -- 221699
will_of_the_necropolis = 22013 , -- 206967
antimagic_barrier = 22014 , -- 205727
mark_of_blood = 22015 , -- 206940
grip_of_the_dead = 19227 , -- 273952
tightening_grasp = 19226 , -- 206970
wraith_walk = 19228 , -- 212552
voracious = 19230 , -- 273953
death_pact = 19231 , -- 48743
bloodworms = 19232 , -- 195679
purgatory = 21207 , -- 114556
red_thirst = 21208 , -- 205723
bonestorm = 21209 , -- 194844
} )
-- PvP Talents
spec : RegisterPvpTalents ( {
blood_for_blood = 607 , -- 356456
dark_simulacrum = 3511 , -- 77606
death_chain = 609 , -- 203173
deaths_echo = 5426 , -- 356367
decomposing_aura = 3441 , -- 199720
dome_of_ancient_shadow = 5368 , -- 328718
last_dance = 608 , -- 233412
murderous_intent = 841 , -- 207018
rot_and_wither = 204 , -- 202727
spellwarden = 5425 , -- 356332
strangulate = 206 , -- 47476
walking_dead = 205 , -- 202731
} )
-- Auras
spec : RegisterAuras ( {
abomination_limb = {
id = 315443 ,
duration = function ( ) return legendary.abominations_frenzy . enabled and 16 or 12 end ,
max_stack = 1 ,
} ,
antimagic_shell = {
id = 48707 ,
duration = function ( ) return ( legendary.deaths_embrace . enabled and 2 or 1 ) * ( ( azerite.runic_barrier . enabled and 1 or 0 ) + ( talent.antimagic_barrier . enabled and 7 or 5 ) ) + ( conduit.reinforced_shell . mod * 0.001 ) end ,
max_stack = 1 ,
} ,
antimagic_zone = {
id = 145629 ,
duration = 8 ,
max_stack = 1 ,
} ,
asphyxiate = {
id = 221562 ,
duration = 5 ,
max_stack = 1 ,
} ,
blood_plague = {
id = 55078 ,
duration = 24 ,
type = " Disease " ,
max_stack = 1 ,
} ,
blood_shield = {
id = 77535 ,
duration = 10 ,
max_stack = 1 ,
} ,
blooddrinker = {
id = 206931 ,
duration = 3 ,
max_stack = 1 ,
} ,
bone_shield = {
id = 195181 ,
duration = 30 ,
max_stack = 10 ,
} ,
bonestorm = {
id = 194844 ,
duration = 10 ,
max_stack = 1 ,
} ,
control_undead = {
id = 111673 ,
duration = 300 ,
max_stack = 1
} ,
crimson_scourge = {
id = 81141 ,
duration = 15 ,
max_stack = 1 ,
} ,
dark_command = {
id = 56222 ,
duration = 3 ,
max_stack = 1 ,
} ,
dancing_rune_weapon = {
id = 81256 ,
duration = function ( ) return pvptalent.last_dance . enabled and 6 or 8 end ,
max_stack = 1 ,
} ,
death_and_decay = {
id = 188290 ,
duration = 10 ,
max_stack = 1 ,
} ,
death_grip = {
id = 51399 ,
duration = 3 ,
} ,
deaths_advance = {
id = 48265 ,
duration = 8 ,
max_stack = 1 ,
} ,
gnaw = {
id = 91800 ,
duration = 1 ,
max_stack = 1 ,
} ,
grip_of_the_dead = {
id = 273977 ,
duration = 3600 ,
max_stack = 1 ,
} ,
--[[ ?? grip_of_the_dead = {
id = 273984 ,
duration = 10 ,
max_stack = 10 ,
} , ] ]
heart_strike = {
id = 206930 ,
duration = 8 ,
max_stack = 1 ,
} ,
hemostasis = {
id = 273947 ,
duration = 15 ,
max_stack = 5 ,
copy = " haemostasis "
} ,
icebound_fortitude = {
id = 48792 ,
duration = 8 ,
max_stack = 1 ,
} ,
lichborne = {
id = 49039 ,
duration = 10 ,
max_stack = 1 ,
} ,
mark_of_blood = {
id = 206940 ,
duration = 15 ,
type = " Magic " ,
max_stack = 1 ,
} ,
on_a_pale_horse = {
id = 51986 ,
} ,
ossuary = {
id = 219788 ,
duration = 3600 ,
max_stack = 1 ,
} ,
path_of_frost = {
id = 3714 ,
duration = 600 ,
max_stack = 1 ,
} ,
perdition = {
id = 123981 ,
duration = 240 ,
max_stack = 1 ,
} ,
rune_of_hysteria = {
id = 326918 ,
duration = 8 ,
max_stack = 1 ,
} ,
rune_tap = {
id = 194679 ,
duration = 4 ,
max_stack = 1 ,
} ,
shackle_the_unworthy = {
id = 312202 ,
duration = 14 ,
max_stack = 1 ,
} ,
shroud_of_purgatory = {
id = 116888 ,
duration = 3 ,
max_stack = 1 ,
} ,
strangulate = {
id = 47476 ,
duration = 5 ,
max_stack = 1 ,
} ,
swarming_mist = { -- Venthyr
id = 311648 ,
duration = 8 ,
tick_time = 1 ,
max_stack = 1 ,
} ,
tombstone = {
id = 219809 ,
duration = 8 ,
max_stack = 1 ,
} ,
unholy_strength = {
id = 53365 ,
duration = 15 ,
max_stack = 1 ,
} ,
vampiric_blood = {
id = 55233 ,
duration = function ( ) return ( level > 55 and 12 or 10 ) + ( legendary.vampiric_aura . enabled and 3 or 0 ) end ,
max_stack = 1 ,
} ,
veteran_of_the_third_war = {
id = 48263 ,
} ,
voracious = {
id = 274009 ,
duration = 6 ,
max_stack = 1 ,
} ,
wraith_walk = {
id = 212552 ,
duration = 4 ,
type = " Magic " ,
max_stack = 1 ,
} ,
-- Azerite Powers
bloody_runeblade = {
id = 289349 ,
duration = 5 ,
max_stack = 1
} ,
bones_of_the_damned = {
id = 279503 ,
duration = 30 ,
max_stack = 1 ,
} ,
cold_hearted = {
id = 288426 ,
duration = 8 ,
max_stack = 1
} ,
deep_cuts = {
id = 272685 ,
duration = 15 ,
max_stack = 1 ,
} ,
eternal_rune_weapon = {
id = 278543 ,
duration = 5 ,
max_stack = 1 ,
} ,
march_of_the_damned = {
id = 280149 ,
duration = 15 ,
max_stack = 1 ,
} ,
-- PvP Talents
blood_for_blood = {
id = 233411 ,
duration = 12 ,
max_stack = 1 ,
} ,
dark_simulacrum = {
id = 77606 ,
duration = 12 ,
max_stack = 1 ,
} ,
death_chain = {
id = 203173 ,
duration = 10 ,
max_stack = 1
} ,
decomposing_aura = {
id = 228581 ,
duration = 3600 ,
max_stack = 1 ,
} ,
focused_assault = {
id = 206891 ,
duration = 6 ,
max_stack = 1 ,
} ,
heartstop_aura = {
id = 228579 ,
duration = 3600 ,
max_stack = 1 ,
} ,
-- Legendaries
abominations_frenzy = {
id = 353546 ,
duration = 12 ,
max_stack = 1 ,
} ,
-- TODO: Model +/- rune regen when applied/removed.
crimson_rune_weapon = {
id = 334526 ,
duration = 10 ,
max_stack = 1
} ,
final_sentence = {
id = 353823 ,
duration = 18 ,
max_stack = 5 ,
} ,
grip_of_the_everlasting = {
id = 334722 ,
duration = 3 ,
max_stack = 1
}
} )
-- Tier 28
spec : RegisterGear ( " tier28 " , 188868 , 188867 , 188866 , 188864 , 188863 )
spec : RegisterSetBonuses ( " tier28_2pc " , 364399 , " tier28_4pc " , 363590 )
-- 2-Set - Endless Rune Waltz Heart Strike increases your Strength by 1% andWhile your Dancing Rune Weapon is active Heart Strike extends the duration of Dancing Rune Weapon by 0.5 seconds and increases your Strength by 1%, persisting for 10 seconds after Dancing Rune Weapon ends.
-- 4-Set - Endless Rune Waltz - Parrying an attack causes your weaponWhen you take damage, you have a chance equal to 100% of your Parry chance to lash out, Heart Striking your attacker. Dancing Rune Weapon now summons 2 Rune Weapons.
spec : RegisterAuras ( {
endless_rune_waltz = {
id = 366008 ,
duration = 30 ,
max_stack = 1
}
} )
spec : RegisterGear ( " tier19 " , 138355 , 138361 , 138364 , 138349 , 138352 , 138358 )
spec : RegisterGear ( " tier20 " , 147124 , 147126 , 147122 , 147121 , 147123 , 147125 )
spec : RegisterAura ( " gravewarden " , {
id = 242010 ,
duration = 10 ,
max_stack = 0
} )
spec : RegisterGear ( " tier21 " , 152115 , 152117 , 152113 , 152112 , 152114 , 152116 )
spec : RegisterGear ( " acherus_drapes " , 132376 )
spec : RegisterGear ( " cold_heart " , 151796 ) -- chilled_heart stacks NYI
spec : RegisterGear ( " consorts_cold_core " , 144293 )
spec : RegisterGear ( " death_march " , 144280 )
-- spec:RegisterGear( "death_screamers", 151797 )
spec : RegisterGear ( " draugr_girdle_of_the_everlasting_king " , 132441 )
spec : RegisterGear ( " koltiras_newfound_will " , 132366 )
spec : RegisterGear ( " lanathels_lament " , 133974 )
spec : RegisterGear ( " perseverance_of_the_ebon_martyr " , 132459 )
spec : RegisterGear ( " rethus_incessant_courage " , 146667 )
spec : RegisterGear ( " seal_of_necrofantasia " , 137223 )
spec : RegisterGear ( " service_of_gorefiend " , 132367 )
spec : RegisterGear ( " shackles_of_bryndaor " , 132365 ) -- NYI (Death Strike heals refund RP...)
spec : RegisterGear ( " skullflowers_haemostasis " , 144281 )
spec : RegisterAura ( " haemostasis " , {
id = 235559 ,
duration = 3600 ,
max_stack = 5
} )
spec : RegisterGear ( " soul_of_the_deathlord " , 151740 )
spec : RegisterGear ( " soulflayers_corruption " , 151795 )
spec : RegisterGear ( " the_instructors_fourth_lesson " , 132448 )
spec : RegisterGear ( " toravons_whiteout_bindings " , 132458 )
spec : RegisterGear ( " uvanimor_the_unbeautiful " , 137037 )
spec : RegisterTotem ( " ghoul " , 1100170 ) -- Texture ID
local any_dnd_set = false
spec : RegisterHook ( " reset_precast " , function ( )
if UnitExists ( " pet " ) then
for i = 1 , 40 do
local expires , _ , _ , _ , id = select ( 6 , UnitDebuff ( " pet " , i ) )
if not expires then break end
if id == 111673 then
summonPet ( " controlled_undead " , expires - now )
break
end
end
end
if state : IsKnown ( " deaths_due " ) then
class.abilities . any_dnd = class.abilities . deaths_due
cooldown.any_dnd = cooldown.deaths_due
setCooldown ( " death_and_decay " , cooldown.deaths_due . remains )
elseif state : IsKnown ( " defile " ) then
class.abilities . any_dnd = class.abilities . defile
cooldown.any_dnd = cooldown.defile
setCooldown ( " death_and_decay " , cooldown.defile . remains )
else
class.abilities . any_dnd = class.abilities . death_and_decay
cooldown.any_dnd = cooldown.death_and_decay
end
if not any_dnd_set then
class.abilityList . any_dnd = " |T136144:0|t |cff00ccff[Any]|r " .. class.abilities . death_and_decay.name
any_dnd_set = true
end
-- Reset CDs on any Rune abilities that do not have an actual cooldown.
for action in pairs ( class.abilityList ) do
local data = class.abilities [ action ]
if data.cooldown == 0 and data.spendType == " runes " then
setCooldown ( action , 0 )
end
end
if set_bonus.tier28_2pc > 0 and buff.dancing_rune_weapon . up then
if buff.endless_rune_waltz . up then buff.endless_rune_waltz . expires = buff.dancing_rune_weapon . expires + 10
else applyBuff ( " endless_rune_waltz " , buff.dancing_rune_weapon . remains + 10 ) end
end
end )
spec : RegisterStateExpr ( " save_blood_shield " , function ( )
return settings.save_blood_shield
end )
-- Abilities
spec : RegisterAbilities ( {
antimagic_shell = {
id = 48707 ,
cast = 0 ,
cooldown = function ( ) return talent.antimagic_barrier . enabled and 40 or 60 end ,
gcd = " off " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 136120 ,
handler = function ( )
applyBuff ( " antimagic_shell " )
end ,
} ,
antimagic_zone = {
id = 51052 ,
cast = 0 ,
cooldown = 180 ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 237510 ,
handler = function ( )
applyBuff ( " antimagic_zone " )
end ,
} ,
asphyxiate = {
id = 221562 ,
cast = 0 ,
cooldown = 45 ,
gcd = " spell " ,
startsCombat = true ,
texture = 538558 ,
toggle = " interrupts " ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
interrupt ( )
applyDebuff ( " target " , " asphyxiate " )
end ,
} ,
blood_boil = {
id = 50842 ,
cast = 0 ,
charges = 2 ,
cooldown = 7.5 ,
recharge = 7.5 ,
hasteCD = true ,
gcd = " spell " ,
startsCombat = true ,
texture = 237513 ,
handler = function ( )
applyDebuff ( " target " , " blood_plague " )
active_dot.blood_plague = active_enemies
if talent.hemostasis . enabled then
applyBuff ( " hemostasis " , 15 , min ( 5 , active_enemies ) )
end
if legendary.superstrain . enabled then
applyDebuff ( " target " , " frost_fever " )
active_dot.frost_fever = active_enemies
applyDebuff ( " target " , " virulent_plague " )
active_dot.virulent_plague = active_enemies
end
if conduit.debilitating_malady . enabled then
addStack ( " debilitating_malady " , nil , 1 )
end
end ,
auras = {
-- Conduit
debilitating_malady = {
id = 338523 ,
duration = 6 ,
max_stack = 3
}
}
} ,
blood_tap = {
id = 221699 ,
cast = 0 ,
charges = 2 ,
cooldown = 60 ,
recharge = 60 ,
gcd = " off " ,
spend = - 1 ,
spendType = " runes " ,
startsCombat = false ,
talent = " blood_tap " ,
handler = function ( )
gain ( 1 , " runes " )
end
} ,
blooddrinker = {
id = 206931 ,
cast = 3 ,
cooldown = 30 ,
channeled = true ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 838812 ,
talent = " blooddrinker " ,
start = function ( )
applyDebuff ( " target " , " blooddrinker " )
end ,
} ,
bonestorm = {
id = 194844 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
spend = 0 ,
spendType = " runic_power " ,
startsCombat = true ,
texture = 342917 ,
talent = " bonestorm " ,
handler = function ( )
local cost = min ( runic_power.current , 100 )
spend ( cost , " runic_power " )
applyBuff ( " bonestorm " , cost / 10 )
end ,
} ,
chains_of_ice = {
id = 45524 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 135834 ,
handler = function ( )
applyDebuff ( " target " , " chains_of_ice " )
end ,
} ,
consumption = {
id = 274156 ,
cast = 0 ,
cooldown = 45 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1121487 ,
talent = " consumption " ,
handler = function ( )
end ,
} ,
control_undead = {
id = 111673 ,
cast = 1.5 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 237273 ,
usable = function ( ) return target.is_undead , " requires undead target " end ,
handler = function ( )
summonPet ( " controlled_undead " )
end ,
} ,
dancing_rune_weapon = {
id = 49028 ,
cast = 0 ,
cooldown = function ( ) return pvptalent.last_dance . enabled and 60 or 120 end ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = false ,
texture = 135277 ,
handler = function ( )
applyBuff ( " dancing_rune_weapon " )
if azerite.eternal_rune_weapon . enabled then applyBuff ( " dancing_rune_weapon " ) end
if legendary.crimson_rune_weapon . enabled then addStack ( " bone_shield " , nil , 5 ) end
end ,
} ,
dark_command = {
id = 56222 ,
cast = 0 ,
cooldown = 8 ,
gcd = " off " ,
startsCombat = true ,
texture = 136088 ,
nopvptalent = " murderous_intent " ,
handler = function ( )
applyDebuff ( " target " , " dark_command " )
end ,
} ,
dark_simulacrum = {
id = 77606 ,
cast = 0 ,
cooldown = 20 ,
gcd = " spell " ,
spend = 0 ,
spendType = " runic_power " ,
startsCombat = true ,
texture = 135888 ,
pvptalent = " dark_simulacrum " ,
usable = function ( )
if not target.is_player then return false , " target is not a player " end
return true
end ,
handler = function ( )
applyDebuff ( " target " , " dark_simulacrum " )
end ,
} ,
death_and_decay = {
id = 43265 ,
cast = 0 ,
cooldown = 15 ,
recharge = function ( )
if pvptalent.deaths_echo . enabled then return end
return 15
end ,
charges = function ( )
if pvptalent.deaths_echo . enabled then return end
return 2
end ,
gcd = " spell " ,
spend = function ( ) return buff.crimson_scourge . up and 0 or 1 end ,
spendType = " runes " ,
startsCombat = true ,
texture = 136144 ,
noOverride = 324128 ,
handler = function ( )
removeBuff ( " crimson_scourge " )
if legendary.phearomones . enabled and buff.death_and_decay . down then
stat.haste = stat.haste + ( state.spec . blood and 0.1 or 0.15 )
end
applyBuff ( " death_and_decay " )
end ,
} ,
death_chain = {
id = 203173 ,
cast = 0 ,
cooldown = 30 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1390941 ,
pvptalent = " death_chain " ,
handler = function ( )
applyDebuff ( " target " , " death_chain " )
active_dot.death_chain = min ( 3 , active_enemies )
end ,
} ,
death_grip = {
id = 49576 ,
cast = 0 ,
charges = function ( )
if not pvptalent.deaths_echo . enabled then return end
return 2
end ,
cooldown = 15 ,
recharge = function ( )
if not pvptalent.deaths_echo . enabled then return end
return 15
end ,
gcd = " spell " ,
startsCombat = true ,
texture = 237532 ,
handler = function ( )
applyDebuff ( " target " , " death_grip " )
setDistance ( 5 )
if legendary.grip_of_the_everlasting . enabled and buff.grip_of_the_everlasting . down then
applyBuff ( " grip_of_the_everlasting " )
else
removeBuff ( " grip_of_the_everlasting " )
end
if conduit.unending_grip . enabled then applyDebuff ( " target " , " unending_grip " ) end
end ,
auras = {
unending_grip = {
id = 338311 ,
duration = 5 ,
max_stack = 1
}
}
} ,
death_strike = {
id = 49998 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = function ( ) return ( level > 57 and buff.bone_shield . stack >= 5 ) and 40 or 45 end ,
spendType = " runic_power " ,
startsCombat = true ,
texture = 237517 ,
handler = function ( )
applyBuff ( " blood_shield " ) -- gain absorb shield
gain ( 0.075 * health.max * ( 1.2 * buff.haemostasis . stack ) * ( 1.08 * buff.hemostasis . stack ) , " health " )
removeBuff ( " haemostasis " )
removeBuff ( " hemostasis " )
-- TODO: Calculate real health gain from Death Strike to trigger Bryndaor's Might legendary.
if talent.voracious . enabled then applyBuff ( " voracious " ) end
end ,
} ,
deaths_advance = {
id = 48265 ,
cast = 0 ,
cooldown = function ( ) return azerite.march_of_the_damned . enabled and 40 or 45 end ,
recharge = function ( )
if pvptalent.deaths_echo . enabled then return end
return azerite.march_of_the_damned . enabled and 40 or 45
end ,
charges = function ( )
if pvptalent.deaths_echo . enabled then return end
return 2
end ,
gcd = " spell " ,
startsCombat = false ,
texture = 237561 ,
handler = function ( )
applyBuff ( " deaths_advance " )
if conduit.fleeting_wind . enabled then applyBuff ( " fleeting_wind " ) end
end ,
auras = {
-- Conduit
fleeting_wind = {
id = 338093 ,
duration = 3 ,
max_stack = 1
}
}
} ,
deaths_caress = {
id = 195292 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 1376743 ,
handler = function ( )
applyDebuff ( " target " , " blood_plague " )
end ,
} ,
gorefiends_grasp = {
id = 108199 ,
cast = 0 ,
cooldown = function ( ) return talent.tightening_grasp . enabled and 90 or 120 end ,
gcd = " spell " ,
-- toggle = "cooldowns",
startsCombat = false ,
texture = 538767 ,
handler = function ( )
end ,
} ,
heart_strike = {
id = 206930 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 135675 ,
max_targets = function ( ) return buff.death_and_decay . up and 5 or 2 end ,
handler = function ( )
applyDebuff ( " target " , " heart_strike " )
local targets = min ( active_enemies , buff.death_and_decay . up and 5 or 2 )
active_dot.heart_strike = targets
if pvptalent.blood_for_blood . enabled then
spend ( 0.03 * health.max , " health " )
end
if azerite.deep_cuts . enabled then applyDebuff ( " target " , " deep_cuts " ) end
if legendary.gorefiends_domination . enabled and cooldown.vampiric_blood . remains > 0 then
gainChargeTime ( " vampiric_blood " , 2 )
end
if buff.dancing_rune_weapon . up and set_bonus.tier28_2pc > 0 then
buff.dancing_rune_weapon . expires = buff.dancing_rune_weapon . expires + ( set_bonus.tier28_4pc > 0 and 0.5 or 1 )
addStack ( " endless_rune_waltz " , nil , 1 )
buff.endless_rune_waltz . expires = buff.dancing_rune_weapon . expires + 10
end
end ,
} ,
icebound_fortitude = {
id = 48792 ,
cast = 0 ,
cooldown = function ( ) return 180 - ( azerite.cold_hearted . enabled and 15 or 0 ) + ( conduit.chilled_resilience . mod * 0.001 ) end ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 237525 ,
handler = function ( )
applyBuff ( " icebound_fortitude " )
end ,
} ,
lichborne = {
id = 49039 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 136187 ,
handler = function ( )
applyBuff ( " lichborne " )
if conduit.hardened_bones . enabled then applyBuff ( " hardened_bones " ) end
end ,
auras = {
-- Conduit
hardened_bones = {
id = 337973 ,
duration = 10 ,
max_stack = 1
}
}
} ,
mark_of_blood = {
id = 206940 ,
cast = 0 ,
cooldown = 6 ,
gcd = " spell " ,
startsCombat = true ,
texture = 132205 ,
talent = " mark_of_blood " ,
handler = function ( )
applyDebuff ( " target " , " mark_of_blood " )
end ,
} ,
marrowrend = {
id = 195182 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 2 ,
spendType = " runes " ,
startsCombat = true ,
texture = 1376745 ,
handler = function ( )
applyBuff ( " bone_shield " , 30 , buff.bone_shield . stack + ( buff.dancing_rune_weapon . up and ( set_bonus.tier28_4pc > 0 and 9 or 6 ) or 3 ) )
if azerite.bones_of_the_damned . enabled then applyBuff ( " bones_of_the_damned " ) end
end ,
} ,
mind_freeze = {
id = 47528 ,
cast = 0 ,
cooldown = 15 ,
gcd = " spell " ,
startsCombat = true ,
texture = 237527 ,
toggle = " interrupts " ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
if conduit.spirit_drain . enabled then gain ( conduit.spirit_drain . mod * 0.1 , " runic_power " ) end
interrupt ( )
end ,
} ,
murderous_intent = {
id = 207018 ,
cast = 0 ,
cooldown = 20 ,
gcd = " spell " ,
startsCombat = true ,
texture = 136088 ,
pvptalent = " murderous_intent " ,
handler = function ( )
applyDebuff ( " target " , " focused_assault " )
end ,
} ,
path_of_frost = {
id = 3714 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 237528 ,
handler = function ( )
applyBuff ( " path_of_frost " )
end ,
} ,
raise_dead = {
id = 46585 ,
cast = 0 ,
cooldown = 120 ,
gcd = " off " ,
startsCombat = false ,
toggle = " cooldowns " ,
usable = function ( ) return not pet.alive , " cannot have an active pet " end ,
handler = function ( )
summonPet ( " ghoul " )
end ,
} ,
rune_tap = {
id = 194679 ,
cast = 0 ,
charges = function ( ) return level > 43 and 2 or nil end ,
cooldown = 25 ,
recharge = function ( ) return level > 43 and 25 or nil end ,
gcd = " off " ,
toggle = " defensives " ,
spend = 1 ,
spendType = " runes " ,
startsCombat = true ,
texture = 237529 ,
handler = function ( )
applyBuff ( " rune_tap " )
end ,
} ,
--[[ runeforging = {
id = 53428 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = true ,
texture = 237523 ,
handler = function ( )
end ,
} , ] ]
sacrificial_pact = {
id = 327574 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
spend = 20 ,
spendType = " runic_power " ,
toggle = " defensives " ,
startsCombat = true ,
texture = 136133 ,
usable = function ( ) return pet.ghoul . alive , " requires an undead pet " end ,
handler = function ( )
gain ( 0.25 * health.max , " health " )
pet.ghoul . expires = query_time - 0.01
end ,
} ,
strangulate = {
id = 47476 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
spend = 0 ,
spendType = " runes " ,
toggle = " interrupts " ,
pvptalent = " strangulate " ,
interrupt = true ,
startsCombat = true ,
texture = 136214 ,
debuff = " casting " ,
readyTime = state.timeToInterrupt ,
handler = function ( )
interrupt ( )
applyDebuff ( " target " , " strangulate " )
end ,
} ,
tombstone = {
id = 219809 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
toggle = " cooldowns " ,
startsCombat = true ,
texture = 132151 ,
talent = " tombstone " ,
buff = " bone_shield " ,
handler = function ( )
local bs = min ( 5 , buff.bone_shield . stack )
removeStack ( " bone_shield " , bs )
gain ( 6 * bs , " runic_power " )
-- This is the only predictable Bone Shield consumption that I have noted.
if cooldown.dancing_rune_weapon . remains > 0 then
cooldown.dancing_rune_weapon . expires = cooldown.dancing_rune_weapon . expires - ( 3 * bs )
end
if cooldown.blood_tap . charges_fractional < cooldown.blood_tap . max_charges then
gainChargeTime ( " blood_tap " , 2 * bs )
end
if set_bonus.tier21_2pc == 1 then
cooldown.dancing_rune_weapon . expires = max ( 0 , cooldown.dancing_rune_weapon . expires - ( 3 * bs ) )
end
applyBuff ( " tombstone " )
end ,
} ,
vampiric_blood = {
id = 55233 ,
cast = 0 ,
cooldown = function ( ) return 90 * ( essence.vision_of_perfection . enabled and 0.87 or 1 ) end ,
gcd = " spell " ,
toggle = " defensives " ,
startsCombat = false ,
texture = 136168 ,
handler = function ( )
applyBuff ( " vampiric_blood " )
if legendary.gorefiends_domination . enabled then gain ( 45 , " runic_power " ) end
end ,
} ,
--[[ wartime_ability = {
id = 264739 ,
cast = 0 ,
cooldown = 0 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1518639 ,
handler = function ( )
end ,
} , ] ]
wraith_walk = {
id = 212552 ,
cast = 4 ,
fixedCast = true ,
channeled = true ,
cooldown = 60 ,
gcd = " spell " ,
startsCombat = true ,
texture = 1100041 ,
start = function ( )
applyBuff ( " wraith_walk " )
end ,
} ,
-- Death Knight - Kyrian - 312202 - shackle_the_unworthy (Shackle the Unworthy)
shackle_the_unworthy = {
id = 312202 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
startsCombat = true ,
texture = 3565442 ,
toggle = " essences " ,
handler = function ( )
applyDebuff ( " target " , " shackle_the_unworthy " )
end ,
auras = {
final_sentence = {
id = 353823 ,
duration = 10 ,
max_stack = 5 ,
} ,
}
} ,
-- Death Knight - Necrolord - 315443 - abomination_limb (Abomination Limb)
abomination_limb = {
id = 315443 ,
cast = 0 ,
cooldown = 120 ,
gcd = " spell " ,
startsCombat = true ,
texture = 3578196 ,
toggle = " essences " ,
handler = function ( )
applyBuff ( " abomination_limb " )
if soulbind.kevins_oozeling . enabled then applyBuff ( " kevins_oozeling " ) end
end ,
auras = {
abominations_frenzy = {
id = 353546 ,
duration = 12 ,
max_stack = 1 ,
}
}
} ,
-- Death Knight - Night Fae - 324128 - deaths_due (Death's Due)
deaths_due = {
id = 324128 ,
cast = 0 ,
charges = function ( )
if not pvptalent.deaths_echo . enabled then return end
return 2
end ,
cooldown = 15 ,
recharge = function ( )
if not pvptalent.deaths_echo . enabled then return end
return 15
end ,
gcd = " spell " ,
spend = function ( ) return buff.crimson_scourge . up and 0 or 1 end ,
spendType = " runes " ,
startsCombat = true ,
texture = 3636837 ,
notalent = " defile " ,
handler = function ( )
removeBuff ( " crimson_scourge " )
if legendary.phearomones . enabled and buff.death_and_decay . down then
stat.haste = stat.haste + ( state.spec . blood and 0.1 or 0.15 )
end
applyBuff ( " death_and_decay " )
setCooldown ( " death_and_decay " , 15 )
applyBuff ( " deaths_due_buff " )
-- TODO: Model increase RP income within Death's Due.
applyDebuff ( " target " , " deaths_due_debuff " )
-- Note: Debuff is actually a buff on the target...
end ,
bind = { " defile " , " any_dnd " } ,
auras = {
deaths_due_buff = {
id = 324165 ,
duration = function ( ) return legendary.rampant_transference . enabled and 12 or 10 end ,
max_stack = 15 ,
copy = " deaths_due "
} ,
deaths_due_debuff = {
id = 324164 ,
duration = 15 ,
max_stack = 15 ,
generate = function ( t , auraType )
local name , icon , count , debuffType , duration , expirationTime , caster , stealable , nameplateShowPersonal , spellID , canApplyAura , isBossDebuff , nameplateShowAll , timeMod , value1 , value2 , value3 = FindUnitDebuffByID ( " target " , 324164 , " PLAYER " )
if name and expirationTime > query_time then
t.name = name
t.count = count > 0 and count or 1
t.expires = expirationTime
t.applied = expirationTime - duration
t.caster = " player "
return
end
t.count = 0
t.expires = 0
t.applied = 0
t.caster = " nobody "
end
} ,
}
} ,
-- Death Knight - Venthyr - 311648 - swarming_mist (Swarming Mist)
swarming_mist = {
id = 311648 ,
cast = 0 ,
cooldown = 60 ,
gcd = " spell " ,
spend = 1 ,
spendType = " runes " ,
toggle = " essences " ,
startsCombat = true ,
texture = 3565716 ,
handler = function ( )
applyBuff ( " swarming_mist " )
if conduit.impenetrable_gloom . enabled then applyBuff ( " impenetrable_gloom " ) end
if legendary.insatiable_hunger . enabled then applyBuff ( " insatiable_hunger " ) end
end ,
auras = {
-- Conduit
impenetrable_gloom = {
id = 338629 ,
duration = 4 ,
max_stack = 1
} ,
insatiable_hunger = {
id = 353729 ,
duration = 8 ,
max_stack = 1 ,
} ,
}
} ,
} )
spec : RegisterOptions ( {
enabled = true ,
aoe = 2 ,
nameplates = true ,
nameplateRange = 8 ,
damage = true ,
damageExpiration = 8 ,
potion = " potion_of_phantom_fire " ,
package = " Blood " ,
} )
spec : RegisterSetting ( " save_blood_shield " , true , {
name = " Save |T237517:0|t Blood Shield " ,
desc = " If checked, the default priority (or any priority checking |cFFFFD100save_blood_shield|r) will try to avoid letting your |T237517:0|t Blood Shield fall off during lulls in damage. " ,
type = " toggle " ,
width = " full "
} )
spec : RegisterSetting ( " blood_boil_drw " , false , {
name = " With Tier 28, use |T237513:0|t Blood Boil in AOE during |T135277:0|t Dancing Rune Weapon (Tier) " ,
desc = " If checked, when you have Tier 28 4-piece, the addon will recommend more |T237513:0|t Blood Boil in AOE while |T135277:0|t Dancing Rune Weapon is active. \n \n " ..
" This can help with AOE threat and damage, but can reduce your self-healing, absorbs, and potentially your Dancing Rune Weapon uptime. " ,
type = " toggle " ,
width = " full "
} )
spec : RegisterPack ( " Blood " , 20220911 , [ [ Hekili : vZvFVnUns ) plbfNxBVj ( SCIt6wyzG2Tf3T5P3Ea1fO3FzzAjAB9e9w1ljBkm0N9BgskjsjszNSb9UdDXUjsuKdN53mZVzirxBT ( xxVYJKtx ) 5 ztNnB6hSSMyb ) 78 zRxL ) CcD9QeI7dK9WpercH ) ( hcIJ9WN ( CqmXd ) 6 S4Iux4nR8dlci5 ( XrFmLSlF9QTf ( b5FkA9w9Ra8Ljux4PZNUE1bFppkFO0mxXYuU5hPK8dLB ( ) I83FiV8 ( v0KCA4wAA5glRll3Gty59L3 ) XdKO90SVR8 ( Rk3SQijjonVCZUyyCIj6hI9dk34hbt5V8BLBYO55 ( r7NSEvGFwEgtjK ( Ktrc8tFMPtOrKTbuV1 ) W6vUP ( 50 uFcUJ2TBY24iQt2bFAG3KSCq7uUzz5M5LBguUjTiIc ) QniAv ) UVRts8t00jE0D ( U ( 58 xF906XdI5E6eyrcZIJCWN48eLKehnPsgwrCr1kyrId3MLdR ) 6 CqVzumhwUPJKMsdj ( rzLBwyZx2j5 ( HuN8yNRl3C84P ( cyk37c6X3xUXnooWl ( POjBrvRxQF0dWUlLs8EUCZ4Yn5KaAuU6BfIj793uUzeFj1jNcn6IknimMlW18rykGznI6MgheN6jj0KTXH ( rmKNtGF42jfjSLG ) hJwbe ( 0 OAdjPPXpLsJ8qD719PBH ) 4 EGagTSwMAkxxzvVb9If6bNKaY ( cQQoDMSIa8fccCYXPnpt8rBzG2AWLyrD2LYfAsaF9b ) PQD6fCPRsBb ) t ( HNtzVIPQYEIKc6Q9oHaSNRNAubnlkQcUPLkiobCyP5nd ) rcOqG3I ) uqbLPAMnNbru3mhOK0CNS8u ) hOYie2Z3caN2iKzmXcMFhEmh5jWjnXbCvrjCEljSsW8WGgIH317LTj7aXfWB0yOfTG2RQn8enYJK2Vc ) dGAWxnnSzRnq25P ( 1 YcbFNh4d ( dUGF ) nJpqYYzE732hIuvFZ3 ) KiphpQlbCkX4nnyGQinzUqGBiYJWBb36NyEqW2nT1Z1VhLY7mkLsAvbQD60gzcC7cOzzIOFKG8 ) qk06nNcAxRuvH3Yk2Rvr6vkFuM ) wdWij3bP9HiZHSlAT9VxF4z6TRFOpnwtq6zvy0g5tgfIZK10Zr5 ) FiiTwFtuOzjBRERBCuwryc ) xA2j5W ) TQYYN1Fk6leik2cL54vWb41jlKEUSuEJ0q66G0s ( zFE ) PGRvkEKixerkNxVEHxw5y2X7au6Fa8pUstUbfqolE518CDnsPYqQZNv9225lvv1Dc8lH9Jlc26h5njPilViG6qtlygRg8alks1WEmg5dcJlloa9xvGnvgQ2dY5qrijk23JP39JG1gxfh ) Dscq7pszGHHupFKW5kRMn9oi ( YbxoX0MXUpiEljahOM8jQUIvHrABTwWcLjP7paXTajl ) a1Pi6jGj6HN5i4KuQlqGJKRdbJ0Et9fq ) F6lu3ICurTfPhsrNm8dXFFpGCMuU57DDbYWagkko6kGyq4UciodxiGNghf88eT7EMOe6N7VNHa63BccleKFysIBoBJoFAnFfW8TpngDTafsRHD7TkOXhjHj ( PGgJfruNFJ ( m3kQKpf5IO29aPksiupcyfO ) EHp4kbMFGzFgs ( 4 VaB8DLBcjFPsMq0yq8LOOR7LybbeXozI8g3xSCo8vZ5AbxpXo1TinfHDAOkEg7LFmo6DGmhqH ) Iasa9lGBkBVjQwzfJEcSvtJvfRmYJuhzkmm1FBHDop0Iu ( vfwpcJw ) 0 HSMmNfBbt50BqHCs0dmzVAkzr6YjjtW4FALVR5YNqxYmiWknDIK7A1K0VFPg4jpI5SPSPu ) ExcA67s3gxamyaVSC ) 8 cVtW1Q1cEhNyEcnFY ( dqSjfn4CPyceykW0UKahOEAHtiKjMue8sIgqFKMc8WqsbWFFGYC4XQCr4p5rIFalzUuvn ( 4 ElLs ) dT5ReC6XqR6y1xX ) wgkdP ( ctCiHGwlVvE3MI0WQ1D2rQknWHgKb ) 8851 LkC30 ( RYQguHrBmbVbzhejxKfHefccKQK ) loyT98k8fBePWE9IP5mf0K5gtjPyBWafv2IKy8zneIaeojJv2w0EQhed6j67cGG0zph5c ) Ipga6h ) LFRr25tqnKV6XfzuhqYcZALOUnmLVh3dHicCI3XsaTZpf28K0T4oRzg7zmvK4RDej ( WYdiaVwREBAZAOGPvbQTQ ( kaZjiQbw976wYQOjd6ytFwOcOCAWXmtlhAJEWQWGVphSpjqqH8yW ( kgBfUGfAaGX7qeaatsb6jU5Ws8mIcqeruCo2Sai5uHRiRe7lJaw5LB2vKxKsBvY3Ru9DBvNcmAHKh9nvgl9r4MXxpoX06sv88PnfupQHK ) l1S0q4hNIE72vtVxA6ftT8CdBRWKMEBIY3wxgC72JTSvLx8mkIStwMJI1VJGevHUVNnZVYaus5qnQCfD7exftTrPxJduDEKhj1JNjRYdQxUKNOKiw7dLcn0ttgrB0fNOrJD6R1UI0NRZbw ) kAAgnft10k6MzJk ( PajmAen0xQdGv4go5PEB74TsvlqsDjGwiPaZqE6CsfrhIdEgtftJ2derKn3byuGmN ) ) cV9HcUPkPraTouEEkeadTS6YLunsiJaLZvxDqkjg2s2ZYGazGFODMjZ5goNwXk0jaXgbh7Cj8wVqm9HPyU ( JzDGXy48tumF3aTG9Tv ) VGigU1mHhQVned6VleQ1n1UbpMXKV5NlXBzZ2uo0cZ47 ) x5ql65elUTU64xFc65kjO1V14SGo9PBizktpNdAs1 ( 2 l5Gf9jGsgF1JvP3oSCIouAQiK3W2u ( Md9B3TtZfw2lTeP4jhOHXaGlZpRg3Xb6ZzL ( AUd0A7WF7wu3ZXb1UZ ( sg4hW8aI8fkSI ) hW74nDr0xdVyAMGTBce3eYG6Ef9l5a6qPlhEu2EvzQB6MWoMZKsnbtM3FwhJN7XGAqtkfy3CWXpsSCYqhtEywtBBQvomKEBTV ( dd5Te8PCihDkS5ml9V15c86ZkQ2kaytA9MDuHSFWAYm5dI8TB21wat7QpEzNUsT3OHkN6IRKoWeZ0uoJtV76EbS9ukt7kQo5HrDcIS6Cg5AeU3ijXNjyXHjXz ( 4 A092qOBhyodJ50v8tHzCRDK8zrHZ8Rj2T1jYKRFLvd8A17zQs5bIQYr0MJK85A3djX7oTC2EMFFDb ( MXaV5Lbafc8iuXg ( A ( LjAoGZwbXdJWJKD9QF77 ) Lp ) Pp ) 3 ( UYnLB ( vSbk ( HsxfO3Xl69D1hDGhE6ayRujfajvcRfR8U1LnP8 ( F2h1UwWK9X4iyzzV ( DneP ( xVJ3Uh5hvbsHxHNwZp9p ) zWSy9Lr1t3TSPd2rU8g6 ( 7 fKa ) 8 NX1LIgJDPXHWuABxn54piMHY7pX ( RQiPx2o8Mx7o8CfR6g581jx1h ( xTy18ezPAMqQ ( etiWp9UQdgRCd76EbVgpnU4D ( yYUV5BQ5N066MHVX0vodFxZ1od ) Tx4vpJnjae5T5O ( kVx87tQpLX3B ) xBo2VoR2zEuc1ZRT0rju ) qyjQYXDjYxW2ej9lJtSzSnUecR6XINBFrxcexYsGBF30lBilypFU861URu81TPX ( xYptaBRl93zlogHJh7EeclNYuiVb9Vxw64tbU091bCPpOU3 ( 6 EiFVzUz9YFttF6LFQC9SOuDrpI1GHASihpAOy1L3n60MfrFbzA6 ) eArUSa1Udp4U ) LTbVD0Gt1K8L3myyNEoTy2XJDj2TaYwEgAS6yLDSIy ) MzBcuowypBGkLSLW8pOltKL2qfKJoEun9noy5fqZw8uOffSNAJMfHcyjBFbUc6viv50WayvH4Qvs2nMnj5vULBgnVlUr8knmr7UqiGsUSlC1oNgLS86bsuDwAp8dtVAypxNNXxpAK ( LV9L2r ) OAc4JsOX7RZXJgVjnd4kX ( UvoxQ5U2GXBBDRAuEKS00EUnOV1CpAWnfd ( ROwxGvplbp4ip76 ( owJb7q ( D5CMx0sU3uBgPlTVE6GEBCw71ee7MgEXCwnXPEHTQhPamQDKdbV133tdmh3tZlhFd483vky7 ( fZuc5xDZQfIIMBv9OrJ0QNMnvJIOPkgMIyOi2KqxdrWSajZ0f
end