Files
Delves/BOSS Scripts (Lua)/ArathiFarmlands/Savathun.lua
2026-01-01 17:09:37 -05:00

212 lines
6.8 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
--------------------------------------------------------------------------------
-- Savathûn, The Redeemer (Arathi Highlands) - Boss 1
-- NPC ID: 600700
-- FINAL 100% CLEAN, 100% WORKING, ZERO CRASHES
-- Uses explicit Event IDs + correct self signature everywhere
--------------------------------------------------------------------------------
print("Arathi Highlands Boss 3 - Savathûn, The Redeemer Loaded")
local BOSS_ID = 600700
-- Models
local MODEL_P1 = 30972 -- Veiled form
local MODEL_P2 = 27710 -- True demonic form
-- Phase 1 spells (>50%)
local BLACK_CLEAVE = 33480
local FROST_STRIKE = 60951
local ICE_BOULDER = 54673
local CHAINS_OF_ICE = 61077
-- Phase 2 spells (≤50%)
local PLAGUE_BITE = 60678
local FEL_BREATH = 38813
local DISEASE_CLOUD = 58808
local RADIATION_AURA = 21862
local GHOUL_PLAGUE = 16458
-- ONE-TIME at 50%
local FIRE_NOVA = 61163
local CHAOS_NOVA = 37997
-- EXPLICIT EVENT IDs
local EVENT_BLACK_CLEAVE = 101
local EVENT_FROST_STRIKE = 102
local EVENT_ICE_BOULDER = 103
local EVENT_CHAINS_WARNING = 104
local EVENT_PLAGUE_BITE = 201
local EVENT_FEL_BREATH = 202
local EVENT_DISEASE_CLOUD = 203
local EVENT_PHASE_CHECK = 999 -- Never removed during combat
-- Thresholds
local TH_85 = 85
local TH_75 = 75
local TH_50 = 50
local TH_35 = 35
local TH_10 = 10
-- GUID-safe phase table
local phases = {}
-- Yells
local CHAINS_WARNINGS = {
"Be bound by my will!",
"Your freedom ends here!",
"Chains of eternity claim you!"
}
local function GetTank(self) return self:GetVictim() end
local function GetFarthest(self) return self:GetAITarget(4, true) end
--------------------------------------------------------------------------------
-- PHASE 1 ABILITIES
--------------------------------------------------------------------------------
local function CastBlackCleave(_, _, _, self)
if self:IsInCombat() then
local t = GetTank(self)
if t then self:CastSpell(t, BLACK_CLEAVE, true) end
end
end
local function CastFrostStrike(_, _, _, self)
if self:IsInCombat() then
local t = GetTank(self)
if t then self:CastSpell(t, FROST_STRIKE, true) end
end
end
local function CastIceBoulder(_, _, _, self)
if self:IsInCombat() then
self:CastSpell(self, ICE_BOULDER, true)
end
end
local function CastChainsOfIce(_, _, _, self)
if self:IsInCombat() then
local target = GetFarthest(self)
if target then self:CastSpell(target, CHAINS_OF_ICE, true) end
end
end
-- FIXED: Now correctly accepts 4 args and uses self
local function WarnAndCastChains(_, _, _, self)
if not self:IsInCombat() then return end
self:SendUnitYell(CHAINS_WARNINGS[math.random(#CHAINS_WARNINGS)], 0)
self:RegisterEvent(function(_, _, _, creature)
if creature:IsInCombat() then CastChainsOfIce(_, _, _, creature) end
end, 5000, 1)
end
--------------------------------------------------------------------------------
-- PHASE 2 ABILITIES
--------------------------------------------------------------------------------
local function CastPlagueBite(_, _, _, self)
if self:IsInCombat() then
local t = GetTank(self)
if t then self:CastSpell(t, PLAGUE_BITE, true) end
end
end
local function CastFelBreath(_, _, _, self)
if self:IsInCombat() then
self:CastSpell(self, FEL_BREATH, true)
end
end
local function CastDiseaseCloud(_, _, _, self)
if self:IsInCombat() then
self:CastSpell(self, DISEASE_CLOUD, true)
end
end
--------------------------------------------------------------------------------
-- PHASE CHECKER PRESERVED FOREVER
--------------------------------------------------------------------------------
local function PhaseCheck(eventId, _, _, self)
if not self:IsInCombat() or self:IsDead() then
self:RemoveEventById(eventId)
return
end
local guid = self:GetGUIDLow()
phases[guid] = phases[guid] or {}
local p = phases[guid]
local hp = self:GetHealthPct()
if hp <= TH_10 and not p[10] then
p[10] = true
self:SendUnitYell("I am eternal! You are naught but dust!", 0)
elseif hp <= TH_35 and not p[35] then
p[35] = true
self:SendUnitYell("The curse intensifies! Struggle is futile!", 0)
elseif hp <= TH_50 and not p[50] then
p[50] = true
-- TRUE FORM + ONE-TIME NOVAS
self:SetDisplayId(MODEL_P2)
self:SendUnitYell("BEHOLD MY TRUE FORM!!!", 0)
self:CastSpell(self, RADIATION_AURA, true)
self:CastSpell(self, GHOUL_PLAGUE, true)
self:CastSpell(self, FIRE_NOVA, true)
self:CastSpell(self, CHAOS_NOVA, true)
-- ONLY REMOVE PHASE 1 EVENTS PhaseCheck (999) and future P2 events are 100% safe
self:RemoveEventById(EVENT_BLACK_CLEAVE)
self:RemoveEventById(EVENT_FROST_STRIKE)
self:RemoveEventById(EVENT_ICE_BOULDER)
self:RemoveEventById(EVENT_CHAINS_WARNING)
-- START PHASE 2 ROTATION
self:RegisterEvent(CastPlagueBite, 20000, 0, EVENT_PLAGUE_BITE)
self:RegisterEvent(CastFelBreath, 45000, 0, EVENT_FEL_BREATH)
self:RegisterEvent(CastDiseaseCloud, 60000, 0, EVENT_DISEASE_CLOUD)
elseif hp <= TH_75 and not p[75] then
p[75] = true
self:SendUnitYell("Doubt is your true enemy! I feed on your fear!", 0)
elseif hp <= TH_85 and not p[85] then
p[85] = true
self:SendUnitYell("You cannot stop my plan! My ascension is complete!", 0)
end
end
--------------------------------------------------------------------------------
-- COMBAT EVENTS
--------------------------------------------------------------------------------
local function OnEnterCombat(event, creature, target)
creature:SendUnitYell("Your souls are weak! I will cleanse this realm in your blood!", 0)
creature:SetDisplayId(MODEL_P1)
local guid = creature:GetGUIDLow()
phases[guid] = {}
creature:RegisterEvent(CastBlackCleave, 45000, 0, EVENT_BLACK_CLEAVE)
creature:RegisterEvent(CastFrostStrike, 30000, 0, EVENT_FROST_STRIKE)
creature:RegisterEvent(CastIceBoulder, 50000, 0, EVENT_ICE_BOULDER)
creature:RegisterEvent(WarnAndCastChains, 60000, 0, EVENT_CHAINS_WARNING)
creature:RegisterEvent(PhaseCheck, 1000, 0, EVENT_PHASE_CHECK)
end
local function OnLeaveCombat(event, creature)
creature:RemoveEvents()
creature:SendUnitYell("You merely delayed the inevitable. I shall return!", 0)
creature:SetDisplayId(MODEL_P1)
phases[creature:GetGUIDLow()] = nil
end
local function OnDied(event, creature, killer)
creature:RemoveEvents()
creature:SendUnitYell("My power... was not enough...", 0)
phases[creature:GetGUIDLow()] = nil
end
RegisterCreatureEvent(BOSS_ID, 1, OnEnterCombat)
RegisterCreatureEvent(BOSS_ID, 2, OnLeaveCombat)
RegisterCreatureEvent(BOSS_ID, 4, OnDied)