mirror of
https://github.com/araxiaonline/Delves.git
synced 2026-06-13 03:42:24 -04:00
212 lines
6.8 KiB
Lua
212 lines
6.8 KiB
Lua
--------------------------------------------------------------------------------
|
||
-- 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) |