-------------------------------------------------------------------------------- -- TODO List: -- - WaveSpawn got broken, figure out a new way to do this -- Wave 1: Wisp, Drake, Treant -- Wave 2: Wisp, Drake, Sister -- Wave 3: 2x Sister, Treant -- Wave 4: 2x Drake, Wisp -- Wave 5: 2x Treant, Sister -- Wave 6: 2x Wisp, Sister -------------------------------------------------------------------------------- -- Module Declaration -- local mod, CL = BigWigs:NewBoss("Cenarius", 1520, 1750) if not mod then return end mod:RegisterEnableMob(104636) mod.engageId = 1877 mod.respawnTime = 30 -------------------------------------------------------------------------------- -- Locals -- local mobCollector = {} local forcesOfNightmareCount = 1 local phase = 1 local wispMarks = { [8] = true, [7] = true, [6] = true, [5] = true, [4] = true } local wispMarked = {} local nightmareStacks = {} local mobTable = { [105468] = {}, -- Nightmare Ancient [105494] = {}, -- Rotten Drake [105495] = {}, -- Twisted Sister } local mobCount = { [105468] = 0, -- Nightmare Ancient [105494] = 0, -- Rotten Drake [105495] = 0, -- Twisted Sister } local drakeDeaths = 0 -------------------------------------------------------------------------------- -- Localization -- local L = mod:GetLocale() if L then L.forces = "Forces" L.bramblesSay = "Brambles near %s" L.custom_off_multiple_breath_bar = "Show multiple Rotten Breath bars" L.custom_off_multiple_breath_bar_desc = "Per default BigWigs will only show the Rotten Breath bar of one drake. Enable this option if you want to see the timer for each drake." end -------------------------------------------------------------------------------- -- Initialization -- local wispMarker = mod:AddMarkerOption(false, "npc", 8, -13348, 8, 7, 6, 5, 4) -- Corrupted Wisp function mod:GetOptions() return { --[[ Cenarius ]]-- "stages", {210279, "INFOBOX"}, -- Creeping Nightmares {210290, "SAY", "FLASH"}, -- Nightmare Brambles 212726, -- Forces of Nightmare 210346, -- Dread Thorns -- P2 214505, -- Entangling Nightmares 214529, -- Spear of Nightmares {213162, "TANK"}, -- Nightmare Blast --[[ Malfurion Stormrage ]]-- 212681, -- Cleansed Ground --[[ Corrupted Wisp ]]-- wispMarker, --[[ Nightmare Treant ]]-- 226821, -- Desiccating Stomp --[[ Rotten Drake ]]-- {211192, "SAY"}, -- Rotten Breath "custom_off_multiple_breath_bar", --[[ Twisted Sister ]]-- 211368, -- Twisted Touch of Life {211471, "SAY", "FLASH", "PROXIMITY"}, -- Scorned Touch {211989, "SAY"}, -- Unbound Touch --[[ Mythic ]]-- 214876, -- Beasts of Nightmare 214884, -- Corrupt Allies of Nature },{ ["stages"] = -13339, -- Cenarius [212681] = -13344, -- Malfurion Stormrage [wispMarker] = -13348, -- Corrupted Wisp [226821] = -13350, -- Nightmare Treant [211192] = -13354, -- Rotten Drake [211368] = -13357, -- Twisted Sister [214876] = "mythic", } end function mod:OnBossEnable() --[[ Cenarius ]]-- self:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", nil, "boss1") self:Log("SPELL_CAST_START", "ForcesOfNightmare", 212726) self:Death("MobDeath", 105468, 105494, 105495) -- Nightmare Ancient, Rotten Drake, Twisted Sister self:Log("SPELL_AURA_APPLIED_DOSE", "CreepingNightmares", 210279) self:Log("SPELL_AURA_REMOVED", "CreepingNightmaresRemoved", 210279) self:Log("SPELL_AURA_APPLIED", "DreadThorns", 210346) self:Log("SPELL_AURA_REMOVED", "DreadThornsRemoved", 210346) self:Log("SPELL_AURA_APPLIED", "EntanglingNightmares", 214505) self:Log("SPELL_CAST_START", "SpearOfNightmaresCast", 214529) self:Log("SPELL_AURA_APPLIED", "SpearOfNightmares", 214529) self:Log("SPELL_AURA_APPLIED_DOSE", "SpearOfNightmares", 214529) --[[ Malfurion Stormrage ]]-- self:Log("SPELL_AURA_APPLIED", "CleansedGround", 212681) self:Log("SPELL_AURA_REMOVED", "CleansedGroundRemoved", 212681) --[[ Corrupted Wisp ]]-- self:Death("WispDeath", 106659) --[[ Nightmare Treant ]]-- self:Log("SPELL_CAST_START", "DesiccatingStomp", 226821, 211073) -- mythic, normal/heroic self:Log("SPELL_CAST_START", "NightmareBlast", 213162) --[[ Rotten Drake ]]-- self:Log("SPELL_CAST_START", "RottenBreath", 211192) --[[ Twisted Sister ]]-- self:Log("SPELL_CAST_START", "TwistedTouchOfLife", 211368) self:Log("SPELL_AURA_APPLIED", "TwistedTouchOfLifeApplied", 211368) self:Log("SPELL_AURA_APPLIED", "ScornedTouch", 211471) self:Log("SPELL_AURA_REMOVED", "ScornedTouchRemoved", 211471) self:Log("SPELL_AURA_APPLIED", "UnboundTouch", 211989) --[[ Mythic ]]-- self:Log("SPELL_AURA_APPLIED", "CorruptAlliesOfNature", 214884) end function mod:OnEngage() forcesOfNightmareCount = 1 phase = 1 self:CDBar(212726, 10, CL.count:format(self:SpellName(212726), forcesOfNightmareCount)) -- Forces of Nightmare self:Bar(210290, 28) -- Nightmare Brambles if self:Mythic() then self:CDBar(213162, 30) -- Nightmare Blast end mobCollector = {} nightmareStacks = {} mobTable = { [105468] = {}, -- Nightmare Ancient [105494] = {}, -- Rotten Drake [105495] = {}, -- Twisted Sister } mobCount = { [105468] = 0, -- Nightmare Ancient [105494] = 0, -- Rotten Drake [105495] = 0, -- Twisted Sister } drakeDeaths = 0 self:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT") wispMarked = {} wispMarks = { [8] = true, [7] = true, [6] = true, [5] = true, [4] = true } self:OpenInfo(210279, self:SpellName(210279)) -- Creeping Nightmares end function mod:OnBossDisable() wispMarked = {} mobCollector = {} end -------------------------------------------------------------------------------- -- Local Functions -- local function getMobNumber(mobId, guid) if mobTable[mobId][guid] then return mobTable[mobId][guid] end mobCount[mobId] = mobCount[mobId] + 1 mobTable[mobId][guid] = mobCount[mobId] return mobCount[mobId] end -------------------------------------------------------------------------------- -- Event Handlers -- function mod:MobDeath(args) local mobId = self:MobId(args.destGUID) local mobText = getMobNumber(mobId, args.destGUID) if mobId == 105468 then -- Nightmare Ancient self:StopBar(CL.count:format(self:SpellName(226821), mobText)) -- Desiccating Stomp elseif mobId == 105494 then -- Rotten Drake self:StopBar(CL.count:format(self:SpellName(211192), mobText)) -- Rotten Breath self:StopBar(CL.cast:format(CL.count:format(self:SpellName(211192), mobText))) -- drakeDeaths = drakeDeaths + 1 self:UnregisterUnitEvent("UNIT_TARGET", mobCollector[args.destGUID]) elseif mobId == 105495 then -- Twisted Sister self:StopBar(CL.count:format(self:SpellName(211471), mobText)) -- Scorned Touch self:StopBar(CL.count:format(self:SpellName(211368), mobText)) -- Twisted Touch of Life end end function mod:WispMark(event, unit, guid) if self:MobId(guid) == 106659 and UnitIsEnemy("player", unit) and not wispMarked[guid] then local icon = next(wispMarks) if icon then -- At least one icon unused self:CustomIcon(false, unit, icon) wispMarks[icon] = nil -- Mark is no longer available wispMarked[guid] = icon -- Save the wisp we marked and the icon we marked it with end end end function mod:WispDeath(args) if wispMarked[args.destGUID] then -- Did we mark the wisp? wispMarks[wispMarked[args.destGUID]] = true -- Mark used is available again end end --[[ Cenarius ]]-- function mod:UNIT_SPELLCAST_SUCCEEDED(_, _, _, spellId) if spellId == 210290 then -- Nightmare Brambles self:Bar(spellId, phase == 2 and 20 or 30) -- at some point starts casting with 15sec-20sec cd local targetGUID = self:UnitGUID("boss1target") -- selects target 2sec prior to the cast if targetGUID then if self:Me(targetGUID) then self:Flash(spellId) self:Say(spellId, L.bramblesSay:format(self:UnitName("player")), true) self:MessageOld(spellId, "orange", "alarm", CL.near:format(self:SpellName(spellId))) else self:MessageOld(spellId, "orange", "alarm") end end elseif spellId == 217368 then -- Phase 2 phase = 2 self:StopBar(213162) -- Nightmare Blast self:StopBar(CL.count:format(self:SpellName(212726), forcesOfNightmareCount)) -- Forces of Nightmare self:StopBar(210346) -- Dread Thorns self:Bar(210290, 13) -- Nightmare Brambles self:Bar(214529, 23) -- Spear Of Nightmares self:Bar(214505, 35) -- Entangling Nightmares self:MessageOld("stages", "cyan", "long", CL.stage:format(2), false) elseif spellId == 214876 then -- Beasts of Nightmare self:MessageOld(spellId, "red", "alert", CL.incoming:format(self:SpellName(spellId))) self:Bar(spellId, 30.3) end end do local prev = 0 function mod:CreepingNightmares(args) nightmareStacks[args.destName] = args.amount if self:Me(args.destGUID) then local amount = args.amount or 1 if amount > 15 and amount % 4 == 0 then self:StackMessage(args.spellId, args.destName, amount, "orange", "warning") end end local t = GetTime() if t-prev > 2 then prev = t self:SetInfoByTable(args.spellId, nightmareStacks) end end end function mod:CreepingNightmaresRemoved(args) nightmareStacks[args.destName] = nil if self:Me(args.destGUID) then self:MessageOld(args.spellId, "green", "info", CL.removed:format(args.spellName)) end end function mod:NightmareBlast(args) self:MessageOld(args.spellId, "orange", "alert", CL.casting:format(args.spellName)) self:CDBar(args.spellId, 32) end function mod:ForcesOfNightmare(args) self:MessageOld(args.spellId, "orange", nil, CL.casting:format(args.spellName)) forcesOfNightmareCount = forcesOfNightmareCount + 1 self:Bar(210346, 6) -- Dread Thorns self:Bar(212681, 11) -- Cleansed Ground self:Bar(args.spellId, 77.7, CL.count:format(args.spellName, forcesOfNightmareCount)) if self:GetOption(wispMarker) then self:RegisterTargetEvents("WispMark") self:ScheduleTimer("UnregisterTargetEvents", 10) end end do local adds = { [106304] = -13348, -- Corrupted Wisp [105468] = -13350, -- Nightmare Treant [105494] = -13354, -- Rotten Drake [105495] = -13357, -- Twisted Sister } function mod:INSTANCE_ENCOUNTER_ENGAGE_UNIT() for i = 1, 5 do local unit = ("boss%d"):format(i) local guid = self:UnitGUID(unit) if guid and not mobCollector[guid] and UnitIsEnemy("player", unit) then mobCollector[guid] = true local mobId = self:MobId(guid) local id = adds[mobId] if id then self:MessageOld(212726, "cyan", "info", CL.count:format(self:SpellName(id), getMobNumber(mobId, guid)), false) end if mobId == 105468 then -- Nightmare Ancient self:Bar(226821, 20, CL.count:format(self:SpellName(226821), getMobNumber(mobId, guid))) -- Desiccating Stomp elseif mobId == 105494 then -- Rotten Drake mobCollector[guid] = unit if self:GetOption("custom_off_multiple_breath_bar") or (mobCount[105494]-drakeDeaths == 1) or (drakeDeaths+1 == getMobNumber(105494, guid)) then self:Bar(211192, 20, CL.count:format(self:SpellName(211192), getMobNumber(mobId, guid))) -- Rotten Breath end self:ScheduleTimer("RegisterUnitEvent", 15, "UNIT_TARGET", "BreathTarget", unit) elseif mobId == 105495 then -- Twisted Sister self:CDBar(211471, 5, CL.count:format(self:SpellName(211471), getMobNumber(mobId, guid))) -- Scorned Touch self:CDBar(211368, 6, CL.count:format(self:SpellName(211368), getMobNumber(mobId, guid))) -- Twisted Touch of Life end end end end end function mod:DreadThorns(args) self:TargetMessageOld(args.spellId, args.destName, "orange", "alarm") self:Bar(args.spellId, 45, CL.on:format(args.spellName, args.destName)) end function mod:DreadThornsRemoved(args) self:MessageOld(args.spellId, "green", "info", CL.removed:format(args.spellName)) if phase == 1 then self:CDBar(args.spellId, 32.7) end end function mod:EntanglingNightmares(args) self:TargetMessageOld(args.spellId, args.destName, "orange", "alarm") self:CDBar(args.spellId, 51) end -- untested local prev = 0 function mod:CorruptAlliesOfNature(args) local t = GetTime() if t-prev > 10 then prev = t self:MessageOld(args.spellId, "yellow", "info", CL.other:format(args.spellName, args.destName)) end end function mod:SpearOfNightmaresCast(args) self:MessageOld(args.spellId, "orange", nil, CL.casting:format(args.spellName)) end function mod:SpearOfNightmares(args) local amount = args.amount or 1 self:StackMessage(args.spellId, args.destName, amount, "orange", self:Tank() and "warning") self:Bar(args.spellId, 15.7) end --[[ Malfurion Stormrage ]]-- do local cleansedGroundCheck = nil local function checkForCleansedGround(self, spellId, spellName) if self:UnitDebuff("player", spellName) then self:MessageOld(spellId, "green", "alert", CL.underyou:format(spellName)) cleansedGroundCheck = self:ScheduleTimer(checkForCleansedGround, 1, self, spellId, spellName) end end function mod:CleansedGround(args) if self:Me(args.destGUID) then if cleansedGroundCheck then self:CancelTimer(cleansedGroundCheck) end cleansedGroundCheck = self:ScheduleTimer(checkForCleansedGround, 1, self, args.spellId, args.spellName) -- you shouldn't stand in there for too long end end function mod:CleansedGroundRemoved(args) if cleansedGroundCheck and self:Me(args.destGUID) then self:CancelTimer(cleansedGroundCheck) cleansedGroundCheck = nil end end end --[[ Nightmare Treant ]]-- do local prev = 0 function mod:DesiccatingStomp(args) self:StopBar(CL.count:format(args.spellName, getMobNumber(105468, args.sourceGUID))) -- Desiccating Stomp self:MessageOld(226821, "orange", "long", CL.casting:format(args.spellName)) local t = GetTime() if t-prev > 4 then prev = t local spellText = CL.count:format(args.spellName, getMobNumber(105468, args.sourceGUID)) self:CastBar(226821, self:Mythic() and 6.1 or 3, spellText) self:ScheduleTimer("Bar", 6.1, 226821, 27, spellText) end end end --[[ Rotten Drake ]]-- function mod:RottenBreath(args) if self:GetOption("custom_off_multiple_breath_bar") or (mobCount[105494]-drakeDeaths == 1) or (drakeDeaths+1 == getMobNumber(105494, args.sourceGUID)) then local spellText = CL.count:format(args.spellName, getMobNumber(105494, args.sourceGUID)) self:CastBar(args.spellId, 5.5, spellText) self:CDBar(args.spellId, 25, spellText) end end function mod:BreathTarget(event, unit) -- They love to drop their target after casting local target = unit.."target" local guid = self:UnitGUID(target) if not guid or self:Tanking(unit, target) or self:MobId(guid) ~= 1 then return end if self:Me(guid) then self:Say(211192) end self:TargetMessageOld(211192, self:UnitName(target), "yellow", "alert", nil, nil, true) end --[[ Twisted Sister ]]-- function mod:TwistedTouchOfLife(args) local spellText = CL.count:format(args.spellName, getMobNumber(105495, args.sourceGUID)) self:MessageOld(args.spellId, "red", self:Interrupter() and "alarm", CL.casting:format(spellText)) self:Bar(args.spellId, self:Mythic() and 11 or 15.5, spellText) end function mod:TwistedTouchOfLifeApplied(args) self:TargetMessageOld(args.spellId, args.destName, "orange", "alarm", nil, nil, self:Dispeller("magic", true, args.spellId)) end do local proxList, isOnMe, scheduled = {}, nil, nil local prev = 0 local function warn(self, spellId, spellName, guid) if not isOnMe then self:MessageOld(spellId, "red", "alert", CL.count:format(spellName, getMobNumber(105495, guid))) end scheduled = nil end function mod:ScornedTouch(args) if self:Me(args.destGUID) then self:TargetMessageOld(args.spellId, args.destName, "blue", "alert") isOnMe = true self:Flash(args.spellId) self:Say(args.spellId) local _, _, _, expires = self:UnitDebuff("player", args.spellName) local t = expires - GetTime() self:TargetBar(args.spellId, t, args.destName) self:OpenProximity(args.spellId, 8) end proxList[#proxList+1] = args.destName if not isOnMe then self:OpenProximity(args.spellId, 8, proxList) end local t = GetTime() if t-prev > 19 and (not scheduled) then -- prevent debuff spread to reset timer prev = t scheduled = self:ScheduleTimer(warn, 0.1, self, args.spellId, args.spellName, args.sourceGUID) self:Bar(args.spellId, 20.6, CL.count:format(args.spellName, getMobNumber(105495, args.sourceGUID))) end end function mod:ScornedTouchRemoved(args) if self:Me(args.destGUID) then isOnMe = nil self:StopBar(args.spellName, args.destName) self:CloseProximity(args.spellId) end tDeleteItem(proxList, args.destName) if not isOnMe then -- Don't change proximity if it's on you and expired on someone else if #proxList == 0 then self:CloseProximity(args.spellId) else self:OpenProximity(args.spellId, 8, proxList) end end end end function mod:UnboundTouch(args) if self:Me(args.destGUID) then self:TargetMessageOld(args.spellId, args.destName, "blue", "alert") self:Say(args.spellId) end end