--------------------------------------------------------------------------------
-- Module Declaration
--
local mod , CL = BigWigs : NewBoss ( " Lady Inerva Darkvein " , 2296 , 2420 )
if not mod then return end
mod : RegisterEnableMob ( 165521 ) -- Lady Inerva Darkvein
mod : SetEncounterID ( 2406 )
mod : SetRespawnTime ( 30 )
--------------------------------------------------------------------------------
-- Locals
--
local anima = { }
local concentratedAnimaCount = 1
local conjuredManifestationList = { }
local mobCollector = { }
local conjuredManifestationCount = 1
local enabledContainer = 0 -- 1: Desires, 2: Bottles, 3: Sins, 4: Adds
--------------------------------------------------------------------------------
-- Localization
--
local L = mod : GetLocale ( )
if L then
L.times = " %dx %s "
L.level = " %s (Level |cffffff00%d|r) "
L.full = " %s (|cffff0000FULL|r) "
L.anima_adds = " Concentrated Anima Adds "
L.anima_adds_desc = " Show a timer for when adds spawn from the Concentrated Anima debuffs. "
L.custom_off_experimental = " Enable experimental features "
L.custom_off_experimental_desc = " These features are |cffff0000not tested|r and could |cffff0000spam|r. "
L.anima_tracking = " Anima Tracking |cffff0000(Experimental)|r "
L.anima_tracking_desc = " Messages and Bars to track anima levels in the containers.|n|cffaaff00Tip: You might want to disable the information box or bars, depending your preference. "
L.anima_tracking_icon = " achievement_boss_darkanimus "
L.custom_on_stop_timers = " Always show ability bars "
L.custom_on_stop_timers_desc = " Just for testing right now "
L.desires = " Desires "
L.bottles = " Bottles "
L.sins = " Sins "
end
--------------------------------------------------------------------------------
-- Initialization
--
local sharedSufferingMarker = mod : AddMarkerOption ( false , " player " , 1 , 324983 , 1 , 2 , 3 ) -- Shared Suffering
local concentratedAnimaMarker = mod : AddMarkerOption ( false , " player " , 8 , 332664 , 8 , 7 , 6 ) -- Concentrated Anima
local conjuredManifestationMarker = mod : AddMarkerOption ( true , " npc " , 8 , - 22618 , 8 , 7 ) -- Conjured Manifestation
function mod : GetOptions ( )
return {
" custom_off_experimental " ,
{ " anima_tracking " , " INFOBOX " } ,
" custom_on_stop_timers " ,
331870 , -- Focus Anima
-- Container of Desire
{ 341621 , " TANK_HEALER " } , -- Expose Desires
{ 325382 , " TANK " } , -- Warped Desires
{ 340452 , " SAY " , " SAY_COUNTDOWN " , " ME_ONLY " , " ME_ONLY_EMPHASIZE " } , -- Change of Heart
325936 , -- Shared Cognition
-- Container of Bottled Anima
325769 , -- Bottled Anima
325713 , -- Lingering Anima
-- Container of Sin
{ 324983 , " SAY " , " ME_ONLY_EMPHASIZE " } , -- Shared Suffering
sharedSufferingMarker ,
-- Container of Concentrated Anima
{ 332664 , " SAY " , " SAY_COUNTDOWN " , " PROXIMITY " } , -- Concentrated Anima
" anima_adds " ,
concentratedAnimaMarker ,
conjuredManifestationMarker ,
{ 331573 , " ME_ONLY " } , -- Unconscionable Guilt
331550 , -- Condemn
} , {
[ 331870 ] = " general " ,
[ 325379 ] = - 22571 , -- Container of Desire
[ 325769 ] = - 22592 , -- Container of Bottled Anima
[ 324983 ] = - 22599 , -- Container of Sin
[ 332664 ] = - 22567 , -- Container of Concentrated Anima
} , {
[ 340452 ] = CL.bomb , -- Change of Heart (Bomb)
[ 341621 ] = L.desires , -- Expose Desires (Desires)
[ 325769 ] = L.bottles , -- Bottled Anima (Bottles)
[ 324983 ] = L.sins , -- Shared Suffering (Sins)
[ 332664 ] = CL.adds , -- Concentrated Anima (Adds)
}
end
function mod : OnBossEnable ( )
self : RegisterEvent ( " UPDATE_UI_WIDGET " , " WIDGET " ) -- need to fix BossPrototype implementation before using mod:RegisterWidgetEvent
self : RegisterMessage ( " BigWigs_BarCreated " , " BarCreated " )
-- General
self : RegisterUnitEvent ( " UNIT_SPELLCAST_SUCCEEDED " , nil , " boss1 " )
-- Container of Desire
self : Log ( " SPELL_CAST_START " , " ExposeDesires " , 341621 , 341623 , 341625 ) -- Expose Desires, Expose Cognition, Expose Heart // Each stage of the empowerment.
self : Log ( " SPELL_AURA_APPLIED " , " WarpedDesiresApplied " , 325382 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " WarpedDesiresApplied " , 325382 )
self : Log ( " SPELL_AURA_APPLIED " , " SharedCognitionApplied " , 325936 )
self : Log ( " SPELL_AURA_REMOVED " , " SharedCognitionRemoved " , 325936 )
self : Log ( " SPELL_AURA_APPLIED " , " ChangeOfHeartApplied " , 340452 )
self : Log ( " SPELL_AURA_REMOVED " , " ChangeOfHeartRemoved " , 340452 )
-- Container of Bottled Anima
self : Log ( " SPELL_CAST_START " , " BottledAnima " , 342280 , 342281 , 342282 ) -- Bottled Anima, Lingering Anima, Replicating Anima
-- Container of Sin
self : Log ( " SPELL_AURA_APPLIED " , " SharedSufferingPreDebuffApplied " , 355553 ) -- Shared Suffering Pre-Debuff
self : Log ( " SPELL_AURA_REMOVED " , " SharedSufferingRemoved " , 324983 ) -- Shared Suffering Normal Debuff
-- Container of Concentrated Anima
self : Log ( " SPELL_CAST_START " , " ConcentratedAnima " , 342320 , 342321 ) -- Lightly Concentrated Anima, Concentrated Anima
self : Log ( " SPELL_AURA_APPLIED " , " ConcentratedAnimaApplied " , 332664 , 340477 ) -- Concentrated Anima, Highly Concentrated Anima
self : Log ( " SPELL_AURA_REMOVED " , " ConcentratedAnimaRemoved " , 332664 , 340477 )
self : Log ( " SPELL_AURA_APPLIED " , " UnconscionableGuiltApplied " , 331573 )
self : Log ( " SPELL_AURA_APPLIED_DOSE " , " UnconscionableGuiltApplied " , 331573 )
self : Log ( " SPELL_CAST_START " , " Condemn " , 331550 )
self : Log ( " SPELL_AURA_APPLIED " , " GroundDamage " , 325713 ) -- Lingering Anima
self : Log ( " SPELL_PERIODIC_DAMAGE " , " GroundDamage " , 325713 )
self : Log ( " SPELL_PERIODIC_MISSED " , " GroundDamage " , 325713 )
end
function mod : OnEngage ( )
conjuredManifestationList = { }
mobCollector = { }
conjuredManifestationCount = 1
concentratedAnimaCount = 1
enabledContainer = 0
anima = { }
self : Bar ( 341621 , 12 , L.desires ) -- Expose Desires
self : Bar ( 324983 , 23 , L.sins ) -- Shared Suffering
self : Bar ( 325769 , 33 , L.bottles ) -- Bottled Anima
self : Bar ( 332664 , self : Mythic ( ) and 44 or 54 , CL.count : format ( CL.adds , concentratedAnimaCount ) ) -- Concentrated Anima
if self : GetOption ( " custom_off_experimental " ) then
self : OpenInfo ( " anima_tracking " , L.anima_tracking )
end
if self : GetOption ( conjuredManifestationMarker ) then
self : RegisterTargetEvents ( " ConjuredManifestationMarker " )
end
end
--------------------------------------------------------------------------------
-- Event Handlers
--
do
local abilitysToPause = {
[ 325064 ] = true , -- Sins and Suffering
[ 324983 ] = true , -- Shared Suffering
[ 325769 ] = true , -- Bottled Anima
[ 332664 ] = true , -- Concentrated Anima
}
local castPattern = CL.cast : gsub ( " %%s " , " .+ " )
local function stopAtZeroSec ( bar )
if bar.remaining < 0.15 then -- Pause at 0.0
bar : SetDuration ( 0.01 ) -- Make the bar look full
bar : Start ( )
bar : Pause ( )
bar : SetTimeVisibility ( false )
end
end
function mod : BarCreated ( _ , _ , bar , _ , key , text )
if self : GetOption ( " custom_on_stop_timers " ) and abilitysToPause [ key ] and not text : match ( castPattern ) then
bar : AddUpdateFunction ( stopAtZeroSec )
end
end
end
function mod : ConjuredManifestationMarker ( event , unit , guid )
if self : MobId ( guid ) == 170197 and conjuredManifestationList [ guid ] then -- Conjured Manifestation
self : CustomIcon ( conjuredManifestationMarker , unit , conjuredManifestationList [ guid ] )
end
end
do
local widgetIds = {
[ 2380 ] = { pos = 1 , name = " Desires " , icon = 325379 } , -- Expose Desires
[ 2399 ] = { pos = 2 , name = " Bottles " , icon = 325769 } , -- Bottled Anima
[ 2400 ] = { pos = 3 , name = " Sins " , icon = 325064 } , -- Sins and Suffering
[ 2401 ] = { pos = 4 , name = CL.add , icon = 332664 } , -- Concentrated Anima
}
local getStatusBarInfo = C_UIWidgetManager.GetStatusBarWidgetVisualizationInfo
function mod : UpdateAnimaInfoBox ( pos , text , time )
self : SetInfo ( " anima_tracking " , pos * 2 - 1 , text )
if time > 60 then
self : SetInfo ( " anima_tracking " , pos * 2 , ( " %d:%02d " ) : format ( time / 60 , time % 60 ) )
elseif time > 0 then
self : SetInfo ( " anima_tracking " , pos * 2 , ( " %d " ) : format ( time ) )
else
self : SetInfo ( " anima_tracking " , pos * 2 , " " )
end
end
local soundPrev = 0
function mod : WIDGET ( tbl )
if not self : GetOption ( " custom_off_experimental " ) then return end
local spell = widgetIds [ tbl.widgetID ]
if not spell then return end
local info = getStatusBarInfo ( tbl.widgetID )
if not info or not info.barValue then return end
local oldInfo = anima [ spell.icon ]
local curLevel = math.floor ( info.barValue / ( info.barMax / 3 ) ) + 1
if not oldInfo then -- first time we're seeing it
anima [ spell.icon ] = { value = info.barValue , level = curLevel , lastUpdate = GetTime ( ) }
else
if curLevel ~= oldInfo.level then
if curLevel > 3 then -- it's full
self : Message ( " anima_tracking " , " cyan " , L.full : format ( spell.name ) , spell.icon )
self : StopBar ( L.full : format ( spell.name ) )
else
self : Message ( " anima_tracking " , " cyan " , L.level : format ( spell.name , curLevel ) , spell.icon )
self : StopBar ( L.level : format ( spell.name , oldInfo.level ) )
end
local t = GetTime ( )
if t - soundPrev > 10 then -- high threshold in case something is really wrong
soundPrev = t
self : PlaySound ( " anima_tracking " , " info " )
end
end
local timeDiff = ( GetTime ( ) - oldInfo.lastUpdate )
local gain = ( info.barValue - oldInfo.value ) / timeDiff
if gain > 0 then
local nextLevelAtAnima = ( info.barMax / 3 ) * curLevel
local animaToNext = nextLevelAtAnima - info.barValue
local t = math.ceil ( animaToNext / gain )
if animaToNext > 0 then -- safety
local text = curLevel > 2 and L.full : format ( spell.name ) or L.level : format ( spell.name , curLevel + 1 )
if math.abs ( t - self : BarTimeLeft ( text ) ) > 1 then -- avoid restarting the bar on small differences
self : Bar ( " anima_tracking " , t , text , spell.icon )
end
self : UpdateAnimaInfoBox ( spell.pos , text , animaToNext / gain )
end
elseif gain < 0 then
self : StopBar ( L.level : format ( spell.name , 2 ) ) -- Stopping all for now, just in case
self : StopBar ( L.level : format ( spell.name , 3 ) )
self : StopBar ( L.full : format ( spell.name ) )
self : UpdateAnimaInfoBox ( spell.pos , " " , 0 )
end
anima [ spell.icon ] . value = info.barValue
anima [ spell.icon ] . level = curLevel
anima [ spell.icon ] . lastUpdate = GetTime ( )
end
end
end
function mod : UNIT_SPELLCAST_SUCCEEDED ( _ , _ , _ , spellId )
if spellId == 331844 then -- Focus Anima: Desires
self : Message ( 331870 , " cyan " , CL.other : format ( self : SpellName ( 331870 ) , L.desires ) )
self : PlaySound ( 331870 , " long " )
enabledContainer = 1
self : Bar ( 331870 , 97 , CL.other : format ( self : SpellName ( 331870 ) , L.bottles ) ) -- She picks the next one 3s early, hidden cast?
elseif spellId == 331870 then -- Focus Anima: Bottles
self : StopBar ( CL.other : format ( self : SpellName ( 331870 ) , L.bottles ) )
self : Message ( 331870 , " cyan " , CL.other : format ( self : SpellName ( 331870 ) , L.bottles ) )
self : PlaySound ( 331870 , " long " )
enabledContainer = 2
self : Bar ( 331870 , 97 , CL.other : format ( self : SpellName ( 331870 ) , L.sins ) )
elseif spellId == 331872 then -- Focus Anima: Sins
self : StopBar ( CL.other : format ( self : SpellName ( 331870 ) , L.sins ) )
self : Message ( 331870 , " cyan " , CL.other : format ( self : SpellName ( 331870 ) , L.sins ) )
self : PlaySound ( 331870 , " long " )
enabledContainer = 3
self : Bar ( 331870 , 97 , CL.other : format ( self : SpellName ( 331870 ) , CL.adds ) )
elseif spellId == 331873 then -- Focus Anima: Adds
self : StopBar ( CL.other : format ( self : SpellName ( 331870 ) , CL.adds ) )
self : Message ( 331870 , " cyan " , CL.other : format ( self : SpellName ( 331870 ) , CL.adds ) )
self : PlaySound ( 331870 , " long " )
enabledContainer = 4
end
end
function mod : ExposeDesires ( args )
self : Message ( 341621 , " purple " , CL.casting : format ( args.spellName ) )
self : Bar ( 341621 , enabledContainer == 1 and 9.7 or 12.9 , L.desires )
if self : Tanking ( " boss1 " ) or self : Healer ( ) then
self : PlaySound ( 341621 , " alert " )
end
end
function mod : WarpedDesiresApplied ( args )
local amount = args.amount or 1
self : NewStackMessage ( args.spellId , " purple " , args.destName , amount , 2 )
if amount > 1 and not self : Tanking ( " boss1 " ) then
self : PlaySound ( args.spellId , " alarm " )
end
end
do
local playerList = { }
local prev = 0
function mod : SharedCognitionApplied ( args )
local t = args.time
if t - prev > 3 then
prev = t
playerList = { }
end
playerList [ # playerList + 1 ] = args.destName
if self : Me ( args.destGUID ) then
self : PlaySound ( args.spellId , " alarm " )
self : TargetBar ( args.spellId , 21 , args.destName )
end
self : NewTargetsMessage ( args.spellId , " yellow " , playerList )
end
function mod : SharedCognitionRemoved ( args )
if self : Me ( args.destGUID ) then
self : StopBar ( args.spellId , args.destName )
end
end
end
function mod : ChangeOfHeartApplied ( args )
if self : Me ( args.destGUID ) then
self : Say ( args.spellId , CL.bomb )
self : SayCountdown ( args.spellId , 4 )
self : PlaySound ( args.spellId , " warning " )
end
self : TargetBar ( args.spellId , 4 , args.destName , CL.bomb )
self : TargetMessage ( args.spellId , " purple " , args.destName , CL.bomb )
end
function mod : ChangeOfHeartRemoved ( args )
if self : Me ( args.destGUID ) then
self : CancelSayCountdown ( args.spellId )
end
self : StopBar ( args.spellId , args.destName )
end
function mod : BottledAnima ( args )
self : Message ( 325769 , " orange " , L.bottles )
self : PlaySound ( 325769 , " info " )
self : Bar ( 325769 , enabledContainer == 2 and ( self : Mythic ( ) and 15 or 30 ) or ( self : Mythic ( ) and 30 or 45 ) , L.bottles )
end
do
local playerList , prev = { } , 0
function mod : SharedSufferingPreDebuffApplied ( args )
local t = args.time
if t - prev > 3 then
prev = t
playerList = { }
end
if self : Me ( args.destGUID ) then
self : Say ( 324983 , L.sins )
self : PlaySound ( 324983 , " warning " )
end
local count = # playerList + 1
playerList [ count ] = args.destName
playerList [ args.destName ] = count -- Set raid marker
self : NewTargetsMessage ( 324983 , " yellow " , playerList , 3 , L.sins )
self : CustomIcon ( sharedSufferingMarker , args.destName , count )
if count == 1 then
self : Bar ( 324983 , enabledContainer == 3 and ( self : Mythic ( ) and 30 or 35 ) or 51 , L.sins )
end
end
function mod : SharedSufferingRemoved ( args )
self : CustomIcon ( sharedSufferingMarker , args.destName )
end
end
do
local playerList , proxList = { } , { }
function mod : ConcentratedAnima ( )
playerList , proxList = { } , { }
conjuredManifestationList = { }
conjuredManifestationCount = 1
self : StopBar ( CL.count : format ( CL.adds , concentratedAnimaCount ) )
concentratedAnimaCount = concentratedAnimaCount + 1
self : CDBar ( 332664 , enabledContainer == 4 and ( self : Mythic ( ) and 43 or 51 ) or ( self : Mythic ( ) and 65 or 60 ) , CL.count : format ( CL.adds , concentratedAnimaCount ) )
end
local isOnMe = false
function mod : ConcentratedAnimaApplied ( args )
local count = # playerList + 1
local icon = 9 - count -- 8, 7, 6
proxList [ count ] = args.destName
playerList [ count ] = args.destName
playerList [ args.destName ] = icon -- Set raid marker
if # playerList == 1 then
self : Bar ( " anima_adds " , 10 , CL.spawning : format ( CL.adds ) , 332664 ) -- Adds Spawning
end
if self : Me ( args.destGUID ) then
isOnMe = true
self : PlaySound ( 332664 , " alarm " )
self : Say ( 332664 , CL.rticon : format ( args.spellId == 340477 and CL.big_add or CL.small_add , icon ) )
self : SayCountdown ( 332664 , 10 , icon )
self : OpenProximity ( 332664 , 8 )
end
self : NewTargetsMessage ( 332664 , " yellow " , playerList , CL.adds )
self : CustomIcon ( concentratedAnimaMarker , args.destName , icon )
if not isOnMe then
self : OpenProximity ( 332664 , 8 , proxList )
end
end
function mod : ConcentratedAnimaRemoved ( args )
tDeleteItem ( proxList , args.destName )
if self : Me ( args.destGUID ) then
isOnMe = nil
self : CancelSayCountdown ( 332664 )
self : CloseProximity ( 332664 )
end
if not isOnMe then
if # proxList == 0 then
self : CloseProximity ( 332664 )
else
self : OpenProximity ( 332664 , 8 , proxList )
end
end
self : CustomIcon ( concentratedAnimaMarker , args.destName )
end
end
function mod : UnconscionableGuiltApplied ( args )
local amount = args.amount or 1
self : NewStackMessage ( args.spellId , " yellow " , args.destName , amount )
self : PlaySound ( args.spellId , " alarm " , nil , args.destName )
end
function mod : Condemn ( args )
local canDo , ready = self : Interrupter ( args.sourceGUID )
if canDo then
self : Message ( args.spellId , " yellow " )
if ready then
self : PlaySound ( args.spellId , " alert " )
end
end
if self : GetOption ( conjuredManifestationMarker ) and not mobCollector [ args.sourceGUID ] and not conjuredManifestationList [ args.sourceGUID ] then
mobCollector [ args.sourceGUID ] = true
conjuredManifestationList [ args.sourceGUID ] = 9 - conjuredManifestationCount -- 8, 7 (max 2 adds per wave)
conjuredManifestationCount = conjuredManifestationCount + 1
for k , v in next , conjuredManifestationList do
local unit = self : GetUnitIdByGUID ( k )
if unit then
self : CustomIcon ( conjuredManifestationMarker , unit , v )
end
end
end
end
do
local prev = 0
function mod : GroundDamage ( args )
if self : Me ( args.destGUID ) then
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