--------------------------------------------------------------------------------
-- Module Declaration
--
local mod , CL = BigWigs : NewBoss ( " Sire Denathrius " , 2296 , 2424 )
if not mod then return end
mod : RegisterEnableMob ( 167406 ) -- Sire Denathrius
mod : SetEncounterID ( 2407 )
mod : SetRespawnTime ( 30 )
mod : SetStage ( 1 )
--------------------------------------------------------------------------------
-- Locals
--
local intermission = nil
local nextStageWarning = 73
local burdenPlayerTracker = { }
local burdenStackTable = { }
local burdenStacksOnMe = 0
local cleansingPainCount = 1
local bloodPriceCount = 1
local nightHunterCount = 1
local ravageCount = 1
local impaleCount = 1
local wrackingPainCount = 1
local handCount = 1
local massacreCount = 1
local shatteringPainCount = 1
local fatalFinesseCount = 1
local addCount = 1
local balefulShadowsList = { }
local mobCollector = { }
local balefulShadowCount = 1
local mirrorList = { }
local mirrorCount = 0
local isMoving = false
local timersEasy = {
[ 1 ] = {
-- Feeding Time
[ 327039 ] = { 15 , 25 , 35 , 25 , 35 , 25 } ,
-- Cleansing Pain
[ 326707 ] = { 8.7 , 26.7 , 32.8 , 26.7 , 34 , 26.8 } , -- From _success to _start, so timers are adjusted by -3s for the cast time
} ,
[ 2 ] = {
-- Crimson Cabalist // First ones are up from the start
[ - 22131 ] = { 4 , 85 , 80 } ,
-- Impale
[ 329951 ] = { 23 , 26.0 , 27.0 , 23.0 , 32.0 , 18.0 , 39.0 , 35.0 } ,
-- Hand of Destruction (P2)
[ 333932 ] = { 42.1 , 41.3 , 40.1 , 56.5 , 19.5 } ,
} ,
[ 3 ] = {
-- Fatal Finesse
[ 332794 ] = { 9.5 , 24 , 25 , 29 , 22 , 34 , 22 , 26 , 32 , 28 } ,
-- Hand of Destruction (P3)
[ 333932 ] = { 64.6 , 76.5 , 94.8 } ,
}
}
local timersHeroic = { -- Heroic confirmed
[ 1 ] = {
-- Night Hunter
[ 327796 ] = { 12 , 26 , 30 , 28 , 30 , 28 } ,
-- Cleansing Pain
[ 326707 ] = { 5.5 , 21.5 , 30.5 , 22 , 29.8 , 22.6 } , -- From _success to _start, so timers are adjusted by -3s for the cast time
} ,
[ 2 ] = {
-- Crimson Cabalist // First ones are up from the start
[ - 22131 ] = { 4 , 85 , 55 } ,
-- Impale
[ 329951 ] = { 23 , 26.0 , 27.0 , 23.0 , 32.0 , 18.0 , 39.0 , 35.0 } ,
-- Hand of Destruction (P2)
[ 333932 ] = { 41.2 , 40.3 , 39.0 , 56.1 , 18.5 , 57.2 } ,
} ,
[ 3 ] = {
-- Fatal Finesse
[ 332794 ] = { 10 , 48 , 6 , 21 , 27 , 19 , 26 , 21 , 40 } ,
-- Hand of Destruction (P3)
[ 333932 ] = { 19.7 , 90.0 , 31.6 , 46.3 } ,
}
}
local timersMythic = {
[ 1 ] = {
-- Night Hunter
[ 327796 ] = { 14 , 25 , 33 , 25 , 33 , 25 } ,
-- Cleansing Pain
[ 326707 ] = { 6 , 21.35 , 29.5 , 22.5 , 29.8 , 22.5 } , -- From _success to _start, so timers are adjusted by -3s for the cast time
} ,
[ 2 ] = {
-- Adds
[ - 22131 ] = { 4 , 75 , 55 } ,
-- Impale
[ 329951 ] = { 43 , 39 , 36 , 45 , 53 } ,
-- Hand of Destruction (P2)
[ 333932 ] = { 38.7 , 31.2 , 39.5 , 44 , 45 } , -- Reduced by 1 second as the pull in happens earlier
} ,
[ 3 ] = {
-- Fatal Finesse
[ 332794 ] = { 19.2 , 22 , 25 , 25 , 38.5 , 33 , 13 , 12 , 13 } ,
-- Shattering Pain
[ 332619 ] = { 5.4 , 25.5 , 21.9 , 24.3 , 24.3 , 25.5 , 22 , 23 , 25 } ,
}
}
local timers = mod : Mythic ( ) and timersMythic or mod : Heroic ( ) and timersHeroic or timersEasy
--------------------------------------------------------------------------------
-- Localization
--
local L = mod : GetLocale ( )
if L then
L.infobox_stacks = " %d |4Stack:Stacks;: %d |4player:players; " -- 4 Stacks: 5 players // 1 Stack: 1 player
L.custom_on_repeating_nighthunter = " Repeating Night Hunter Yell "
L.custom_on_repeating_nighthunter_desc = " Repeating yell messages for the Night Hunter ability using icons {rt1} or {rt2} or {rt3} to find your line easier if you have to soak. "
L.custom_on_repeating_impale = " Repeating Impale Say "
L.custom_on_repeating_impale_desc = " Repeating say messages for the Impale ability using '1' or '22' or '333' or '4444' to make it clear in what order you will be hit. "
L.hymn_stacks = " Nathrian Hymn "
L.hymn_stacks_desc = " Alerts for the amount of Nathrian Hymn stacks currently on you. "
L.hymn_stacks_icon = " 70_inscription_vantus_rune_suramar "
L.ravage_target = " Reflection: Ravage Target Cast Bar "
L.ravage_target_desc = " Cast bar showing the time until the reflection targets a location for Ravage. "
L.ravage_target_icon = " spell_shadow_corpseexplode "
L.ravage_targeted = " Ravage Targeted " -- Text on the bar for when Ravage picks its location to target in stage 3
L.no_mirror = " No Mirror: %d " -- Player amount that does not have the Through the Mirror
L.mirror = " Mirror: %d " -- Player amount that does have the Through the Mirror
end
--------------------------------------------------------------------------------
-- Initialization
--
local nightHunterMarker = mod : AddMarkerOption ( false , " player " , 1 , 327796 , 1 , 2 , 3 ) -- Night Hunter
local impaleMarker = mod : AddMarkerOption ( false , " player " , 1 , 329951 , 1 , 2 , 3 , 4 ) -- Impale
local fatalFinesseMarker = mod : AddMarkerOption ( false , " player " , 1 , 332794 , 1 , 2 , 3 ) -- Fatal Finesse
local balefulShadowsMarker = mod : AddMarkerOption ( true , " npc " , 8 , - 22557 , 8 , 7 ) -- Baleful Shadows
function mod : GetOptions ( )
return {
" stages " ,
-- Stage One: Sinners Be Cleansed
{ 328936 , " TANK " } , -- Inevitable
{ 326699 , " INFOBOX " } , -- Burden of Sin
326707 , -- Cleansing Pain
326851 , -- Blood Price
{ 327039 , " SAY " , " SAY_COUNTDOWN " , " ME_ONLY_EMPHASIZE " } , -- Feeding Time (Normal mode version of Night Hunter)
{ 327796 , " SAY " , " ME_ONLY_EMPHASIZE " } , -- Night Hunter
" custom_on_repeating_nighthunter " ,
nightHunterMarker ,
{ 327227 , " EMPHASIZE " } , -- Command: Ravage
327122 , -- Ravage
327992 , -- Desolation
-- Intermission: March of the Penitent
328276 , -- March of the Penitent
-- Stage Two: The Crimson Chorus
329906 , -- Carnage
{ 329951 , " SAY " , " ME_ONLY_EMPHASIZE " } , -- Impale
" custom_on_repeating_impale " ,
impaleMarker ,
- 22131 , -- Crimson Cabalist
{ 336162 , " FLASH " } , -- Crescendo
335873 , -- Rancor
329181 , -- Wracking Pain
333932 , -- Hand of Destruction
330042 , -- Command: Massacre
-- Stage Three: Indignation
{ 332585 , " TANK " } , -- Scorn
{ 332619 , " EMPHASIZE " } , -- Shattering Pain
{ 332794 , " SAY " , " SAY_COUNTDOWN " } , -- Fatal Finesse
fatalFinesseMarker ,
336008 , -- Smoldering Ire
332849 , -- Reflection: Ravage
" ravage_target " ,
333980 , -- Reflection: Massacre
" hymn_stacks " ,
344776 , -- Vengeful Wail
balefulShadowsMarker ,
{ 338738 , " INFOBOX " } , -- Through the Mirror
333979 , -- Sinister Reflection
} , {
[ " stages " ] = " general " ,
[ 328936 ] = - 22016 , -- Stage One: Sinners Be Cleansed
[ 328276 ] = - 22098 , -- Intermission: March of the Penitent
[ 329906 ] = - 22059 , -- Stage Two: The Crimson Chorus
[ 332585 ] = - 22195 , -- Stage Three: Indignation
[ " hymn_stacks " ] = " mythic " ,
} , {
[ 328936 ] = CL.teleport , -- Inevitable (Teleport)
[ 327039 ] = CL.normal , -- Feeding Time (Normal mode)
[ 327796 ] = CL.heroic .. " / " .. CL.mythic , -- Night Hunter (Heroic mode/Mythic mode)
[ 327227 ] = CL.soon : format ( self : SpellName ( 327122 ) ) , -- Command: Ravage (Ravage soon)
[ 328276 ] = CL.intermission , -- March of the Penitent (Intermission)
[ - 22131 ] = CL.adds , -- Crimson Cabalist (Adds)
[ 332619 ] = CL.knockback , -- Shattering Pain (Knockback)
}
end
function mod : OnBossEnable ( )
self : Log ( " SPELL_AURA_APPLIED " , " EncounterEvent " , 181089 ) -- Crimson Cabalists spawn
self : RegisterEvent ( " PLAYER_STARTED_MOVING " )
self : RegisterEvent ( " PLAYER_STOPPED_MOVING " )
-- Stage One: Sinners Be Cleansed
self : Log ( " SPELL_CAST_SUCCESS " , " Inevitable " , 328936 )
self : Log ( " SPELL_AURA_APPLIED " , " BurdenOfSinStacks " , 326699 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " BurdenOfSinStacks " , 326699 )
self : Log ( " SPELL_AURA_REMOVED_DOSE " , " BurdenOfSinStacks " , 326699 )
self : Log ( " SPELL_AURA_REMOVED " , " BurdenOfSinRemoved " , 326699 )
self : Log ( " SPELL_CAST_START " , " CleansingPain " , 326707 )
self : Log ( " SPELL_CAST_SUCCESS " , " CleansingPainSuccess " , 326707 )
self : Log ( " SPELL_CAST_START " , " BloodPriceStart " , 326851 )
self : Log ( " SPELL_AURA_APPLIED " , " FeedingTimeApplied " , 327039 )
self : Log ( " SPELL_AURA_REMOVED " , " FeedingTimeRemoved " , 327039 )
self : Log ( " SPELL_AURA_APPLIED " , " NightHunterApplied " , 327796 )
self : Log ( " SPELL_AURA_REMOVED " , " NightHunterRemoved " , 327796 )
self : Log ( " SPELL_CAST_START " , " CommandRavage " , 327227 )
self : Log ( " SPELL_CAST_START " , " Ravage " , 327122 )
-- Intermission: March of the Penitent
self : Log ( " SPELL_CAST_START " , " MarchOfThePenitentStart " , 328117 )
-- Stage Two: The Crimson Chorus
self : Log ( " SPELL_CAST_SUCCESS " , " BeginTheChorus " , 329697 )
self : Log ( " SPELL_AURA_APPLIED " , " CarnageApplied " , 329906 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " CarnageApplied " , 329906 )
self : Log ( " SPELL_CAST_SUCCESS " , " Impale " , 329943 )
self : Log ( " SPELL_AURA_APPLIED " , " ImpaleApplied " , 329951 )
self : Log ( " SPELL_AURA_REMOVED " , " ImpaleRemoved " , 329951 )
self : Log ( " SPELL_CAST_START " , " WrackingPain " , 329181 )
self : Log ( " SPELL_AURA_APPLIED " , " WrackingPainApplied " , 329181 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " WrackingPainApplied " , 329181 )
self : Log ( " SPELL_CAST_START " , " HandOfDestruction " , 333932 )
self : Log ( " SPELL_CAST_SUCCESS " , " CommandMassacre " , 330042 )
self : Death ( " AddDeaths " , 169196 , 169470 , 173161 , 173162 , 173163 , 173164 ) -- Crimson Cabalist x2, Lady Sinsear, Lord Evershade, Baron Duskhollow, Countess Gloomveil
-- Stage Three: Indignation
self : Log ( " SPELL_CAST_SUCCESS " , " IndignationSuccess " , 326005 )
self : Log ( " SPELL_AURA_REMOVED " , " IndignationEnd " , 326005 )
self : Log ( " SPELL_AURA_APPLIED " , " ScornApplied " , 332585 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " ScornApplied " , 332585 )
self : Log ( " SPELL_CAST_SUCCESS " , " ShatteringPain " , 332619 )
self : Log ( " SPELL_AURA_APPLIED " , " FatalFinesseApplied " , 332794 )
self : Log ( " SPELL_AURA_REMOVED " , " FatalFinesseRemoved " , 332794 )
self : Log ( " SPELL_CAST_SUCCESS " , " ReflectionRavage " , 332849 )
self : Log ( " SPELL_CAST_SUCCESS " , " ReflectionMassacre " , 333980 )
self : Log ( " SPELL_AURA_APPLIED " , " GroundDamage " , 327992 , 335873 ) -- Desolation, Rancor
self : Log ( " SPELL_PERIODIC_DAMAGE " , " GroundDamage " , 327992 , 335873 )
self : Log ( " SPELL_PERIODIC_MISSED " , " GroundDamage " , 327992 , 335873 )
-- Mythic
self : Log ( " SPELL_AURA_APPLIED " , " HymnApplied " , 338685 , 338689 , 338687 , 338683 ) -- Evershade, Gloomveil, Duskhollow, Sinsear
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " HymnApplied " , 338685 , 338689 , 338687 , 338683 )
self : Log ( " SPELL_AURA_REMOVED " , " HymnRemoved " , 338685 , 338689 , 338687 , 338683 )
self : Log ( " SPELL_CAST_START " , " VengefulWail " , 344776 )
self : Log ( " SPELL_AURA_APPLIED " , " ThroughtheMirror " , 338738 )
self : Log ( " SPELL_AURA_REMOVED " , " ThroughtheMirrorRemoved " , 338738 )
self : Log ( " SPELL_CAST_SUCCESS " , " SinisterReflection " , 333979 )
end
function mod : VerifyEnable ( unit )
if self : GetHealth ( unit ) > 5 then
return true
end
end
function mod : OnEngage ( )
timers = self : Mythic ( ) and timersMythic or self : Heroic ( ) and timersHeroic or timersEasy
intermission = nil
nextStageWarning = 73
isMoving = false
self : SetStage ( 1 )
cleansingPainCount = 1
bloodPriceCount = 1
nightHunterCount = 1
ravageCount = 1
addCount = 1
balefulShadowsList = { }
mobCollector = { }
balefulShadowCount = 1
burdenStackTable = {
[ 0 ] = 0 ,
[ 1 ] = 0 ,
[ 2 ] = 0 ,
[ 3 ] = 0 ,
[ 4 ] = 0 ,
[ 5 ] = 0 ,
[ 6 ] = 0 ,
}
burdenPlayerTracker = { }
burdenStacksOnMe = 0
self : Bar ( 326707 , timers [ 1 ] [ 326707 ] [ cleansingPainCount ] , CL.count : format ( self : SpellName ( 326707 ) , cleansingPainCount ) ) -- Cleansing Pain
self : Bar ( 326851 , 23 , CL.count : format ( self : SpellName ( 326851 ) , bloodPriceCount ) ) -- Blood Price
if self : Easy ( ) then
self : Bar ( 327039 , timers [ 1 ] [ 327039 ] [ nightHunterCount ] , CL.count : format ( self : SpellName ( 327039 ) , nightHunterCount ) ) -- Feeding Time
else
self : Bar ( 327796 , timers [ 1 ] [ 327796 ] [ nightHunterCount ] , CL.count : format ( self : SpellName ( 327796 ) , nightHunterCount ) ) -- Night Hunter
end
self : Bar ( 327122 , 53 , CL.count : format ( self : SpellName ( 327122 ) , ravageCount ) ) -- Ravage
self : RegisterUnitEvent ( " UNIT_HEALTH " , nil , " boss1 " )
self : OpenInfo ( 326699 , self : SpellName ( 326699 ) ) -- Burden of Sin
end
--------------------------------------------------------------------------------
-- Event Handlers
--
function mod : PLAYER_STARTED_MOVING ( )
isMoving = true
end
function mod : PLAYER_STOPPED_MOVING ( )
isMoving = false
end
do
local prev , prevFlash = 0 , 0
local function crescendoMessage ( )
if UnitIsDead ( " player " ) then return end
mod : PersonalMessage ( 336162 , " underyou " )
local t = GetTime ( )
if t - prevFlash > 1.5 and not isMoving then
prevFlash = t
mod : PlaySound ( 336162 , " warning " ) -- Not using underyou as sound, you're not standing in something
mod : Flash ( 336162 )
end
end
function mod : AddDeaths ( args )
local t = args.time
if t - prev > 0.3 then
prev = t
if not self : Easy ( ) then
self : SimpleTimer ( crescendoMessage , 2 )
end
end
end
end
function mod : EncounterEvent ( args ) -- Crimson Cabalists spawn
self : Message ( - 22131 , " yellow " , CL.incoming : format ( CL.count : format ( CL.adds , addCount ) ) , 329711 ) -- Crimson Chorus Icon
self : PlaySound ( - 22131 , " alert " )
addCount = addCount + 1
self : Bar ( - 22131 , timers [ self : GetStage ( ) ] [ - 22131 ] [ addCount ] , CL.count : format ( CL.adds , addCount ) , 329711 ) -- Crimson Chorus Icon
end
function mod : UNIT_HEALTH ( event , unit )
if self : GetHealth ( unit ) < nextStageWarning then -- Stage changes at 70% and 40%
local nextStage = self : GetStage ( ) == 1 and CL.intermission or CL.stage : format ( 3 )
self : Message ( " stages " , " green " , CL.soon : format ( nextStage ) , false )
nextStageWarning = nextStageWarning - ( self : Mythic ( ) and 33 or 30 )
if nextStageWarning < 30 then
self : UnregisterUnitEvent ( event , unit )
end
end
end
function mod : Inevitable ( args )
self : Message ( args.spellId , " cyan " , CL.teleport )
self : PlaySound ( args.spellId , " info " )
end
do
local playerName = mod : UnitName ( " player " )
local scheduled = nil
function mod : UpdateInfoBox ( )
-- Empty first
self : SetInfo ( 326699 , 1 , " " )
self : SetInfo ( 326699 , 2 , " " )
self : SetInfo ( 326699 , 3 , " " )
self : SetInfo ( 326699 , 4 , " " )
self : SetInfo ( 326699 , 5 , " " )
self : SetInfo ( 326699 , 6 , " " )
self : SetInfo ( 326699 , 7 , " " )
self : SetInfo ( 326699 , 8 , " " )
self : SetInfo ( 326699 , 9 , " " )
self : SetInfo ( 326699 , 10 , " " )
-- count the raid size so we can colour accordingly
local playersAlive = 0
for unit in self : IterateGroup ( ) do
local name = self : UnitName ( unit )
if name and not UnitIsDead ( unit ) then
playersAlive = playersAlive + 1
end
end
if playersAlive == 0 then return end -- wipe
-- Lets show the info
local lineCount = 1
for i = 6 , 1 , - 1 do
if burdenStackTable [ i ] and burdenStackTable [ i ] > 0 then
if lineCount == 11 then -- bail out
return
end
local percentOfRaid = burdenStackTable [ i ] / playersAlive
local color = percentOfRaid > 0.6 and " |cffff0000 " or percentOfRaid < 0.3 and " |cff00ff00 " or " |cffffff00 "
local lineText = color .. L.infobox_stacks : format ( i , burdenStackTable [ i ] ) .. " |r "
if i == burdenStacksOnMe then
lineText = " |cff3366ff>>|r " .. lineText .. " |cff3366ff<<|r "
end
self : SetInfo ( 326699 , lineCount , lineText )
lineCount = lineCount + 2
end
end
end
function mod : BurdenOfSinStackMessage ( )
mod : NewStackMessage ( 326699 , " blue " , playerName , burdenStacksOnMe )
mod : PlaySound ( 326699 , " alarm " )
scheduled = nil
end
function mod : BurdenOfSinStacks ( args )
local oldValue = burdenPlayerTracker [ args.destName ]
if oldValue then
burdenStackTable [ oldValue ] = burdenStackTable [ oldValue ] - 1
end
local _ , amount = self : UnitDebuff ( args.destName , args.spellId ) -- no amount in the event, checking ourselves
amount = amount or self : Mythic ( ) and 6 or self : Heroic ( ) and 5 or 4 -- Can rarely be nil on engage
burdenPlayerTracker [ args.destName ] = amount
burdenStackTable [ amount ] = burdenStackTable [ amount ] + 1
if self : Me ( args.destGUID ) then
burdenStacksOnMe = amount
if not scheduled then
scheduled = self : ScheduleTimer ( " BurdenOfSinStackMessage " , 0.1 )
end
end
mod : UpdateInfoBox ( )
end
function mod : BurdenOfSinRemoved ( args )
if scheduled then
self : CancelTimer ( scheduled )
scheduled = nil
end
local oldValue = burdenPlayerTracker [ args.destName ]
burdenStackTable [ oldValue ] = burdenStackTable [ oldValue ] - 1
burdenStackTable [ 0 ] = burdenStackTable [ 0 ] + 1
burdenPlayerTracker [ args.destName ] = 0
if self : Me ( args.destGUID ) then
burdenStacksOnMe = 0
self : Message ( args.spellId , intermission and " green " or " red " , CL.removed : format ( args.spellName ) )
self : PlaySound ( args.spellId , intermission and " info " or " warning " )
end
mod : UpdateInfoBox ( )
end
function mod : BloodPriceStart ( args )
if self : GetStage ( ) == 3 then -- Mythic, Depends on phasing not stacks
self : Message ( args.spellId , " red " )
else
self : NewStackMessage ( args.spellId , " blue " , playerName , burdenStackTable [ burdenStacksOnMe ] )
end
self : PlaySound ( args.spellId , " alarm " )
bloodPriceCount = bloodPriceCount + 1
if self : GetStage ( ) == 3 and bloodPriceCount < 4 then -- Mythic, only 3x in stage 3
self : Bar ( args.spellId , 72 , CL.count : format ( args.spellName , bloodPriceCount ) )
elseif self : GetStage ( ) == 1 and bloodPriceCount < 4 then -- Only 3x in stage 1
self : Bar ( args.spellId , 58 , CL.count : format ( args.spellName , bloodPriceCount ) )
end
end
end
function mod : CleansingPain ( args )
self : Message ( args.spellId , " purple " , CL.count : format ( args.spellName , cleansingPainCount ) )
self : PlaySound ( args.spellId , " alert " )
end
function mod : CleansingPainSuccess ( args )
cleansingPainCount = cleansingPainCount + 1
self : Bar ( args.spellId , timers [ self : GetStage ( ) ] [ args.spellId ] [ cleansingPainCount ] , CL.count : format ( args.spellName , cleansingPainCount ) )
end
do
local prev = 0
function mod : FeedingTimeApplied ( args )
local t = args.time
if t - prev > 5 then
prev = t
self : Message ( args.spellId , " orange " , CL.count : format ( args.spellName , nightHunterCount ) )
nightHunterCount = nightHunterCount + 1
self : Bar ( args.spellId , timers [ self : GetStage ( ) ] [ args.spellId ] [ nightHunterCount ] , CL.count : format ( args.spellName , nightHunterCount ) )
end
if self : Me ( args.destGUID ) then
self : PersonalMessage ( args.spellId )
self : Say ( args.spellId )
self : SayCountdown ( args.spellId , 5 )
self : PlaySound ( args.spellId , " warning " )
end
end
end
function mod : FeedingTimeRemoved ( args )
if self : Me ( args.destGUID ) then
self : CancelSayCountdown ( args.spellId )
end
end
do
local playerList = { }
local prev = 0
function mod : NightHunterApplied ( args )
local t = args.time
if t - prev > 5 then
prev = t
playerList = { }
self : PlaySound ( args.spellId , " warning " )
self : CastBar ( args.spellId , 6 , CL.count : format ( args.spellName , nightHunterCount ) )
nightHunterCount = nightHunterCount + 1
self : Bar ( args.spellId , timers [ self : GetStage ( ) ] [ args.spellId ] [ nightHunterCount ] , CL.count : format ( args.spellName , nightHunterCount ) )
end
local count = # playerList + 1
playerList [ count ] = args.destName
playerList [ args.destName ] = count -- Set raid marker
if self : Me ( args.destGUID ) then
self : Yell ( args.spellId , CL.count_rticon : format ( args.spellName , count , count ) )
if self : GetOption ( " custom_on_repeating_nighthunter " ) then
local text = ( " {rt%d}{rt%d}{rt%d} " ) : format ( count , count , count )
self : YellCountdown ( false , 6 , text , 4 )
end
end
self : NewTargetsMessage ( args.spellId , " orange " , playerList , self : Mythic ( ) and 3 or 2 , CL.count : format ( args.spellName , nightHunterCount - 1 ) )
self : CustomIcon ( nightHunterMarker , args.destName , count )
end
function mod : NightHunterRemoved ( args )
if self : Me ( args.destGUID ) and self : GetOption ( " custom_on_repeating_nighthunter " ) then
self : CancelYellCountdown ( false )
end
self : CustomIcon ( nightHunterMarker , args.destName )
end
end
function mod : CommandRavage ( args ) -- Pre-warning
self : Message ( args.spellId , " yellow " , CL.soon : format ( self : SpellName ( 327122 ) ) , 327122 )
self : PlaySound ( args.spellId , " alert " )
end
function mod : Ravage ( args )
self : Message ( args.spellId , " orange " , CL.count : format ( args.spellName , ravageCount ) )
self : PlaySound ( args.spellId , " alert " )
self : CastBar ( args.spellId , 6 , CL.count : format ( args.spellName , ravageCount ) )
ravageCount = ravageCount + 1
if ravageCount < 4 then
self : Bar ( args.spellId , self : Mythic ( ) and 58.4 or 58 , CL.count : format ( args.spellName , ravageCount ) )
end
end
-- Intermission: March of the Penitent
function mod : MarchOfThePenitentStart ( args )
self : SetStage ( 2 )
intermission = true
self : Message ( 328276 , " green " , CL.percent : format ( 70 , args.spellName ) , false )
self : PlaySound ( 328276 , " long " )
self : Bar ( 328276 , 16.5 , CL.intermission ) -- 1.5s precast, 15s channel
self : StopBar ( CL.count : format ( self : SpellName ( 326707 ) , cleansingPainCount ) ) -- Cleansing Pain
self : StopBar ( CL.count : format ( self : SpellName ( 326851 ) , bloodPriceCount ) ) -- Blood Price
self : StopBar ( CL.count : format ( self : SpellName ( 327039 ) , nightHunterCount ) ) -- Feeding Time
self : StopBar ( CL.count : format ( self : SpellName ( 327796 ) , nightHunterCount ) ) -- Night Hunter
self : StopBar ( CL.count : format ( self : SpellName ( 327122 ) , ravageCount ) ) -- Ravage
self : StopBar ( CL.cast : format ( CL.count : format ( self : SpellName ( 327122 ) , ravageCount - 1 ) ) ) -- Casting: Ravage
end
-- Stage Two: The Crimson Chorus
function mod : BeginTheChorus ( args )
intermission = nil
self : CloseInfo ( 326699 )
self : Message ( " stages " , " green " , CL.stage : format ( 2 ) , false )
self : PlaySound ( " stages " , " long " )
impaleCount = 1
wrackingPainCount = 1
handCount = 1
massacreCount = 1
addCount = 1
balefulShadowCount = 1
ravageCount = 1
self : Bar ( - 22131 , timers [ 2 ] [ - 22131 ] [ addCount ] , CL.count : format ( CL.adds , addCount ) , 329711 ) -- Adds // Crimson Chorus Icon
self : Bar ( 329951 , timers [ 2 ] [ 329951 ] [ impaleCount ] , CL.count : format ( self : SpellName ( 329951 ) , impaleCount ) ) -- Impale
self : Bar ( 329181 , 15.7 , CL.count : format ( self : SpellName ( 329181 ) , wrackingPainCount ) ) -- Wracking Pain
self : Bar ( 333932 , timers [ 2 ] [ 333932 ] [ handCount ] , CL.count : format ( self : SpellName ( 333932 ) , handCount ) ) -- Hand of Destruction
self : Bar ( 330042 , self : Mythic ( ) and 55 or 62 , CL.count : format ( self : SpellName ( 330068 ) , massacreCount ) , 333980 ) -- Massacre
self : Bar ( " stages " , self : Mythic ( ) and 229 or 214 , CL.stage : format ( 3 ) , 338738 ) -- Stage 3
balefulShadowsList = { }
mobCollector = { }
if self : GetOption ( balefulShadowsMarker ) and self : Mythic ( ) then -- Mythic only mechanic
self : RegisterTargetEvents ( " BalefulShadowsMarker " )
end
end
function mod : CarnageApplied ( args )
if self : Me ( args.destGUID ) then
self : NewStackMessage ( args.spellId , " blue " , args.destName , args.amount )
self : PlaySound ( args.spellId , " alarm " )
elseif args.amount and args.amount % 2 == 0 and self : Tank ( ) and self : Tank ( args.destName ) then
self : NewStackMessage ( args.spellId , " purple " , args.destName , args.amount )
end
end
do
local playerList = { }
local sayTimer = nil
function mod : Impale ( args )
playerList = { }
impaleCount = impaleCount + 1
self : Bar ( 329951 , timers [ self : GetStage ( ) ] [ 329951 ] [ impaleCount ] , CL.count : format ( args.spellName , impaleCount ) )
end
local sayMessages = { " 1 " , " 22 " , " 333 " , " 4444 " }
function mod : ImpaleApplied ( args )
local count = # playerList + 1
playerList [ count ] = args.destName
playerList [ args.destName ] = count -- Set raid marker
if self : Me ( args.destGUID ) then
self : Say ( args.spellId , CL.count : format ( args.spellName , count ) )
if self : GetOption ( " custom_on_repeating_impale " ) then
local msg = sayMessages [ count ]
sayTimer = self : ScheduleRepeatingTimer ( " Say " , 1.5 , false , msg , true )
end
self : PlaySound ( args.spellId , " warning " )
end
self : NewTargetsMessage ( args.spellId , " orange " , playerList , self : Mythic ( ) and 4 or 3 , CL.count : format ( args.spellName , impaleCount - 1 ) , nil , 2 ) -- debuffs are late
self : CustomIcon ( impaleMarker , args.destName , count )
end
function mod : ImpaleRemoved ( args )
if self : Me ( args.destGUID ) then
if sayTimer then
self : CancelTimer ( sayTimer )
sayTimer = nil
end
end
self : CustomIcon ( impaleMarker , args.destName )
end
end
function mod : WrackingPain ( args )
self : Message ( args.spellId , " yellow " , CL.casting : format ( CL.count : format ( args.spellName , wrackingPainCount ) ) )
self : PlaySound ( args.spellId , " alert " )
wrackingPainCount = wrackingPainCount + 1
if not self : Mythic ( ) or wrackingPainCount < 12 then -- Only 11 in stage 2 for Mythic
self : CDBar ( args.spellId , self : Mythic ( ) and ( wrackingPainCount == 4 and 17 or wrackingPainCount == 9 and 17 or 18.2 ) or 20 , CL.count : format ( args.spellName , wrackingPainCount ) )
end
end
function mod : WrackingPainApplied ( args )
if self : Tank ( args.destName ) and self : Tank ( ) then
local amount = args.amount or 1
if amount == 1 then
self : TargetMessage ( args.spellId , " purple " , args.destName )
else
self : NewStackMessage ( args.spellId , " purple " , args.destName , amount )
end
self : PlaySound ( args.spellId , " warning " , args.destName )
end
end
function mod : HandOfDestruction ( args )
self : Message ( args.spellId , " orange " , CL.casting : format ( CL.count : format ( args.spellName , handCount ) ) )
self : PlaySound ( args.spellId , " warning " )
self : CastBar ( args.spellId , 6 , CL.count : format ( args.spellName , handCount ) )
handCount = handCount + 1
self : Bar ( args.spellId , timers [ self : GetStage ( ) ] [ args.spellId ] [ handCount ] , CL.count : format ( args.spellName , handCount ) )
end
function mod : CommandMassacre ( args )
self : Message ( args.spellId , " red " , CL.count : format ( self : SpellName ( 330068 ) , massacreCount ) , 333980 )
self : PlaySound ( args.spellId , " alarm " )
massacreCount = massacreCount + 1
if not self : Mythic ( ) or massacreCount < 5 then -- Only 4 in stage 2 for Mythic
self : Bar ( args.spellId , self : Mythic ( ) and 44 or 50 , CL.count : format ( self : SpellName ( 330068 ) , massacreCount ) , 333980 )
end
end
-- Stage Three: Indignation
function mod : IndignationSuccess ( args ) -- not setting stage yet, incase some spells triggered the second you transition
self : UnregisterUnitEvent ( " UNIT_HEALTH " , " boss1 " ) -- Safety
self : Message ( " stages " , " green " , CL.stage : format ( 3 ) , false )
self : PlaySound ( " stages " , " long " )
self : StopBar ( CL.count : format ( self : SpellName ( 329951 ) , impaleCount ) ) -- Impale
self : StopBar ( CL.count : format ( self : SpellName ( 329181 ) , wrackingPainCount ) ) -- Wracking Pain
self : StopBar ( CL.count : format ( self : SpellName ( 333932 ) , handCount ) ) -- Hand of Destruction
self : StopBar ( CL.count : format ( self : SpellName ( 330137 ) , massacreCount ) ) -- Massacre
self : StopBar ( CL.count : format ( CL.adds , addCount ) ) -- Adds
self : StopBar ( CL.stage : format ( 3 ) ) -- Stage 3
if self : Mythic ( ) then
mirrorList = { }
mirrorCount = 0
self : OpenInfo ( 338738 , self : SpellName ( 338738 ) ) -- Through the Mirror
end
end
function mod : IndignationEnd ( args )
if self : GetOption ( balefulShadowsMarker ) then
self : UnregisterTargetEvents ( )
end
self : SetStage ( 3 )
-- These spells could have triggered right after the channel started
self : StopBar ( CL.count : format ( self : SpellName ( 329951 ) , impaleCount ) ) -- Impale
self : StopBar ( CL.count : format ( self : SpellName ( 333932 ) , handCount ) ) -- Hand of Destruction
self : StopBar ( CL.count : format ( self : SpellName ( 330137 ) , massacreCount ) ) -- Massacre
handCount = 1
shatteringPainCount = 1
fatalFinesseCount = 1
massacreCount = 1
ravageCount = 1
bloodPriceCount = 1
self : Bar ( 332619 , self : Mythic ( ) and 5.4 or 6 , CL.count : format ( CL.knockback , shatteringPainCount ) ) -- Shattering Pain
self : Bar ( 332794 , timers [ self : GetStage ( ) ] [ 332794 ] [ fatalFinesseCount ] , CL.count : format ( self : SpellName ( 332794 ) , fatalFinesseCount ) ) -- Fatal Finesse
if self : Mythic ( ) then
self : Bar ( 326851 , 12.6 , CL.count : format ( self : SpellName ( 326851 ) , bloodPriceCount ) ) -- Blood Price
self : Bar ( 333979 , 62 , CL.count : format ( self : SpellName ( 333979 ) , ravageCount ) ) -- Sinister Reflection (Reuse ravageCount for Mythic)
else
self : Bar ( 332849 , 42 , CL.count : format ( self : SpellName ( 332937 ) , ravageCount ) )
self : Bar ( 333932 , timers [ self : GetStage ( ) ] [ 333932 ] [ handCount ] , CL.count : format ( self : SpellName ( 333932 ) , handCount ) ) -- Hand of Destruction
end
end
function mod : ScornApplied ( args )
local amount = args.amount or 1
if amount % 3 == 0 or ( amount > 6 and amount < 12 ) then -- 3, 6-12, 15/18/21... (throttle)
self : NewStackMessage ( args.spellId , " purple " , args.destName , amount , 6 )
if amount > 5 then
self : PlaySound ( args.spellId , " alert " )
end
end
end
function mod : ShatteringPain ( args )
self : Message ( args.spellId , " orange " , CL.count : format ( CL.knockback , shatteringPainCount ) )
self : PlaySound ( args.spellId , " warning " )
shatteringPainCount = shatteringPainCount + 1
self : Bar ( args.spellId , self : Mythic ( ) and timers [ 3 ] [ args.spellId ] [ shatteringPainCount ] or 24 , CL.count : format ( CL.knockback , shatteringPainCount ) )
end
do
local playerList , sphereSpawned = { } , false
local prev = 0
function mod : FatalFinesseApplied ( args )
local t = args.time
if t - prev > 3 then
prev = t
playerList = { }
sphereSpawned = false
fatalFinesseCount = fatalFinesseCount + 1
self : Bar ( args.spellId , timers [ self : GetStage ( ) ] [ args.spellId ] [ fatalFinesseCount ] , CL.count : format ( args.spellName , fatalFinesseCount ) )
end
local count = # playerList + 1
playerList [ count ] = args.destName
playerList [ args.destName ] = count
if self : Me ( args.destGUID ) then
self : Say ( args.spellId , CL.count_rticon : format ( args.spellName , count , count ) )
self : SayCountdown ( args.spellId , 5 , count )
self : PlaySound ( args.spellId , " warning " )
end
self : NewTargetsMessage ( args.spellId , " orange " , playerList , 3 , CL.count : format ( args.spellName , fatalFinesseCount - 1 ) )
self : CustomIcon ( fatalFinesseMarker , args.destName , count )
end
function mod : FatalFinesseRemoved ( args )
self : CustomIcon ( fatalFinesseMarker , args.destName )
if self : Me ( args.destGUID ) then
self : CancelSayCountdown ( args.spellId )
end
if not sphereSpawned then
sphereSpawned = true
self : CastBar ( 336008 , 10 ) -- Smoldering Ire
end
end
end
function mod : ReflectionRavage ( args )
self : Message ( args.spellId , " orange " , CL.count : format ( self : SpellName ( 332937 ) , ravageCount ) )
self : PlaySound ( args.spellId , " long " )
self : CastBar ( " ravage_target " , 3 , L.ravage_targeted , args.spellId )
self : CastBar ( args.spellId , 9 ) -- 6s cast + 3s before he starts it
ravageCount = ravageCount + 1
self : Bar ( 333980 , 40 , CL.count : format ( self : SpellName ( 330068 ) , massacreCount ) ) -- Massacre // Alternates with Ravage
end
function mod : ReflectionMassacre ( args )
self : Message ( args.spellId , " red " , CL.count : format ( self : SpellName ( 330068 ) , massacreCount ) )
self : PlaySound ( args.spellId , " long " )
massacreCount = massacreCount + 1
self : Bar ( 332849 , 40 , CL.count : format ( self : SpellName ( 332937 ) , ravageCount ) ) -- Ravage // Alternates with Massacre
end
do
local prev = 0
function mod : GroundDamage ( args )
if self : Me ( args.destGUID ) and ravageCount < 4 then -- Reset ravageCount at start of stage 2 so Rancor is not affected
local t = args.time
if t - prev > 2 then
prev = t
self : PlaySound ( args.spellId , " underyou " )
self : PersonalMessage ( args.spellId , " underyou " )
end
end
end
end
-- Mythic
function mod : HymnApplied ( args )
if self : Me ( args.destGUID ) then
local amount = args.amount or 1
if amount % 2 == 0 and amount > 7 then -- 7+ every 2
self : NewStackMessage ( " hymn_stacks " , " blue " , args.destName , amount , 10 , args.spellId )
if amount > 9 then
self : PlaySound ( " hymn_stacks " , " alert " )
end
end
end
end
function mod : HymnRemoved ( args )
if self : Me ( args.destGUID ) then
self : Message ( " hymn_stacks " , " green " , CL.removed : format ( args.spellName ) , args.spellId )
self : PlaySound ( " hymn_stacks " , " info " )
end
end
function mod : VengefulWail ( args )
local canDo , ready = self : Interrupter ( args.sourceGUID )
if canDo then
self : Message ( args.spellId , " yellow " )
if ready then
self : PlaySound ( args.spellId , " alarm " )
end
end
if self : GetOption ( balefulShadowsMarker ) and not mobCollector [ args.sourceGUID ] then
mobCollector [ args.sourceGUID ] = true
balefulShadowsList [ args.sourceGUID ] = 9 - balefulShadowCount
balefulShadowCount = balefulShadowCount + 1
for k , v in pairs ( balefulShadowsList ) do
local unit = self : GetUnitIdByGUID ( k )
if unit then
self : CustomIcon ( balefulShadowsMarker , unit , balefulShadowsList [ k ] )
balefulShadowsList [ k ] = nil
end
end
end
end
function mod : BalefulShadowsMarker ( event , unit , guid )
if self : MobId ( guid ) == 175205 and balefulShadowsList [ guid ] then -- Conjured Manifestation
self : CustomIcon ( balefulShadowsMarker , unit , balefulShadowsList [ guid ] )
balefulShadowsList [ guid ] = nil
end
end
do
local mirrorOnMe = false
function mod : UpdateInfoBoxStage3 ( )
-- Empty first
self : SetInfo ( 338738 , 1 , " " )
self : SetInfo ( 338738 , 2 , " " )
self : SetInfo ( 338738 , 3 , " " )
self : SetInfo ( 338738 , 4 , " " )
self : SetInfo ( 338738 , 5 , " " )
self : SetInfo ( 338738 , 6 , " " )
self : SetInfo ( 338738 , 7 , " " )
self : SetInfo ( 338738 , 8 , " " )
self : SetInfo ( 338738 , 9 , " " )
self : SetInfo ( 338738 , 10 , " " )
-- count the raid size so we can colour accordingly
local playersAlive = 0
for unit in self : IterateGroup ( ) do
local name = self : UnitName ( unit )
if name and not UnitIsDead ( unit ) then
playersAlive = playersAlive + 1
end
end
if playersAlive == 0 then return end -- wipe
-- Lets show the info
local percentOfRaid = mirrorCount / playersAlive
local color = percentOfRaid > 0.6 and " |cffff0000 " or " |cff00ff00 "
local lineText = color .. L.mirror : format ( mirrorCount ) .. " |r "
if mirrorOnMe then
lineText = " |cff3366ff>>|r " .. lineText .. " |cff3366ff<<|r "
end
self : SetInfo ( 338738 , 1 , lineText )
color = percentOfRaid < 0.6 and " |cffff0000 " or " |cff00ff00 "
local noMirrorCount = playersAlive - mirrorCount
lineText = color .. L.no_mirror : format ( noMirrorCount ) .. " |r "
if not mirrorOnMe then
lineText = " |cff3366ff>>|r " .. lineText .. " |cff3366ff<<|r "
end
self : SetInfo ( 338738 , 3 , lineText )
end
function mod : ThroughtheMirror ( args )
if self : Me ( args.destGUID ) then
mirrorOnMe = true
self : Message ( args.spellId , " green " , CL.you : format ( args.spellName ) )
self : PlaySound ( args.spellId , " info " )
end
if self : Player ( args.destFlags ) and not mirrorList [ args.destName ] then
mirrorList [ args.destName ] = true
mirrorCount = mirrorCount + 1
mod : UpdateInfoBoxStage3 ( )
end
end
function mod : ThroughtheMirrorRemoved ( args )
if self : Me ( args.destGUID ) then
mirrorOnMe = false
self : Message ( args.spellId , " green " , CL.removed : format ( args.spellName ) )
self : PlaySound ( args.spellId , " info " )
end
if self : Player ( args.destFlags ) and mirrorList [ args.destName ] then
mirrorList [ args.destName ] = nil
mirrorCount = mirrorCount - 1
mod : UpdateInfoBoxStage3 ( )
end
end
end
function mod : SinisterReflection ( args )
self : Message ( args.spellId , " red " )
self : PlaySound ( args.spellId , " warning " )
self : CastBar ( " ravage_target " , 3 , L.ravage_targeted , args.spellId )
self : CastBar ( args.spellId , 9 , CL.count : format ( self : SpellName ( 332937 ) , ravageCount ) , 332937 ) -- 6s cast + 3s before he starts it
ravageCount = ravageCount + 1
self : Bar ( args.spellId , 59.7 , CL.count : format ( args.spellName , ravageCount ) )
end