local mod	= DBM:NewMod(2425, "DBM-CastleNathria", nil, 1190)
local L		= mod:GetLocalizedStrings()

mod:SetRevision("20210614184808")
mod:SetCreatureID(168112, 168113)
mod:SetEncounterID(2417)
mod:SetUsedIcons(1, 2, 3, 4, 5, 6, 7, 8)
mod:SetBossHPInfoToHighest()
mod:SetHotfixNoticeRev(20210128000000)--2021, 01, 28
mod:SetMinSyncRevision(20210126000000)
mod.respawnTime = 29

mod:RegisterCombat("combat")

mod:RegisterEventsInCombat(
	"SPELL_CAST_START 333387 334765 334929 334498 342544 342256 342722 332683 342425 344496 334009 344230",
	"SPELL_CAST_SUCCESS 334765 334929 342732 342253 342985 339690 342425",
	"SPELL_SUMMON 342255 342257 342258 342259",
	"SPELL_AURA_APPLIED 329636 333913 334765 338156 338153 329808 333377 339690 342655 340037 342425 336212",
	"SPELL_AURA_APPLIED_DOSE 333913",
	"SPELL_AURA_REMOVED 329636 333913 334765 329808 333377 339690 340037",
	"SPELL_AURA_REMOVED_DOSE 333913",
--	"SPELL_PERIODIC_DAMAGE",
--	"SPELL_PERIODIC_MISSED",
	"UNIT_DIED",
	"RAID_BOSS_WHISPER",
	"UNIT_SPELLCAST_START boss1 boss2 boss3 boss4 boss5",
	"UNIT_SPELLCAST_SUCCEEDED boss1 boss2 boss3 boss4 boss5"
)

--TODO, review more of timers with some bug fixes to fight as well as just a better version of transcriptor recording it., especailly P3 timers after intermission 2
--TODO, stack announces for https://ptr.wowhead.com/spell=340042/punishment?
--TODO, heart rend is renamed to Soul Crusher in journal, but spell data not renamed yet. Apply rename when it happens.
--TODO, find a way to move timers for Adds to nameplate bars, otherwise they are far less useful and will only feel like spam. They'll be extremely useful on NPs though
--[[
(ability.id = 334765 or ability.id = 333387 or ability.id = 334929 or ability.id = 344496 or ability.id = 334498 or ability.id = 342544 or ability.id = 342256 or ability.id = 342425 or ability.id = 332683 or ability.id = 344230 or ability.id = 334009) and type = "begincast"
 or (ability.id = 339690 or ability.id = 342253) and type = "cast"
 or ability.id = 329636 or ability.id = 329808 or ability.id = 342255 or ability.id = 342257 or ability.id = 342258 or ability.id = 342259
 or (target.id = 168112 or target.id = 168113 or target.id = 172858) and type = "death"
 or (ability.id = 340043 or ability.id = 332683) and type = "begincast"
 or ability.id = 342732 and type = "cast"
 --]]
 --General
local warnHardenedStoneForm						= mod:NewTargetNoFilterAnnounce(329636, 2)
local warnHardenedStoneFormOver					= mod:NewEndAnnounce(329636, 1)
local warnSoldiersOath							= mod:NewTargetNoFilterAnnounce(336212, 4)
--General Kaal
local warnWickedBlade							= mod:NewTargetCountAnnounce(333376, 4, nil, nil, nil, nil, nil, nil, true)
local warnHeartRend								= mod:NewTargetCountAnnounce(334765, 4, nil, "Healer", 2, nil, nil, nil, true)
local warnCallShadowForces						= mod:NewCountAnnounce(342256, 2)
--General Grashaal
local warnReverberatingEruption					= mod:NewTargetCountAnnounce(344496, 3, nil, nil, nil, nil, nil, nil, true)--Normal+
local warnReverberatingLeap						= mod:NewTargetCountAnnounce(334009, 3, nil, nil, nil, nil, nil, nil, true)--LFR
local warnCrystalize							= mod:NewTargetCountAnnounce(339690, 2, nil, nil, nil, nil, nil, nil, true)
local warnPulverizingMeteor						= mod:NewTargetCountAnnounce(342544, 4, nil, nil, nil, nil, nil, nil, true)
--Adds
local warnStoneLegionGoliath					= mod:NewSpellAnnounce("ej22777", 2, 343273)
local warnVolatileAnimaInfusion					= mod:NewTargetNoFilterAnnounce(342655, 2, nil, false)
local warnRavenousFeast							= mod:NewTargetCountAnnounce(343273, 3, nil, nil, nil, nil, nil, nil, true)
local warnStonewrathExhaust						= mod:NewCastAnnounce(342722, 3)
local warnWickedSlaughter						= mod:NewTargetNoFilterAnnounce(342253, 2, nil, "Tank")--So tanks know where adds went
local warnStonegaleEffigy						= mod:NewSpellAnnounce(342985, 3)

