local mod = DBM:NewMod(737, "DBM-HeartofFear", nil, 330)
local L = mod:GetLocalizedStrings()
mod:SetRevision(("$Revision: 8099 $"):sub(12, -3))
mod:SetCreatureID(62511)
mod:SetModelID(43126)
mod:SetZone()
mod:SetMinSyncRevision(8052)
mod:RegisterCombat("combat")
mod:RegisterEventsInCombat(
"SPELL_AURA_APPLIED",
"SPELL_AURA_APPLIED_DOSE",
"SPELL_AURA_REMOVED",
"SPELL_CAST_START",
"SPELL_CAST_SUCCESS",
"SPELL_DAMAGE",
"SPELL_MISSED",
"UNIT_POWER"
)
--[[WoL Reg Expression
(spellid = 45477 or spellid = 122540 or spellid = 122532 or spellid = 122348) and fulltype = SPELL_CAST_SUCCESS or (spellid =122784 or spellid =121949 or spellid = 122395 or spellid = 121994) and fulltype = SPELL_AURA_APPLIED or (spellid =122370 or spellid = 122540 or spellid = 122395 or spellid = 121994) and fulltype = SPELL_AURA_REMOVED or (spellid = 122408 or spellid = 122413 or spellid = 122398 or spellid = 122540 or spellid = 122402) and fulltype = SPELL_CAST_START or fulltype = UNIT_DIED and (targetname = "Omegal" or targetname = "Shiramune")
(spellid = 45477 or spellid = 122540) and fulltype = SPELL_CAST_SUCCESS or (spellid =122784 or spellid =121949 or spellid = 122395 or spellid = 121994) and fulltype = SPELL_AURA_APPLIED or (spellid =122370 or spellid = 122540 or spellid = 122395 or spellid = 121994) and fulltype = SPELL_AURA_REMOVED or (spellid = 122408 or spellid = 122413 or spellid = 122398 or spellid = 122540 or spellid = 122402) and fulltype = SPELL_CAST_START or fulltype = UNIT_DIED and (targetname = "Omegal" or targetname = "Shiramune")
--]]
--Boss
local warnReshapeLifeTutor = mod:NewAnnounce("warnReshapeLifeTutor", 1, 122784)--Another LFR focused warning really.
local warnReshapeLife = mod:NewTargetAnnounce(122784, 4)
local warnAmberScalpel = mod:NewTargetAnnounce(121994, 3)
local warnParasiticGrowth = mod:NewTargetAnnounce(121949, 4, nil, mod:IsHealer())
--Construct
local warnAmberExplosion = mod:NewAnnounce("warnAmberExplosion", 3, 122398, false)--In case you want to get warned for all of them, but could be spammy later fight so off by default. This announce includes source of cast.
local warnStruggleForControl = mod:NewTargetAnnounce(122395, 2)--Disabled in phase 3 as at that point it's just a burn.
local warnDestabalize = mod:NewStackAnnounce(123059, 1, nil, false)--This can be super spammy so off by default.
--Living Amber
local warnLivingAmber = mod:NewSpellAnnounce("ej6261", 2, nil, false)--122348 is what you check spawns with. ALso spamming and off by default
local warnBurningAmber = mod:NewCountAnnounce("ej6567", 2, nil, false)--Keep track of Burning Amber Puddles. Spammy, but nessesary for heroic for someone managing them.
--Amber Monstrosity
local warnAmberCarapace = mod:NewTargetAnnounce(122540, 4)--Monstrosity Shielding Boss (phase 2 start)
local warnMassiveStomp = mod:NewCastAnnounce(122408, 3)
local warnAmberExplosionSoon = mod:NewPreWarnAnnounce(122402, 10, 3)
local warnFling = mod:NewSpellAnnounce(122413, 3)--think this always does his aggro target but not sure. If it does random targets it will need target scanning.
local warnInterruptsAvailable = mod:NewAnnounce("warnInterruptsAvailable", 1, 122398)
--Boss
local specwarnAmberScalpel = mod:NewSpecialWarningYou(121994)
local yellAmberScalpel = mod:NewYell(121994)
local specwarnAmberScalpelNear = mod:NewSpecialWarningClose(121994)
local specwarnReshape = mod:NewSpecialWarningYou(122784)
local specwarnParasiticGrowth = mod:NewSpecialWarningTarget(121949, mod:IsHealer())
local specwarnParasiticGrowthYou = mod:NewSpecialWarningYou(121949) -- This warn will be needed at player is clustered together. Especially on Phase 3.
--Construct
local specwarnAmberExplosionYou = mod:NewSpecialWarning("specwarnAmberExplosionYou")--Only interruptable by the player controling construct casting, so only that person gets warning. non generic used to make this one more specific.
local specwarnAmberExplosionAM = mod:NewSpecialWarning("specwarnAmberExplosionAM")--Must be on by default. Amber montrosity's MUST be interrupted on heroic or it's an auto wipe. it hits for over 500k.
local specwarnAmberExplosionOther = mod:NewSpecialWarning("specwarnAmberExplosionOther", false)--A compromise. loose non player controled constructs now off by default but should still be an option as they are still perfectly interruptable (and should be)
local specwarnAmberExplosion = mod:NewSpecialWarningTarget(122398, nil, nil, nil, true)--One you can't interrupt it
local specwarnWillPower = mod:NewSpecialWarning("specwarnWillPower")--Special warning for when your will power is low (construct)
--local specwarnBossDebuff = mod:NewSpecialWarning("specwarnBossDebuff")--Some special warning that says "get your ass to boss and refresh debuff NOW" (Debuff stacks up to 255 with 10% damage taken increase every stack, keeping buff up and stacking is paramount to dps check on heroic)
--Living Amber
local specwarnBurningAmber = mod:NewSpecialWarningMove(122504)--Standing in a puddle
--Amber Monstrosity
local specwarnAmberMonstrosity = mod:NewSpecialWarningSwitch("ej6254", not mod:IsHealer())
local specwarnFling = mod:NewSpecialWarningSpell(122413, mod:IsTank())
local specwarnMassiveStomp = mod:NewSpecialWarningSpell(122408, nil, nil, nil, true)
--Boss
local timerReshapeLifeCD = mod:NewNextTimer(50, 122784)--50 second cd in phase 1-2, 15 second in phase 3. if no construct is up, cd is ignored and boss casts it anyways to make sure 1 is always up.
local timerAmberScalpelCD = mod:NewCDTimer(40, 121994)--40 seconds after last one ENDED
local timerAmberScalpel = mod:NewBuffActiveTimer(10, 121994)
local timerParasiticGrowthCD = mod:NewCDTimer(35, 121949, nil, mod:IsHealer())--35-50 variation (most of the time 50, rare pulls he decides to use 35 sec cd instead)
local timerParasiticGrowth = mod:NewTargetTimer(30, 121949, nil, mod:IsHealer())
--Construct
local timerAmberExplosionCD = mod:NewNextSourceTimer(13, 122398)--13 second cd on player controled units, 18 seconds on non player controlled constructs
local timerDestabalize = mod:NewTargetTimer(10, 123059)
local timerStruggleForControl = mod:NewTargetTimer(5, 122395)
--Amber Monstrosity
local timerMassiveStompCD = mod:NewCDTimer(18, 122408)--18-25 seconds variation
local timerFlingCD = mod:NewCDTimer(25, 122413)--25-40sec variation.
local timerAmberExplosionAMCD = mod:NewTimer(46, "timerAmberExplosionAMCD", 122402)--Special timer just for amber monstrosity. easier to cancel, easier to tell apart. His bar is the MOST important and needs to be seperate from any other bar option.
local countdownAmberExplosion = mod:NewCountdown(49, 122398)
mod:AddBoolOption("InfoFrame", true)
mod:AddBoolOption("FixNameplates", false)--Because having 215937495273598637205175t9 hostile nameplates on screen when you enter a construct is not cool.
local Phase = 1
local Puddles = 0
local Constructs = 0
local playerIsConstruct = false
local warnedWill = false
local lastStrike = 0
local scansDone = 0
local Totems = nil
local Guardians = nil
local Pets = nil
local TPTPNormal = nil
local amberExplosion = GetSpellInfo(122402)
local Monstrosity = EJ_GetSectionInfo(6254)
local MutatedConstruct = EJ_GetSectionInfo(6249)
local canInterrupt = {}
local guids = {}
local guidTableBuilt = false--Entirely for DCs, so we don't need to reset between pulls cause it doesn't effect building table on combat start and after a DC then it will be reset to false always
local function buildGuidTable()
table.wipe(guids)
for i = 1, DBM:GetGroupMembers() do
guids[UnitGUID("raid"..i) or "none"] = GetRaidRosterInfo(i)
end
end
function mod:ScalpelTarget()
scansDone = scansDone + 1
local targetname = DBM:GetUnitFullName("boss1targettarget")--Not a mistake, just clever use of available api to get the target of an invisible mob the boss is targeting ;)
if UnitExists("boss1targettarget") and not UnitIsUnit("boss1", "boss1targettarget") then
warnAmberScalpel:Show(targetname)
if targetname == UnitName("player") then
specwarnAmberScalpel:Show()
yellAmberScalpel:Yell()
else
local uId = DBM:GetRaidUnitId(targetname)
if uId then
local x, y = GetPlayerMapPosition(uId)
if x == 0 and y == 0 then
SetMapToCurrentZone()
x, y = GetPlayerMapPosition(uId)
end
local inRange = DBM.RangeCheck:GetDistance("player", x, y)
if inRange and inRange < 5 then--Guessed range
specwarnAmberScalpelNear:Show(targetname)
end
end
end
else--He failed sanity check (ie boss1targettarget was himself, so he was obviously still targeting tank, reschedule check)
if scansDone < 6 then
self:ScheduleMethod(0.2, "ScalpelTarget")
end
end
end
function mod:OnCombatStart(delay)
warnedWill = true--avoid wierd bug on pull
buildGuidTable()
Phase = 1
Puddles = 0
Constructs = 0
lastStrike = 0
table.wipe(canInterrupt)
playerIsConstruct = false
timerAmberScalpelCD:Start(9-delay)
timerReshapeLifeCD:Start(20-delay)
timerParasiticGrowthCD:Start(23.5-delay)
if self.Options.InfoFrame then
DBM.InfoFrame:SetHeader(L.WillPower)--This is a work in progress
DBM.InfoFrame:Show(5, "playerpower", 1, ALTERNATE_POWER_INDEX, nil, nil, true)--At a point i need to add an arg that lets info frame show the 5 LOWEST not the 5 highest, instead of just showing 10
end
if self.Options.FixNameplates then
--Blizz settings either return 1 or nil, we pull users original settings first, then change em if appropriate after.
Totems = GetCVarBool("nameplateShowEnemyTotems")
Guardians = GetCVarBool("nameplateShowEnemyGuardians")
Pets = GetCVarBool("nameplateShowEnemyPets")
--Now change all settings to make the nameplates while in constructs not terrible.
if Totems then
SetCVar("nameplateShowEnemyTotems", 0)
elseif Guardians then
SetCVar("nameplateShowEnemyGuardians", 0)
elseif Pets then
SetCVar("nameplateShowEnemyPets", 0)
end
--Check for Tidy plates threat plates (it has additional options to even further hide worthless nameplates on unsok.
if IsAddOnLoaded("TidyPlates_ThreatPlates") then
TidyPlatesNormal = TidyPlatesThreat.db.profile.nameplate.toggle["Normal"]--Returns true or false, use TidyPlatesNormal to save that value on pull
if TPTPNormal == true then
TidyPlatesThreat.db.profile.nameplate.toggle["Normal"] = false
TidyPlates:ReloadTheme()--Call the Tidy plates update methods
TidyPlates:ForceUpdate()
end
end
end
end
function mod:OnCombatEnd()
if self.Options.InfoFrame then
DBM.InfoFrame:Hide()
end
if self.Options.FixNameplates then
--if any of settings were on before pull, we put them back to way they were.
if Totems then
SetCVar("nameplateShowEnemyTotems", 1)
elseif Guardians then
SetCVar("nameplateShowEnemyGuardians", 1)
elseif Pets then
SetCVar("nameplateShowEnemyPets", 1)
end
if IsAddOnLoaded("TidyPlates_ThreatPlates") then
if TPTPNormal == true and not TidyPlatesThreat.db.profile.nameplate.toggle["Normal"] then--Normal plates were on when we pulled but aren't on now.
TidyPlatesThreat.db.profile.nameplate.toggle["Normal"] = true--Turn them back on
TidyPlates:ReloadTheme()--Call the Tidy plates update methods
TidyPlates:ForceUpdate()
end
end
end
end
function mod:SPELL_AURA_APPLIED(args)
if args:IsSpellID(123059) and not args:GetDestCreatureID() == 62691 then--Only track debuffs on boss, constructs, or monstrosity, ignore oozes.
warnDestabalize:Show(args.destName, args.amount or 1)
timerDestabalize:Start(args.destName)
elseif args:IsSpellID(121949) then
warnParasiticGrowth:Show(args.destName)
specwarnParasiticGrowth:Show(args.destName)
if args:IsPlayer() then
specwarnParasiticGrowthYou:Show()
end
timerParasiticGrowth:Start(args.destName)
timerParasiticGrowthCD:Start()
elseif args:IsSpellID(122540) then
Phase = 2
warnAmberCarapace:Show(args.destName)
specwarnAmberMonstrosity:Show()
timerMassiveStompCD:Start(20)
timerFlingCD:Start(33)
warnAmberExplosionSoon:Schedule(45.5)
timerAmberExplosionAMCD:Start(55.5, amberExplosion, Monstrosity)
elseif args:IsSpellID(122395) and Phase < 3 then
warnStruggleForControl:Show(args.destName)
timerStruggleForControl:Start(args.destName)
elseif args:IsSpellID(122784) then
Constructs = Constructs + 1
warnReshapeLife:Show(args.destName)
if args:IsPlayer() then
playerIsConstruct = true
warnedWill = true -- fix bad low will special warning on entering Construct. After entering vehicle, this will be return to false. (on alt.power changes)
specwarnReshape:Show()
warnReshapeLifeTutor:Show()
end
if Phase < 3 then
timerReshapeLifeCD:Start()
else
timerReshapeLifeCD:Start(15)--More often in phase 3
end
end
end
mod.SPELL_AURA_APPLIED_DOSE = mod.SPELL_AURA_APPLIED
function mod:SPELL_AURA_REMOVED(args)
if args:IsSpellID(122754) then
timerDestabalize:Cancel(args.destName)
elseif args:IsSpellID(122784) then
Constructs = Constructs - 1
if args:IsPlayer() then
countdownAmberExplosion:Cancel()
playerIsConstruct = false
end
timerAmberExplosionCD:Cancel(args.destName)
elseif args:IsSpellID(121994) then
timerAmberScalpelCD:Start()
elseif args:IsSpellID(121949) then
timerParasiticGrowth:Cancel(args.destName)
elseif args:IsSpellID(122540) then--Phase 3
Phase = 3
timerMassiveStompCD:Cancel()
timerFlingCD:Cancel()
timerAmberExplosionAMCD:Cancel()
warnAmberExplosionSoon:Cancel()
--He does NOT reset reshape live cd here, he finishes out last CD first, THEN starts using new one.
end
end
function mod:SPELL_CAST_START(args)
if args:IsSpellID(122398) then
warnAmberExplosion:Show(args.sourceName, args.spellName)
if args:GetSrcCreatureID() == 62701 then--Cast by a wild construct not controlled by player
if Constructs == 0 then--No constructs, thus no interrupt. Give a beware warning.
specwarnAmberExplosion:Show(args.sourceName)
end
if playerIsConstruct then--Player is construct
if GetTime() - lastStrike >= 4 then--Check if Amber Strike will be available before cast ends.
specwarnAmberExplosionOther:Show(args.spellName, args.sourceName)
if self:LatencyCheck() then--if you're too laggy we don't want you telling us you can interrupt it 2-3 seconds from now. we only care if you can interrupt it NOW
self:SendSync("InterruptAvailable", UnitGUID("player")..":122398")
end
end
end
timerAmberExplosionCD:Start(18, args.sourceName, args.sourceGUID)--Longer CD if it's a non player controlled construct. Everyone needs to see this bar because there is no way to interrupt these.
elseif args.sourceGUID == UnitGUID("player") then--Cast by YOU
specwarnAmberExplosionYou:Show(args.spellName)
timerAmberExplosionCD:Start(13, args.sourceName)--Only player needs to see this, they are only person who can do anything about it.
countdownAmberExplosion:Start(13)
end
elseif args:IsSpellID(122402) then--Amber Monstrosity
warnAmberExplosion:Show(args.sourceName, args.spellName)
if Constructs == 0 then--No constructs, thus no interrupt. Give a beware warning.
specwarnAmberExplosion:Show(args.sourceName)
end
if playerIsConstruct then--Player is construct
if GetTime() - lastStrike >= 4 then--Check if Amber Strike will be available before cast ends.
specwarnAmberExplosionAM:Show(args.spellName, args.sourceName)--On heroic, not interrupting amber montrosity is an auto wipe. this is single handedly the most important special warning of all!!!!!!
if self:LatencyCheck() then--if you're too laggy we don't want you telling us you can interrupt it 2-3 seconds from now. we only care if you can interrupt it NOW
self:SendSync("InterruptAvailable", UnitGUID("player")..":122402")
end
end
end
warnAmberExplosionSoon:Cancel()
warnAmberExplosionSoon:Schedule(39)
timerAmberExplosionAMCD:Start(46, args.spellName, args.sourceName)
elseif args:IsSpellID(122408) then
warnMassiveStomp:Show()
specwarnMassiveStomp:Show()
timerMassiveStompCD:Start()
elseif args:IsSpellID(122413) then
warnFling:Show()
specwarnFling:Show()
timerFlingCD:Start()
end
end
function mod:SPELL_CAST_SUCCESS(args)
if args:IsSpellID(122348) then
warnLivingAmber:Show()
elseif args:IsSpellID(121994) then
scansDone = 0
self:ScheduleMethod(0.2, "ScalpelTarget")
elseif args:IsSpellID(122532) then
Puddles = Puddles + 1
warnBurningAmber:Show(Puddles)
elseif args:IsSpellID(123156) then
Puddles = Puddles - 1
warnBurningAmber:Show(Puddles)
elseif args:IsSpellID(122389) and args.sourceGUID == UnitGUID("player") then--Amber Strike
lastStrike = GetTime()
end
end
function mod:SPELL_DAMAGE(_, _, _, _, destGUID, _, _, _, spellId)
if spellId == 122504 and destGUID == UnitGUID("player") and self:AntiSpam(3) then
specwarnBurningAmber:Show()
end
end
mod.SPELL_MISSED = mod.SPELL_DAMAGE
function mod:UNIT_POWER(uId)
if uId ~= "player" then return end
if UnitPower(uId, ALTERNATE_POWER_INDEX) < 28 and not warnedWill then
warnedWill = true
specwarnWillPower:Show()
elseif UnitPower(uId, ALTERNATE_POWER_INDEX) >= 32 and warnedWill then
warnedWill = false
end
end
local function warnAmberExplosionCast(spellId)
if #canInterrupt == 0 then--No interupts, warn the raid to prep for aoe damage with beware! alert.
specwarnAmberExplosion:Show(spellId == 122402 and Monstrosity or MutatedConstruct)
else--Interrupts available, lets call em out as a great tool to give raid leader split second decisions on who to allocate to the task (so they don't all waste it on same target and not have for next one).
print("Debug: Interrupts Available")
warnInterruptsAvailable:Show(spellId == 122402 and Monstrosity or MutatedConstruct, table.concat(canInterrupt, "<, >"))
end
table.wipe(canInterrupt)
end
function mod:OnSync(msg, str, sender)
print(msg, str, sender)--This could generate a decent amount of spam in phase 3 if there is a loose construct casting away and multiple player constructs up. None the less, that would be the greatest debug if a user complains about spam (and thus, shares it).
if not guidTableBuilt then
buildGuidTable()
guidTableBuilt = true
end
local guid, spellId
if sender and str then
guid, spellId = string.split(":", str)
spellId = tonumber(spellId or "")
print(guid, spellId)
end
if msg == "InterruptAvailable" and guids[guid] and spellId then
canInterrupt[#canInterrupt + 1] = guids[guid]
self:Unschedule(warnAmberExplosionCast)
self:Schedule(0.5, warnAmberExplosionCast, spellId)
end
end