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.

499 lines
16 KiB

4 years ago
-- GLOBALS: tDeleteItem
--------------------------------------------------------------------------------
-- TODO List:
-- - Shattering Scream: Find target before debuffs, without spamming? (current method allows for kicks before warnings)
-- - Add wave timers (no spell info)
-- - Stop Bars when initial bosses die (Spear/Bind/Collapsing Fissure)
--------------------------------------------------------------------------------
-- Module Declaration
--
local mod, CL = BigWigs:NewBoss("The Desolate Host", 1676, 1896)
if not mod then return end
mod:RegisterEnableMob(118460, 118462, 119072) -- Engine of Souls, Soul Queen Dejahna, The Desolate Host
mod.engageId = 2054
mod.respawnTime = 40
--------------------------------------------------------------------------------
-- Locals
--
local myRealm = 0 -- 1 = Spirit Realm, 0 = Corporeal Realm
local phasedList = {}
local unphasedList = {}
local stage = 1
local tormentedCriesCounter = 1
local wailingSoulsCounter = 1
local boneArmorCounter = 0
local spearCount = 1
local updateProximity = nil
local updateRealms = nil
local armorAppliedTimer, armorRemovedTimer = nil, nil
local soulList = mod:NewTargetList()
local nextWailingSouls, nextTormentedCries = 0, 0
--------------------------------------------------------------------------------
-- Localization
--
local L = mod:GetLocale()
if L then
L.infobox_players = "Players"
L.armor_remaining = "%s Remaining (%d)" -- Bonecage Armor Remaining (#)
L.custom_on_mythic_armor = "Ignore Bonecage Armor on Reanimated Templars in Mythic Difficulty"
L.custom_on_mythic_armor_desc = "Leave this option enabled if you are offtanking Reanimated Templars to ignore warnings and counting the Bonecage Armor on the Ranimated Templars"
L.custom_on_armor_plates = "Bonecage Armor icon on Enemy Nameplate"
L.custom_on_armor_plates_desc = "Show an icon on the nameplate of Reanimated Templars who have Bonecage Armor.\nRequires the use of Enemy Nameplates. This feature is currently only supported by KuiNameplates."
L.custom_on_armor_plates_icon = 236513
L.tormentingCriesSay = "Cries" -- Tormenting Cries (short say)
end
--------------------------------------------------------------------------------
-- Initialization
--
local soulBindMarker = mod:AddMarkerOption(false, "player", 3, 236459, 3,4)
function mod:GetOptions()
return {
"infobox",
{239006, "PROXIMITY"}, -- Dissonance
236678, -- Quietus
{235924, "SAY", "SAY_COUNTDOWN"}, -- Spear of Anguish
235907, -- Collapsing Fissure
{238570, "SAY", "SAY_COUNTDOWN", "ICON"}, -- Tormented Cries
235927, -- Rupturing Slam
236513, -- Bonecage Armor
"custom_on_armor_plates",
"custom_on_mythic_armor",
236131, -- Wither
{236459, "ME_ONLY"}, -- Soulbind
soulBindMarker,
236072, -- Wailing Souls
{236515, "ME_ONLY"}, -- Shattering Scream
236361, -- Spirit Chains
236241, -- Soul Rot
236542, -- Sundering Doom
236544, -- Doomed Sundering
236548, -- Torment
},{
["infobox"] = "general",
[235933] = -14856,-- Corporeal Realm
[235927] = CL.adds,-- Adds
[236131] = -14857,-- Spirit Realm
[236515] = CL.adds,-- Adds
[236542] = -14970, -- Tormented Souls
}
end
function mod:OnBossEnable()
-- General
updateRealms(self)
self:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", nil, "boss1", "boss2", "boss3")
self:Log("SPELL_AURA_APPLIED", "Quietus", 236678)
self:Log("SPELL_AURA_APPLIED", "SpiritualBarrier", 235732)
self:Log("SPELL_AURA_REMOVED", "SpiritualBarrierRemoved", 235732)
self:Log("SPELL_AURA_APPLIED", "GroundEffectDamage", 235907, 236241) -- Collapsing Fissure, Soul Rot
self:Log("SPELL_PERIODIC_DAMAGE", "GroundEffectDamage", 235907, 236241) -- Collapsing Fissure, Soul Rot
self:Log("SPELL_PERIODIC_MISSED", "GroundEffectDamage", 235907, 236241) -- Collapsing Fissure, Soul Rot
-- Corporeal Realm
self:Log("SPELL_AURA_APPLIED", "SpearofAnguish", 235924)
self:Log("SPELL_AURA_REMOVED", "SpearofAnguishRemoved", 235924)
self:Log("SPELL_CAST_START", "TormentedCries", 238570)
self:Log("SPELL_AURA_APPLIED", "TormentedCriesApplied", 238018)
self:Log("SPELL_AURA_REMOVED", "TormentedCriesRemoved", 238018)
self:Log("SPELL_AURA_APPLIED", "TormentedCriesDamage", 236011)
self:Log("SPELL_PERIODIC_DAMAGE", "TormentedCriesDamage", 236011, 238018)
self:Log("SPELL_PERIODIC_MISSED", "TormentedCriesDamage", 236011, 238018)
-- Adds
self:Log("SPELL_CAST_START", "RupturingSlam", 235927)
self:Log("SPELL_AURA_APPLIED", "BonecageArmor", 236513)
self:Log("SPELL_AURA_REMOVED", "BonecageArmorRemoved", 236513)
-- Spirit Realm
self:Log("SPELL_AURA_APPLIED", "Wither", 236131, 236138) -- Both ids are used
self:Log("SPELL_AURA_APPLIED", "Soulbind", 236459)
self:Log("SPELL_AURA_REMOVED", "SoulbindRemoved", 236459)
self:Log("SPELL_CAST_SUCCESS", "WailingSouls", 236072)
-- Adds
self:Log("SPELL_AURA_APPLIED", "ShatteringScream", 236515)
self:Log("SPELL_AURA_APPLIED", "SpiritChains", 236361)
-- Tormented Souls
self:Log("SPELL_CAST_START", "SunderingDoom", 236542)
self:Log("SPELL_CAST_START", "DoomedSundering", 236544)
self:Log("SPELL_AURA_APPLIED", "Torment", 236548)
self:Log("SPELL_AURA_APPLIED_DOSE", "Torment", 236548)
self:Death("EngineDies", 118460)
end
function mod:OnEngage()
updateRealms(self)
if not self:Easy() then -- No Dissonance in LFR/Normal
updateProximity(self)
end
stage = 1
boneArmorCounter = 0
tormentedCriesCounter = 1
wailingSoulsCounter = 1
spearCount = 1
armorAppliedTimer, armorRemovedTimer = nil, nil
nextWailingSouls, nextTormentedCries = GetTime() + 60, GetTime() + 120
soulList = {}
if self:Easy() then
self:OpenInfo("infobox", L.infobox_players)
self:SetInfo("infobox", 1, self:SpellName(-14857)) -- Spirit Realm
self:SetInfo("infobox", 2, #phasedList)
self:SetInfo("infobox", 3, self:SpellName(-14856)) -- Corporeal Realm
self:SetInfo("infobox", 4, #unphasedList)
else
self:OpenInfo("infobox")
self:SetInfo("infobox", 1, self:SpellName(55336)) -- Bone Armor (Shorter Text)
self:SetInfo("infobox", 2, boneArmorCounter)
self:SetInfo("infobox", 6, L.infobox_players)
self:SetInfo("infobox", 7, self:SpellName(-14857)) -- Spirit Realm
self:SetInfo("infobox", 8, #phasedList)
self:SetInfo("infobox", 9, self:SpellName(-14856)) -- Corporeal Realm
self:SetInfo("infobox", 10, #unphasedList)
end
self:CDBar(235907, 6) -- Collapsing Fissure
self:CDBar(236459, 16) -- Soulbind
if not self:Easy() then -- Heroic+ only
self:CDBar(235924, 20, CL.count:format(self:SpellName(235924), spearCount)) -- Spear of Anguish
end
self:CDBar(236072, 60) -- Wailing Souls
self:CDBar(238570, 120) -- Tormented Cries
end
--------------------------------------------------------------------------------
-- Event Handlers
--
function mod:UNIT_SPELLCAST_SUCCEEDED(_, _, _, spellId)
if spellId == 235885 then -- Collapsing Fissure
self:MessageOld(235907, "yellow", "alert", spellId, 235907)
local t = stage == 2 and 15.8 or 30.5
local remaining = nextTormentedCries - GetTime()
if stage ~= 2 and remaining < 30.5 and remaining > 0 then
t = 65 + remaining -- Time Left + 60s channel + 5s~ cooldown
end
self:Bar(235907, t)
elseif spellId == 239978 then -- Soul Pallor // Stage 2
stage = 2
self:StopBar(236072) -- Wailing Souls
self:StopBar(238570) -- Tormented Cries
self:StopBar(CL.cast:format(self:SpellName(236072))) -- <cast: Wailing Souls>
self:StopBar(CL.cast:format(self:SpellName(238570))) -- <cast: Tormented Cries>
self:CDBar(235907, 2.5) -- Collapsing Fissure
if not self:Easy() then
self:CDBar(235924, 8, CL.count:format(self:SpellName(235924), spearCount)) -- Spear of Anguish
end
self:CDBar(236459, 9) -- Soulbind
self:CDBar(236542, 17) -- Sundering Doom
self:CDBar(236544, 28) -- Doomed Sundering
end
end
function updateRealms(self)
-- Dissonance Handling
phasedList = {}
unphasedList = {}
for unit in self:IterateGroup() do
local buffCheck = self:UnitDebuff(unit, 235621) -- Spirit Realm
local guid = self:UnitGUID(unit)
if buffCheck then
phasedList[#phasedList+1] = self:UnitName(unit)
if self:Me(guid) then
myRealm = 1 -- Spirit Realm
end
else
unphasedList[#unphasedList+1] = self:UnitName(unit)
if self:Me(guid) then
myRealm = 0 -- Corporeal Realm
end
end
end
end
function updateProximity(self)
if myRealm == 0 then -- Corporeal Realm
self:OpenProximity(239006, 8, phasedList) -- Avoid people in Spirit Realm
else
self:OpenProximity(239006, 8, unphasedList) -- Avoid people not in Spirit Realm
end
end
do
local function updateInfoBox(self)
if self:Easy() then
self:SetInfo("infobox", 2, #phasedList)
self:SetInfo("infobox", 4, #unphasedList)
else
self:SetInfo("infobox", 8, #phasedList)
self:SetInfo("infobox", 10, #unphasedList)
end
end
function mod:SpiritualBarrier(args)
phasedList[#phasedList+1] = args.destName
tDeleteItem(unphasedList, args.destName)
if self:Me(args.destGUID) then
myRealm = 1
self:MessageOld(239006, "cyan", "info", self:SpellName(-14857), false) -- Dissonance // Spirit Realm
end
if not self:Easy() then -- No Dissonance in LFR/Normal
updateProximity(self)
end
updateInfoBox(self)
end
function mod:SpiritualBarrierRemoved(args)
unphasedList[#unphasedList+1] = args.destName
tDeleteItem(phasedList, args.destName)
if self:Me(args.destGUID) then
myRealm = 0 -- Corporeal Realm
self:MessageOld(239006, "cyan", "info", self:SpellName(-14856), false) -- Dissonance // Corporeal Realm
end
if not self:Easy() then -- No Dissonance in LFR/Normal
updateProximity(self)
end
updateInfoBox(self)
end
end
do
local prev = 0
function mod:GroundEffectDamage(args)
local t = GetTime()
if self:Me(args.destGUID) and t-prev > 1.5 then
prev = t
self:MessageOld(args.spellId, "blue", "alert", CL.underyou:format(args.spellName))
end
end
end
function mod:Quietus(args)
self:MessageOld(args.spellId, "red", "warning")
end
function mod:SpearofAnguish(args)
self:TargetMessageOld(args.spellId, args.destName, "orange", "alarm", CL.count:format(args.spellName, spearCount), nil, true)
if self:Me(args.destGUID) then
self:Say(args.spellId)
self:SayCountdown(args.spellId, 6)
end
spearCount = spearCount + 1
local t = 21
local remaining = nextTormentedCries - GetTime()
if remaining < 20.5 and remaining > 0 then
t = 80.5 + remaining -- Time Left + 60s channel + 20.5s cooldown
end
self:Bar(args.spellId, t, CL.count:format(args.spellName, spearCount))
end
function mod:SpearofAnguishRemoved(args)
if self:Me(args.destGUID) then
self:CancelSayCountdown(args.spellId)
end
end
function mod:TormentedCries(args)
self:MessageOld(args.spellId, "yellow", "info", CL.incoming:format(args.spellName))
tormentedCriesCounter = tormentedCriesCounter + 1
if tormentedCriesCounter <= 2 then -- Does a 3rd cast exist?
nextTormentedCries = GetTime() + 120
self:Bar(args.spellId, 120)
end
self:CastBar(args.spellId, 60)
end
function mod:TormentedCriesApplied(args)
self:TargetMessageOld(238570, args.destName, "orange", "alarm")
if self:Me(args.destGUID) then
self:Say(238570, L.tormentingCriesSay)
self:SayCountdown(238570, 4)
end
self:PrimaryIcon(238570, args.destName)
end
function mod:TormentedCriesRemoved(args)
self:PrimaryIcon(238570)
if self:Me(args.destGUID) then
self:CancelSayCountdown(238570)
end
end
do
local prev = 0
function mod:TormentedCriesDamage(args)
local t = GetTime()
if self:Me(args.destGUID) and t-prev > 1.5 then
prev = t
self:MessageOld(238570, "blue", "alert", CL.underyou:format(args.spellName))
end
end
end
do
local prev = 0
function mod:RupturingSlam(args)
local t = GetTime()
if t-prev > 3 then
prev = t
self:MessageOld(args.spellId, "yellow", "alert", CL.incoming:format(args.spellName))
end
end
end
do
local function printArmorApplied(self, spellId, spellName)
armorAppliedTimer = nil
self:MessageOld(spellId, "yellow", "warning", CL.count:format(spellName, boneArmorCounter))
end
local function printArmorRemoved(self, spellId, spellName)
armorRemovedTimer = nil
self:MessageOld(spellId, "green", "info", L.armor_remaining:format(spellName, boneArmorCounter))
end
function mod:BonecageArmor(args)
if self:Mythic() and self:GetOption("custom_on_mythic_armor") and self:MobId(args.destGUID) == 118715 then return end -- Reanimated Templar
boneArmorCounter = boneArmorCounter + 1
self:SetInfo("infobox", 2, boneArmorCounter)
if self:GetOption("custom_on_armor_plates") then
self:AddPlateIcon(236513, args.sourceGUID) -- Display an armor icon above targets with armor
end
if not armorAppliedTimer then
armorAppliedTimer = self:ScheduleTimer(printArmorApplied, 0.1, self, args.spellId, args.spellName)
end
end
function mod:BonecageArmorRemoved(args)
if self:Mythic() and self:GetOption("custom_on_mythic_armor") and self:MobId(args.destGUID) == 118715 then return end -- Reanimated Templar
boneArmorCounter = boneArmorCounter - 1
self:SetInfo("infobox", 2, boneArmorCounter)
if self:GetOption("custom_on_armor_plates") then
self:RemovePlateIcon(236513, args.sourceGUID) -- Remove the armor icon
end
if not armorRemovedTimer then
armorRemovedTimer = self:ScheduleTimer(printArmorRemoved, 0.1, self, args.spellId, args.spellName)
end
end
end
function mod:Wither(args)
if self:Me(args.destGUID) then
self:TargetMessageOld(236131, args.destName, "blue", "alarm")
end
end
do
local linkOnMe = false
function mod:Soulbind(args)
soulList[#soulList+1] = args.destName
if #soulList == 1 then
local t = stage == 2 and 19.4 or 24.3
if self:Easy() then
t = stage == 2 and 24 or 34
end
local remaining = nextWailingSouls - GetTime()
if stage ~= 2 and remaining < 24.3 and remaining > 0 then
t = 74.5 + remaining -- Time Left + 60s channel + 14.5s cooldown
end
self:Bar(args.spellId, t)
if self:GetOption(soulBindMarker) then
self:CustomIcon(false, args.destName, 3)
end
linkOnMe = self:Me(args.destGUID)
elseif #soulList == 2 then -- Announce at 2
if self:GetOption(soulBindMarker) then
self:CustomIcon(false, args.destName, 4)
end
if self:Me(args.destGUID) then
self:MessageOld(args.spellId, "blue", "warning", CL.link_with:format(self:ColorName(soulList[1])))
elseif linkOnMe then
self:MessageOld(args.spellId, "blue", "warning", CL.link_with:format(self:ColorName(soulList[2])))
elseif not self:CheckOption(args.spellId, "ME_ONLY") then
self:MessageOld(args.spellId, "green", "info", CL.link_both:format(self:ColorName(soulList[1]), self:ColorName(soulList[2])))
end
soulList = {}
end
end
end
function mod:SoulbindRemoved(args)
if self:Me(args.destGUID) then
self:MessageOld(args.spellId, "blue", "long", CL.link_removed)
end
if self:GetOption(soulBindMarker) then
self:CustomIcon(false, args.destName)
end
end
function mod:WailingSouls(args)
self:MessageOld(args.spellId, "red", "warning")
wailingSoulsCounter = wailingSoulsCounter + 1
if wailingSoulsCounter <= 2 then -- XXX Does a 3rd cast exist?
nextWailingSouls = GetTime() + 120
self:Bar(args.spellId, 120)
end
self:CastBar(args.spellId, 60)
end
do
local list = mod:NewTargetList()
function mod:ShatteringScream(args)
list[#list+1] = args.destName
if #list == 1 then
self:ScheduleTimer("TargetMessageOld", 0.5, args.spellId, list, "yellow", "warning")
end
end
end
function mod:SpiritChains(args)
if self:Me(args.destGUID) then
self:TargetMessageOld(args.spellId, args.destName, "blue", "alert")
end
end
function mod:SunderingDoom(args)
self:MessageOld(args.spellId, "red", "warning")
self:Bar(args.spellId, self:Easy() and 26.5 or 25)
self:CastBar(args.spellId, self:Easy() and 6 or self:Heroic() and 5 or 4)
end
function mod:DoomedSundering(args)
self:MessageOld(args.spellId, "red", "warning")
self:Bar(args.spellId, self:Easy() and 26.5 or 25)
self:CastBar(args.spellId, self:Easy() and 6 or self:Heroic() and 5 or 4)
end
do
local prev = 0
function mod:Torment(args)
local t = GetTime()
if t-prev > 1 then
prev = t
self:StackMessage(args.spellId, args.destName, args.amount, "yellow", "info")
end
end
end
function mod:EngineDies()
self:StopBar(236459) -- Soulbind
self:StopBar(235907) -- Collapsing Fissure
self:StopBar(CL.count:format(self:SpellName(235924), spearCount)) -- Spear of Anguish
end