--General Kaal
local specWarnWickedBladeCast					= mod:NewSpecialWarningCount(333376, false, nil, nil, 2, 2)
local specWarnWickedBlade						= mod:NewSpecialWarningYouPos(333376, nil, nil, nil, 1, 2)
local yellWickedBlade							= mod:NewPosYell(333376)
local yellWickedBladeFades						= mod:NewIconFadesYell(333376)
local specWarnHeartRendCast						= mod:NewSpecialWarningCount(334765, false, nil, nil, 1, 2)
local specWarnHeartRend							= mod:NewSpecialWarningYou(334765, false, nil, nil, 1, 2)
local specWarnSerratedSwipe						= mod:NewSpecialWarningDefensive(334929, nil, nil, nil, 1, 2)
--local specWarnLaceration						= mod:NewSpecialWarningStack(333913, nil, 3, nil, nil, 1, 6)
--local specWarnGTFO							= mod:NewSpecialWarningGTFO(270290, nil, nil, nil, 1, 8)
--General Grashaal
local specWarnReverberatingEruption				= mod:NewSpecialWarningYou(344496, nil, 138658, nil, 1, 2, 2)
local yellReverberatingEruption					= mod:NewYell(344496, 138658)--Short text "Eruption"
local yellReverberatingEruptionFades			= mod:NewFadesYell(344496, 138658)--Short text "Eruption"
local specWarnReverberatingLeap					= mod:NewSpecialWarningYou(334009, nil, 337445, nil, 1, 2, 1)
local yellReverberatingLeap						= mod:NewYell(334009, 337445)--Short text "Leap"
local yellReverberatingLeapFades				= mod:NewFadesYell(334009, 337445)--Short text "Leap"
local specWarnEchoingAnnihilation				= mod:NewSpecialWarningMoveTo(344721, false, nil, nil, 1, 2, 4)--Off by default since strats may vary. Auto asigns reverb soak by remember which one you spawned
local specWarnSeismicUpheaval					= mod:NewSpecialWarningDodge(334498, nil, nil, nil, 2, 2)
local specWarnCrystalize						= mod:NewSpecialWarningYou(339690, nil, nil, nil, 1, 2)
local specWarnCrystalizeTarget					= mod:NewSpecialWarningMoveTo(339690, false, nil, nil, 1, 2)
local yellCrystalize							= mod:NewYell(339690, nil, nil, nil, "YELL")
local yellCrystalizeFades						= mod:NewFadesYell(339690, nil, nil, nil, "YELL")
local specWarnMeteor							= mod:NewSpecialWarningYou(342544, nil, nil, nil, 1, 2)
local yellMeteor								= mod:NewYell(342544, nil, nil, nil, "YELL")
local specWarnStoneFist							= mod:NewSpecialWarningDefensive(342425, nil, nil, nil, 1, 2)
local specWarnStoneFistTaunt					= mod:NewSpecialWarningTaunt(342425, nil, nil, nil, 1, 2)
--Adds/Intermissions
local specWarnVolatileStoneShell				= mod:NewSpecialWarningSwitch(340037, "Dps", nil, nil, 1, 2)
local specWarnShatteringBlast					= mod:NewSpecialWarningSpell(332683, nil, nil, nil, 2, 2)

--General Kaal
mod:AddTimerLine(DBM:EJ_GetSectionInfo(22284))
local timerWickedBladeCD						= mod:NewCDCountTimer(30, 333387, nil, nil, nil, 3, nil, nil, true)--30 unless ICDed
local timerHeartRendCD							= mod:NewCDCountTimer(42.4, 334765, nil, nil, nil, 3, nil, DBM_CORE_L.DEADLY_ICON, true)--42.4 unless ICDed
local timerSerratedSwipeCD						= mod:NewCDCountTimer(21.8, 334929, nil, "Tank|Healer", nil, 5, nil, DBM_CORE_L.TANK_ICON, true)
local timerCallShadowForcesCD					= mod:NewCDCountTimer(52, 342256, nil, nil, nil, 1, nil, DBM_CORE_L.MYTHIC_ICON)
--General Grashaal
mod:AddTimerLine(DBM:EJ_GetSectionInfo(22288))
local timerReverberatingEruptionCD				= mod:NewCDCountTimer(30, 344496, 138658, nil, 3, 3, nil, nil, true)--Short text "Eruption" (Normal+)
local timerReverberatingLeapCD					= mod:NewCDCountTimer(30, 334009, 337445, nil, 3, 3, nil, nil, true)--Short text "Leap" (LFR)
local timerSeismicUpheavalCD					= mod:NewCDCountTimer(25.1, 334498, nil, nil, nil, 3, nil, nil, true)
local timerCrystalizeCD							= mod:NewCDCountTimer(55, 339690, nil, nil, 3, 5, nil, nil, true)--55 on mythic, 50 on non mythic
local timerStoneFistCD							= mod:NewCDCountTimer(18, 342425, nil, "Tank|Healer", nil, 5, nil, DBM_CORE_L.TANK_ICON, true)
--Phasing
local timerShatteringBlast						= mod:NewCastTimer(5, 332683, nil, nil, nil, 2)
--Adds
mod:AddTimerLine(DBM_CORE_L.ADDS)
local timerRavenousFeastCD						= mod:NewCDCountTimer(18.6, 343273, nil, nil, nil, 3)--Kind of all over the place right now 23-30)
local timerWickedSlaughterCD					= mod:NewCDTimer(8.5, 342253, nil, "Tank|Healer", nil, 3, nil, DBM_CORE_L.MYTHIC_ICON)

local berserkTimer								= mod:NewBerserkTimer(600)

mod:AddInfoFrameOption(333913, true)
mod:AddSetIconOption("SetIconOnHeartRend", 334765, true, false, {1, 2, 3, 4})--On by default since it's most important mechanic to manage outside of shadow forces
mod:AddSetIconOption("SetIconOnWickedBlade2", 333387, false, false, {1, 2})--Off by default since it conflicts with heart rend
mod:AddSetIconOption("SetIconOnEruption2", 344496, false, false, {4})--Off by default since it conflicts with heart rend
mod:AddSetIconOption("SetIconOnCrystalize", 339690, true, false, {5})
mod:AddSetIconOption("SetIconOnShadowForces", 342256, true, true, {6, 7, 8})
mod:AddNamePlateOption("NPAuraOnVolatileShell", 340037)
mod:AddBoolOption("ExperimentalTimerCorrection", true)
mod:AddDropdownOption("BladeMarking", {"SetOne", "SetTwo"}, "SetOne", "misc")--SetTwo is BW default

local markingSet = "SetOne"
local playerName = UnitName("player")
local LacerationStacks = {}
local castsPerGUID = {}
local playerEruption = 0--Players eruption and the numbber that was theres
mod.vb.HeartIcon = 1
mod.vb.wickedBladeIcon = 1
mod.vb.bladeCount = 0
mod.vb.heartCount = 0
mod.vb.swipeCount = 0
mod.vb.forcesCount = 0
mod.vb.eruptionCount = 0
mod.vb.upHeavalCount = 0
mod.vb.crystalCount = 0
mod.vb.fistCount = 0
mod.vb.shieldUp = false
mod.vb.kaalDead = false
mod.vb.grashDead = false

--Seismic Upheavel triggers an 8 second ICD
--Crystalize triggers an 8 second ICD
--Reverberating Eruption triggers an 8 second ICD/ Leap is inconclusive but probably same
--Wicked blade triggers a 6 second ICD on all but swipe, which then only imposes 5
--Heart rend triggers 2.3 second ICD
--Stone fist triggers 3-3.5 second ICD
--Serrated swipe triggers 2.4 second ICD
--Exclusions:
--1-Heart rend DC not extended by crystalize most of time
--2-To prevent swipe from altering it's OWN CD since it's started in success and not start (where timer update is)
--3-To prevent stone fist from altering it's OWN CD since it's started in success and not start (where timer update is)
--4-Heart rend is not extended by LFR version Reverberation (or anything else?)
--5-Heart rend in general seems ot have half ICD of everything else when ICD is triggered
--Crystallize > tank abilities> wicked blade> eruption>seismic upheaval
local function updateAllTimers(self, ICD, exclusion)
	if not self.Options.ExperimentalTimerCorrection then return end
	DBM:Debug("updateAllTimers running", 3)
	exclusion = exclusion or 0
	--All phase abilities
	if not self.vb.grashDead and timerCrystalizeCD:GetRemaining(self.vb.crystalCount+1) < ICD then
		local elapsed, total = timerCrystalizeCD:GetTime(self.vb.crystalCount+1)
		local extend = ICD - (total-elapsed)
		DBM:Debug("timerCrystalizeCD extended by: "..extend, 2)
		timerCrystalizeCD:Stop()
		timerCrystalizeCD:Update(elapsed, total+extend, self.vb.crystalCount+1)
	end
	if not self.vb.kaalDead and timerWickedBladeCD:GetRemaining(self.vb.bladeCount+1) < ICD then
		local elapsed, total = timerWickedBladeCD:GetTime(self.vb.bladeCount+1)
		local extend = ICD - (total-elapsed)
		DBM:Debug("timerWickedBladeCD extended by: "..extend, 2)
		timerWickedBladeCD:Stop()
		timerWickedBladeCD:Update(elapsed, total+extend, self.vb.bladeCount+1)
	end
	local phase = self.vb.phase
	if not self.vb.kaalDead and (phase == 1 or phase == 3) then
		if exclusion ~= 1 and exclusion ~= 4 and timerHeartRendCD:GetRemaining(self.vb.heartCount+1) < (ICD/2) then
			local elapsed, total = timerHeartRendCD:GetTime(self.vb.heartCount+1)
			local extend = (ICD/2) - (total-elapsed)
			DBM:Debug("timerHeartRendCD extended by: "..extend, 2)
			timerHeartRendCD:Stop()
			timerHeartRendCD:Update(elapsed, total+extend, self.vb.heartCount+1)
		end
		if exclusion ~= 2 and timerSerratedSwipeCD:GetRemaining(self.vb.swipeCount+1) < ICD then
			local elapsed, total = timerSerratedSwipeCD:GetTime(self.vb.swipeCount+1)
			local extend = ICD - (total-elapsed) - 1.5--Whatever ICD is, this ability specifically is that ICD minus 1
			DBM:Debug("timerSerratedSwipeCD extended by: "..extend, 2)
			timerSerratedSwipeCD:Stop()
			timerSerratedSwipeCD:Update(elapsed, total+extend, self.vb.swipeCount+1)
		end
	end
	if not self.vb.grashDead and (phase == 2 or phase == 3) then
		if self:IsLFR() then
			if timerReverberatingLeapCD:GetRemaining(self.vb.eruptionCount+1) < ICD then
				local elapsed, total = timerReverberatingLeapCD:GetTime(self.vb.eruptionCount+1)
				local extend = ICD - (total-elapsed)
				DBM:Debug("timerReverberatingLeapCD extended by: "..extend, 2)
				timerReverberatingLeapCD:Stop()
				timerReverberatingLeapCD:Update(elapsed, total+extend, self.vb.eruptionCount+1)
			end
		else
			if timerReverberatingEruptionCD:GetRemaining(self.vb.eruptionCount+1) < ICD then
				local elapsed, total = timerReverberatingEruptionCD:GetTime(self.vb.eruptionCount+1)
				local extend = ICD - (total-elapsed)
				DBM:Debug("timerReverberatingEruptionCD extended by: "..extend, 2)
				timerReverberatingEruptionCD:Stop()
				timerReverberatingEruptionCD:Update(elapsed, total+extend, self.vb.eruptionCount+1)
			end
		end
		if not self.vb.shieldUp and timerSeismicUpheavalCD:GetRemaining(self.vb.upHeavalCount+1) < ICD then
			local elapsed, total = timerSeismicUpheavalCD:GetTime(self.vb.upHeavalCount+1)
			local extend = ICD - (total-elapsed)
			DBM:Debug("timerSeismicUpheavalCD extended by: "..extend, 2)
			timerSeismicUpheavalCD:Stop()
			timerSeismicUpheavalCD:Update(elapsed, total+extend, self.vb.upHeavalCount+1)
		end
		if exclusion ~= 3 and timerStoneFistCD:GetRemaining(self.vb.fistCount+1) < ICD then
			local elapsed, total = timerStoneFistCD:GetTime(self.vb.fistCount+1)
			local extend = ICD - (total-elapsed)
			DBM:Debug("timerStoneFistCD extended by: "..extend, 2)
			timerStoneFistCD:Stop()
			timerStoneFistCD:Update(elapsed, total+extend, self.vb.fistCount+1)
		end
	end
end

function mod:EruptionTarget(targetname, uId)
	if not targetname then return end
	if self:AntiSpam(4, targetname.."2") then
		if self.Options.SetIconOnEruption2 then
			self:SetIcon(targetname, 4, 5)--So icon clears 1 second after blast
		end
		if self:IsLFR() then
			if targetname == playerName then
				specWarnReverberatingLeap:Show()
				specWarnReverberatingLeap:Play("runout")
				yellReverberatingLeap:Yell()
				yellReverberatingLeapFades:Countdown(3.97)--This scan method doesn't support scanningTime, but should be about right
				playerEruption = self.vb.eruptionCount
			else
				warnReverberatingLeap:Show(self.vb.eruptionCount, targetname)
			end
		else
			if targetname == playerName then
				specWarnReverberatingEruption:Show()
				specWarnReverberatingEruption:Play("runout")
				yellReverberatingEruption:Yell()
				yellReverberatingEruptionFades:Countdown(3.97)--This scan method doesn't support scanningTime, but should be about right
				playerEruption = self.vb.eruptionCount
			else
				warnReverberatingEruption:Show(self.vb.eruptionCount, targetname)
			end
		end
	end
end

function mod:MeteorTarget(targetname, uId)
	if not targetname then return end
	if targetname == playerName then
		specWarnMeteor:Show()
		specWarnMeteor:Play("runout")
		yellMeteor:Yell()
	else
		warnPulverizingMeteor:Show(self.vb.crystalCount, targetname)
	end
end

function mod:OnCombatStart(delay)
	table.wipe(LacerationStacks)
	table.wipe(castsPerGUID)
	playerEruption = 0
	self.vb.HeartIcon = 1
	self.vb.wickedBladeIcon = self.Options.BladeMarking == "SetOne" and 1 or 2
	self:SetStage(1)
	self.vb.bladeCount = 0
	self.vb.heartCount = 0
	self.vb.swipeCount = 0
	self.vb.forcesCount = 0
	self.vb.eruptionCount = 0
	self.vb.upHeavalCount = 0
	self.vb.crystalCount = 0
	self.vb.fistCount = 0
	self.vb.shieldUp = false
	self.vb.kaalDead = false
	self.vb.grashDead = false
	--Summons a goliath instantly on pull now, no timer needed for this
	if self:IsMythic() then
		--Blizz made timers more consistent on mythic, but said "screw everyone else"
		--General Kaal
		timerSerratedSwipeCD:Start(8.1-delay, 1)--START, but next timer is started at SUCCESS
		timerCallShadowForcesCD:Start(10.5-delay, 1)
		timerWickedBladeCD:Start(18-delay, 1)--16.8-21
		timerHeartRendCD:Start(33.6-delay, 1)--START
		--General Grashaal Air ability
		timerCrystalizeCD:Start(32.5-delay, 1)
		berserkTimer:Start(720)
	else
		--Everyone else still gets crappy less consistent timers
		--General Kaal
		timerSerratedSwipeCD:Start(8.1-delay, 1)--START, but next timer is started at SUCCESS
		timerWickedBladeCD:Start(16.6-delay, 1)--16.8-21
		timerHeartRendCD:Start(28.9-delay, 1)--START 28-30
		--General Grashaal Air ability
		timerCrystalizeCD:Start(23.1-delay, 1)
		berserkTimer:Start(840)
	end
	if self.Options.NPAuraOnVolatileShell then
		DBM:FireEvent("BossMod_EnableHostileNameplates")
	end
	if self.Options.InfoFrame then
		DBM.InfoFrame:SetHeader(DBM:GetSpellInfo(333913))
		DBM.InfoFrame:Show(10, "table", LacerationStacks, 1)
	end
	if UnitIsGroupLeader("player") then self:SendSync(self.Options.BladeMarking) end
--	berserkTimer:Start(-delay)--Confirmed normal and heroic
end

function mod:OnCombatEnd()
	table.wipe(castsPerGUID)
	if self.Options.InfoFrame then
		DBM.InfoFrame:Hide()
	end
	if self.Options.NPAuraOnVolatileShell then
		DBM.Nameplate:Hide(true, nil, nil, nil, true, true)
	end
end

function mod:SPELL_CAST_START(args)
	local spellId = args.spellId
	if spellId == 333387 or spellId == 344230 then
		self.vb.bladeCount = self.vb.bladeCount + 1
		specWarnWickedBladeCast:Show(self.vb.bladeCount)
		specWarnWickedBladeCast:Play("specialsoon")
		self.vb.wickedBladeIcon = markingSet == "SetOne" and 1 or 2
		timerWickedBladeCD:Start(nil, self.vb.bladeCount+1)
		updateAllTimers(self, 6)
	elseif spellId == 334765 then
		self.vb.HeartIcon = 1
		self.vb.heartCount = self.vb.heartCount + 1
		specWarnHeartRendCast:Show(self.vb.heartCount)
		specWarnHeartRendCast:Play("specialsoon")
		timerHeartRendCD:Start(nil, self.vb.heartCount+1)
		updateAllTimers(self, 2.3)
	elseif spellId == 334929 then
		if self:IsTanking("player", nil, nil, true, args.sourceGUID) then
			specWarnSerratedSwipe:Show()
			specWarnSerratedSwipe:Play("defensive")
		end
		updateAllTimers(self, 2.4, 2)
	elseif spellId == 344496 then--Eruption (Normal+)
		--"Reverberating Eruption-344496-npc:168113 = pull:252.3, 40.0, 40.0, 32.1, 40.0, Intermission/22.5, 9.6/32.1, 31.9, 28.1", -- [6]
		self.vb.eruptionCount = self.vb.eruptionCount + 1
		timerReverberatingEruptionCD:Start(nil, self.vb.eruptionCount+1)
		if self:IsMythic() and playerEruption > 0 then
			specWarnEchoingAnnihilation:Show(self:IconNumToTexture(playerEruption))
			specWarnEchoingAnnihilation:Play("helpsoak")
		end
		updateAllTimers(self, 8)
		--self:BossTargetScanner(args.sourceGUID, "EruptionTarget", 0.01, 12)
	elseif spellId == 334009 then--Leap (LFR)
		self.vb.eruptionCount = self.vb.eruptionCount + 1
		timerReverberatingLeapCD:Start(nil, self.vb.eruptionCount+1)
		updateAllTimers(self, 8, 4)
		--self:BossTargetScanner(args.sourceGUID, "EruptionTarget", 0.01, 12)
	elseif spellId == 334498 then
		self.vb.upHeavalCount = self.vb.upHeavalCount + 1
		specWarnSeismicUpheaval:Show(self.vb.upHeavalCount)
		specWarnSeismicUpheaval:Play("watchstep")
		if not self.vb.shieldUp then
			timerSeismicUpheavalCD:Start(nil, self.vb.upHeavalCount+1)--usually averages around 30-40, but yes it goes this low as 25.1 when not spell queued to death
		end
		updateAllTimers(self, 8)
	elseif spellId == 342544 then
		self:BossTargetScanner(args.sourceGUID, "MeteorTarget", 0.05, 12)
	elseif spellId == 342256 then
		self.vb.forcesCount = self.vb.forcesCount + 1
		warnCallShadowForces:Show(self.vb.forcesCount)
		if not self.vb.shieldUp then
			timerCallShadowForcesCD:Start(nil, self.vb.forcesCount+1)
		end
	elseif spellId == 342722 then
		warnStonewrathExhaust:Show()
	elseif spellId == 332683 then
		self.vb.shieldUp = false--Technically not accurate but it's how fight is scripted
		specWarnShatteringBlast:Show()
		specWarnShatteringBlast:Play("carefly")
		timerShatteringBlast:Start()
		--Start INCOMING boss timers here, that seems to be how it's scripted.
		self:SetStage(0)
		self.vb.upHeavalCount = 0--always resets since boss stops casting it while shielded, so even between phase 2 and 3 there is a long break
		self.vb.forcesCount = 0
		if self.vb.phase == 2 then
			--Kaal's Wicked Blade timer is tied to shield 100%
			--Start initial Grashal timers and reset crystalize timer
			timerCrystalizeCD:Stop()--Chance this doesn't happen here but at shield
			timerCrystalizeCD:Start(18.5, self.vb.crystalCount+1)--18.5-20.7
			timerStoneFistCD:Start(26.4, 1)--26.4-28.1
			if self:IsLFR() then
				timerReverberatingLeapCD:Start(29.4, 1)--Assumed for now
			else
				timerReverberatingEruptionCD:Start(29.4, 1)--29.4-38.2 (it's basically either 29 or 38 based on if wicked blade happens first
			end
			timerSeismicUpheavalCD:Start(50.2, 1)--19.5-51.7 (19.9, 22.6, 43, 51.7, 29.8)
			--Kael also resumes summoning adds on mythic once intermission 1 is over, but it's pretty instant
--			if self:IsMythic() then
--				timerCallShadowForcesCD:Start(0, 1)--0-5
--			end
		else--Stage 3 (Both Generals at once)
			self.vb.heartCount = 0
			self.vb.swipeCount = 0
			--General Kaal returning
			--Kaal's Wicked Blade timer is tied to shield 100%
			timerSerratedSwipeCD:Start(13.8, 1)--START 13.8-14.1
			timerHeartRendCD:Start(35.8, 1)--START 35.8-38.2
			--Kael also resumes summing adds on mythic once intermission 2 is over
--			if self:IsMythic() then
--				timerCallShadowForcesCD:Start(8, 1)--8-16.6
--			end
			--General Grashaal
			--Restart timers
			timerCrystalizeCD:Stop()
			timerStoneFistCD:Stop()
			timerReverberatingLeapCD:Stop()
			timerReverberatingEruptionCD:Stop()
			timerCrystalizeCD:Start(12.4, self.vb.crystalCount+1)--12.4-12.7
			timerStoneFistCD:Start(20.9, self.vb.fistCount+1)--20.9-21.2
			if self:IsLFR() then
				timerReverberatingLeapCD:Start(25.2, self.vb.eruptionCount+1)--Guessed
			else
				timerReverberatingEruptionCD:Start(25.2, self.vb.eruptionCount+1)--25.2-30.9
			end
			--Re-enable Upheaval
			timerSeismicUpheavalCD:Start(44, 1)--44-44.4
		end
	elseif spellId == 342425 then
		updateAllTimers(self, 3, 3)
		if self:IsTanking("player", nil, nil, true, args.sourceGUID) then
			specWarnStoneFist:Show()
			specWarnStoneFist:Play("defensive")
		end
	end
end

function mod:SPELL_CAST_SUCCESS(args)
	local spellId = args.spellId
	if spellId == 334929 then--Boss stutter casts this often
		self.vb.swipeCount = self.vb.swipeCount + 1
		timerSerratedSwipeCD:Start(20.4, self.vb.swipeCount+1)--21.9 - 1.5
	elseif spellId == 339690 then
		self.vb.crystalCount = self.vb.crystalCount + 1
		timerCrystalizeCD:Start(self:IsMythic() and 55 or 50, self.vb.crystalCount+1)
		updateAllTimers(self, 8, 1)
	elseif spellId == 342732 then
		if not castsPerGUID[args.sourceGUID] then
			castsPerGUID[args.sourceGUID] = 0
		end
		castsPerGUID[args.sourceGUID] = castsPerGUID[args.sourceGUID] + 1
		local count = castsPerGUID[args.sourceGUID]
		warnRavenousFeast:Show(count, args.destName)
		timerRavenousFeastCD:Start(self:IsMythic() and 24.6 or 18.2, count+1, args.sourceGUID)
	elseif spellId == 342253 then
		warnWickedSlaughter:CombinedShow(1.5, args.destName)--Needs to allow at least 1.5 to combine targets
		timerWickedSlaughterCD:Start(8.5, args.sourceGUID)
	elseif spellId == 342985 and self:AntiSpam(3, 3) then
		warnStonegaleEffigy:Show()
	elseif spellId == 342425 then
		self.vb.fistCount = self.vb.fistCount + 1
		timerStoneFistCD:Start(15.5, self.vb.fistCount+1)--18-2.5
	end
end

function mod:SPELL_SUMMON(args)
	local spellId = args.spellId
	if spellId == 342255 then--Summon Reinforcements
		local cid = self:GetCIDFromGUID(args.destGUID)
		if cid == 172858 then--stone-legion-goliath
			warnStoneLegionGoliath:Show()
			if self:IsHard() then
				timerRavenousFeastCD:Start(27.6, 1, args.destGUID)
			end
		end
	elseif spellId == 342257 or spellId == 342258 or spellId == 342259 then
		if self.Options.SetIconOnShadowForces then
			local icon = spellId == 342257 and (markingSet == "SetOne" and 8 or 6) or spellId == 342258 and 7 or (markingSet == "SetOne" and 6 or 8)
			self:ScanForMobs(args.destGUID, 2, icon, 1, 0.2, 12, "SetIconOnShadowForces")
		end
		timerWickedSlaughterCD:Start(6.1, args.destGUID)
	end
end

function mod:SPELL_AURA_APPLIED(args)
	local spellId = args.spellId
	if spellId == 329636 or spellId == 329808 then--50% transition for Kaal/50% transition for Grashaal
		self.vb.shieldUp = true
		warnHardenedStoneForm:Show(args.destName)
		timerCallShadowForcesCD:Stop()--The only timer that always stops here is this one, rest continue on until boss leaves
		if spellId == 329808 then--Grashaal seems to stop casting this while stoned
			timerSeismicUpheavalCD:Stop()
		end
	elseif spellId == 333913 then
		local amount = args.amount or 1
		LacerationStacks[args.destName] = amount
		if self.Options.InfoFrame then
			DBM.InfoFrame:UpdateTable(LacerationStacks)
		end
	elseif spellId == 334765 then
		if self.Options.SetIconOnHeartRend then
			self:SetIcon(args.destName, self.vb.HeartIcon)
		end
		if args:IsPlayer() then
			specWarnHeartRend:Show()
			specWarnHeartRend:Play("targetyou")
		end
		self.vb.HeartIcon = self.vb.HeartIcon + 1
		warnHeartRend:CombinedShow(0.3, self.vb.heartCount, args.destName)
	elseif spellId == 333377 then
		local icon = self.vb.wickedBladeIcon
		if self.Options.SetIconOnWickedBlade2 then
			self:SetIcon(args.destName, icon, 5)
		end
		if args:IsPlayer() then
			specWarnWickedBlade:Show(self:IconNumToTexture(icon))
			specWarnWickedBlade:Play("mm"..icon)
			yellWickedBlade:Yell(icon, icon, icon)
			yellWickedBladeFades:Countdown(4, nil, icon)
		end
		warnWickedBlade:CombinedShow(0.3, self.vb.bladeCount, args.destName)
		self.vb.wickedBladeIcon = self.vb.wickedBladeIcon + 1
	elseif spellId == 339690 then
		if self.Options.SetIconOnCrystalize then
			self:SetIcon(args.destName, markingSet == "SetOne" and 5 or 1)
		end
		if args:IsPlayer() then
			specWarnCrystalize:Show()
			specWarnCrystalize:Play("targetyou")
			yellCrystalize:Yell()
			yellCrystalizeFades:Countdown(spellId)
		elseif self.Options.SpecWarn339690moveto and DBM:UnitDebuff("player", 333913) then
			specWarnCrystalizeTarget:Show(args.destName)
			specWarnCrystalizeTarget:Play("gathershare")
		else
			warnCrystalize:Show(self.vb.crystalCount, args.destName)
		end
	elseif spellId == 342655 then
		warnVolatileAnimaInfusion:Show(args.destName)
	elseif spellId == 340037 then
		if self:AntiSpam(5, 1) then
			specWarnVolatileStoneShell:Show()
			specWarnVolatileStoneShell:Play("targetchange")
		end
		if self.Options.NPAuraOnVolatileShell then
			DBM.Nameplate:Show(true, args.destGUID, spellId, nil, 4)
		end
	elseif spellId == 342425 and not args:IsPlayer() then
		specWarnStoneFistTaunt:Show(args.destName)
		specWarnStoneFistTaunt:Play("tauntboss")
	elseif spellId == 336212 then
		warnSoldiersOath:Show(args.destName)
	end
end
mod.SPELL_AURA_APPLIED_DOSE = mod.SPELL_AURA_APPLIED

function mod:SPELL_AURA_REMOVED(args)
	local spellId = args.spellId
	if spellId == 329636 or spellId == 329808 then--phase 2 (Kael Departing, Grashaal landing)
		warnHardenedStoneFormOver:Show()
		timerWickedBladeCD:Stop()--Probably stops--resets now
		if spellId == 329636 then
			--Stop Outgoing boss (Kael) timers here
			timerHeartRendCD:Stop()
			timerSerratedSwipeCD:Stop()
			--Start Outgoing boss (Kael) (stuff he still casts airborn) here as well
			timerWickedBladeCD:Start(25.5, self.vb.bladeCount+1)--TODO, Needs more data and fixing, 25.7-32 spell queue seems off
		else
			timerWickedBladeCD:Start(19.6, self.vb.bladeCount+1)
		end
		--If crystalize was off CD going into this phase, the CD is reset.
		--But if crystalize was still ticking down it's CD, it's NOT reset
--		if timerCrystalizeCD:GetRemaining(self.vb.crystalCount+1) <= 0 then
--			timerCrystalizeCD:Stop()
--			timerCrystalizeCD:Start(self:IsMythic() and 55 or 50, self.vb.crystalCount+1)
--		end
	elseif spellId == 333913 then
		LacerationStacks[args.destName] = nil
		if self.Options.InfoFrame then
			DBM.InfoFrame:UpdateTable(LacerationStacks)
		end
	elseif spellId == 334765 then
		if self.Options.SetIconOnHeartRend then
			self:SetIcon(args.destName, 0)
		end
	elseif spellId == 339690 then
		if args:IsPlayer() then
			yellCrystalizeFades:Cancel()
		end
		if self.Options.SetIconOnCrystalize then
			self:SetIcon(args.destName, 0)
		end
	elseif spellId == 340037 then
		if self.Options.NPAuraOnVolatileShell then
			DBM.Nameplate:Hide(true, args.destGUID, spellId)
		end
	end
end

function mod:SPELL_AURA_REMOVED_DOSE(args)
	local spellId = args.spellId
	if spellId == 333913 then
		LacerationStacks[args.destName] = args.amount or 1
		if self.Options.InfoFrame then
			DBM.InfoFrame:UpdateTable(LacerationStacks)
		end
	end
end

function mod:RAID_BOSS_WHISPER(msg)
	if (msg:find("344496") or msg:find("344500")) and self:AntiSpam(4, playerName.."2") then--Eruption Backup (if scan fails)
		if self.Options.SetIconOnEruption2 then
			self:SetIcon(playerName, 4, 4.5)--So icon clears 1 second after
		end
		specWarnReverberatingEruption:Show()
		specWarnReverberatingEruption:Play("runout")
		yellReverberatingEruption:Yell()
		yellReverberatingEruptionFades:Countdown(3.5)--A good 0.5 sec slower
		playerEruption = self.vb.eruptionCount
	elseif msg:find("334009") and self:AntiSpam(4, playerName.."2") then--Leap Backup (if scan fails)
		if self.Options.SetIconOnEruption2 then
			self:SetIcon(playerName, 4, 4.5)--So icon clears 1 second after
		end
		specWarnReverberatingLeap:Show()
		specWarnReverberatingLeap:Play("runout")
		yellReverberatingLeap:Yell()
		yellReverberatingLeapFades:Countdown(3.5)--A good 0.5 sec slower
		playerEruption = self.vb.eruptionCount
	end
end

function mod:OnTranscriptorSync(msg, targetName)
	if (msg:find("344496") or msg:find("344500")) and targetName then--Eruption Backup (if scan fails)
		targetName = Ambiguate(targetName, "none")
		if self:AntiSpam(4, targetName.."2") then--Same antispam as RAID_BOSS_WHISPER on purpose. if player got personal warning they don't need this one
			if self.Options.SetIconOnEruption2 then
				self:SetIcon(targetName, 4, 4.5)--So icon clears 1 second after
			end
			warnReverberatingEruption:Show(targetName)
		end
	elseif msg:find("334009") and targetName then--Leap Backup (if scan fails)
		targetName = Ambiguate(targetName, "none")
		if self:AntiSpam(4, targetName.."2") then--Same antispam as RAID_BOSS_WHISPER on purpose. if player got personal warning they don't need this one
			if self.Options.SetIconOnEruption2 then
				self:SetIcon(targetName, 4, 4.5)--So icon clears 1 second after
			end
			warnReverberatingLeap:Show(targetName)
		end
	end
end

function mod:UNIT_DIED(args)
	local cid = self:GetCIDFromGUID(args.destGUID)
	if cid == 172858 then--stone-legion-goliath
		timerRavenousFeastCD:Stop((castsPerGUID[args.sourceGUID] or 0)+1, args.destGUID)
	elseif cid == 173280 then--stone-legion-skirmisher
		timerWickedSlaughterCD:Stop(args.destGUID)
	elseif cid == 168112 and not self.vb.kaalDead then--Kaal
		self.vb.kaalDead = true
		timerWickedBladeCD:Stop()
		timerHeartRendCD:Stop()
		timerSerratedSwipeCD:Stop()
		timerCallShadowForcesCD:Stop()
		timerCrystalizeCD:Stop()--Yes this stops on kaal death too, because his death causes grashaal to recast it immediately
	elseif cid == 168113 and not self.vb.grashDead then--Grashaal
		self.vb.grashDead = true
		timerReverberatingEruptionCD:Stop()
		timerReverberatingLeapCD:Stop()
		timerSeismicUpheavalCD:Stop()
		timerCrystalizeCD:Stop()
		timerStoneFistCD:Stop()
	end
end

--[[
function mod:SPELL_PERIODIC_DAMAGE(_, _, _, _, destGUID, _, _, _, spellId, spellName)
	if spellId == 270290 and destGUID == UnitGUID("player") and self:AntiSpam(2, 2) then
		specWarnGTFO:Show(spellName)
		specWarnGTFO:Play("watchfeet")
	end
end
mod.SPELL_PERIODIC_MISSED = mod.SPELL_PERIODIC_DAMAGE
--]]
--"<10.92 16:10:19> [UNIT_SPELLCAST_START] General Grashaal(Lightea) - Reverberating Leap - 5.2s [[boss2:Cast-3-2084-2296-21431-334009-0026A47AA9:334009]]", -- [614]
--"<10.92 16:10:19> [CLEU] SPELL_CAST_START#Creature-0-2084-2296-21431-168113-0000247A6F#General Grashaal##nil#334009#Reverberating Leap#nil#nil", -- [616]
--"<10.94 16:10:19> [DBM_Debug] boss2 changed targets to Kngflyven#nil", -- [618]
--"<11.38 16:10:19> [CHAT_MSG_ADDON] RAID_BOSS_WHISPER_SYNC#|TInterface\\Icons\\INV_ElementalEarth2.blp:20|t%s targets you with |cFFFF0000|Hspell:334094|h[Reverberating Leap]|h|r!#Kngflyven-TheMaw", -- [661]
function mod:UNIT_SPELLCAST_START(uId, _, spellId)
	if spellId == 344496 or spellId == 334009 then
		self:BossUnitTargetScanner(uId, "EruptionTarget", 1)
	end
end

function mod:UNIT_SPELLCAST_SUCCEEDED(uId, _, spellId)
	if spellId == 343288 then
		local cid = self:GetUnitCreatureId(uId)
		if cid == 168112 and not self.vb.kaalDead then--Kaal
			self.vb.kaalDead = true
			timerWickedBladeCD:Stop()
			timerHeartRendCD:Stop()
			timerSerratedSwipeCD:Stop()
			timerCallShadowForcesCD:Stop()
			timerCrystalizeCD:Stop()--Yes this stops on kaal death too, because his death causes grashaal to recast it immediately
		elseif cid == 168113 and not self.vb.grashDead then--Grashaal
			self.vb.grashDead = true
			timerReverberatingEruptionCD:Stop()
			timerReverberatingLeapCD:Stop()
			timerSeismicUpheavalCD:Stop()
			timerCrystalizeCD:Stop()
			timerStoneFistCD:Stop()
		end
	end
end

do
	--Delayed function just to make absolute sure RL sync overrides user settings after OnCombatStart functions run
	local function UpdateYellIcons(self, msg)
		markingSet = msg
		self.vb.wickedBladeIcon = msg == "SetOne" and 1 or 2
	end

	function mod:OnSync(msg)
		self:Schedule(3, UpdateYellIcons, self, msg)
	end
end
