diff options
3 files changed, 180 insertions, 243 deletions
diff --git a/sql/updates/world/3.3.5/2025_08_10_00_world.sql b/sql/updates/world/3.3.5/2025_08_10_00_world.sql new file mode 100644 index 00000000000..2c8d752352f --- /dev/null +++ b/sql/updates/world/3.3.5/2025_08_10_00_world.sql @@ -0,0 +1,9 @@ +-- +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_sartura_whirlwind'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(26084, 'spell_sartura_whirlwind'), +(26686, 'spell_sartura_whirlwind'); + +DELETE FROM `creature_text` WHERE `CreatureID` = 15516 AND `GroupID` = 3; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(15516,3,0,"%s goes into a frenzy!",16,0,100,0,0,0,2384,0,"sartura EMOTE_FRENZY"); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp index d11116f2441..b95c5652fb2 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp @@ -15,304 +15,229 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Sartura -SD%Complete: 95 -SDComment: -SDCategory: Temple of Ahn'Qiraj -EndScriptData */ - #include "ScriptMgr.h" #include "InstanceScript.h" #include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" #include "temple_of_ahnqiraj.h" #include "Player.h" -enum Sartura +enum SarturaTexts { - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_DEATH = 2, + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2, + EMOTE_FRENZY = 3 +}; - SPELL_WHIRLWIND = 26083, - SPELL_ENRAGE = 28747, //Not sure if right ID. - SPELL_ENRAGEHARD = 28798, +enum SarturaSpells +{ + // Sartura + SPELL_SUNDERING_CLEAVE = 25174, + SPELL_WHIRLWIND = 26083, + SPELL_FRENZY = 8269, + SPELL_BERSERK = 27680, + + // Guard + SPELL_KNOCKBACK = 26027, + SPELL_WHIRLWIND_GUARD = 26038 +}; - //Guard Spell - SPELL_WHIRLWINDADD = 26038, - SPELL_KNOCKBACK = 26027 +enum SarturaEvents +{ + // Sartura + EVENT_SUNDERING_CLEAVE = 1, + EVENT_WHIRLWIND, + EVENT_FRENZY, + EVENT_BERSERK, + + // Guard + EVENT_KNOCKBACK, + EVENT_WHIRLWIND_GUARD }; -class boss_sartura : public CreatureScript +// 15516 - Battleguard Sartura +struct boss_sartura : public BossAI { -public: - boss_sartura() : CreatureScript("boss_sartura") { } + boss_sartura(Creature* creature) : BossAI(creature, DATA_SARTURA), _frenzied(false) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetAQ40AI<boss_sarturaAI>(creature); + _Reset(); + _frenzied = false; } - struct boss_sarturaAI : public BossAI + void JustEngagedWith(Unit* who) override { - boss_sarturaAI(Creature* creature) : BossAI(creature, DATA_SARTURA) - { - Initialize(); - } + Talk(SAY_AGGRO); + BossAI::JustEngagedWith(who); - void Initialize() + events.ScheduleEvent(EVENT_SUNDERING_CLEAVE, 2s, 5s); + events.ScheduleEvent(EVENT_WHIRLWIND, 10s, 20s); + events.ScheduleEvent(EVENT_BERSERK, 10min); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (!_frenzied && me->HealthBelowPctDamaged(25, damage)) { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = urand(3000, 7000); - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = urand(45000, 55000); - AggroResetEnd_Timer = 5000; - EnrageHard_Timer = 10 * 60000; - - WhirlWind = false; - AggroReset = false; - Enraged = false; - EnragedHard = false; + _frenzied = true; + events.ScheduleEvent(EVENT_FRENZY, 0s); } + } - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 EnrageHard_Timer; + void OnSpellCast(SpellInfo const* spell) override + { + if (spell->Id == SPELL_FRENZY) + Talk(EMOTE_FRENZY); + } - bool Enraged; - bool EnragedHard; - bool WhirlWind; - bool AggroReset; + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } - void Reset() override - { - Initialize(); - _Reset(); - } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + } - void JustEngagedWith(Unit* who) override - { - Talk(SAY_AGGRO); - BossAI::JustEngagedWith(who); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - _JustDied(); - } + events.Update(diff); - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void UpdateAI(uint32 diff) override + while (uint32 eventId = events.ExecuteEvent()) { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (WhirlWind) + switch (eventId) { - if (WhirlWindRandom_Timer <= diff) - { - //Attack random Gamers - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true)) - { - AddThreat(target, 1.0f); - AttackStart(target); - } - WhirlWindRandom_Timer = urand(3000, 7000); - } else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer <= diff) - { - WhirlWind = false; - WhirlWind_Timer = urand(25000, 40000); - } else WhirlWindEnd_Timer -= diff; + case EVENT_SUNDERING_CLEAVE: + DoCastVictim(SPELL_SUNDERING_CLEAVE); + events.Repeat(2s, 5s); + break; + case EVENT_WHIRLWIND: + DoCastSelf(SPELL_WHIRLWIND); + events.Repeat(20s, 25s); + break; + case EVENT_FRENZY: + DoCastSelf(SPELL_FRENZY); + break; + case EVENT_BERSERK: + DoCastSelf(SPELL_BERSERK); + break; + default: + break; } - if (!WhirlWind) - { - if (WhirlWind_Timer <= diff) - { - DoCast(me, SPELL_WHIRLWIND); - WhirlWind = true; - WhirlWindEnd_Timer = 15000; - } else WhirlWind_Timer -= diff; - - if (AggroReset_Timer <= diff) - { - //Attack random Gamers - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true)) - { - AddThreat(target, 1.0f); - AttackStart(target); - } - AggroReset = true; - AggroReset_Timer = urand(2000, 5000); - } else AggroReset_Timer -= diff; - - if (AggroReset) - { - if (AggroResetEnd_Timer <= diff) - { - AggroReset = false; - AggroResetEnd_Timer = 5000; - AggroReset_Timer = urand(35000, 45000); - } else AggroResetEnd_Timer -= diff; - } - - //If she is 20% enrage - if (!Enraged) - { - if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false)) - { - DoCast(me, SPELL_ENRAGE); - Enraged = true; - } - } - - //After 10 minutes hard enrage - if (!EnragedHard) - { - if (EnrageHard_Timer <= diff) - { - DoCast(me, SPELL_ENRAGEHARD); - EnragedHard = true; - } else EnrageHard_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - }; + DoMeleeAttackIfReady(); + } + +private: + bool _frenzied; }; -class npc_sartura_royal_guard : public CreatureScript +// 15984 - Sartura's Royal Guard +struct npc_sartura_royal_guard : public ScriptedAI { -public: - npc_sartura_royal_guard() : CreatureScript("npc_sartura_royal_guard") { } + npc_sartura_royal_guard(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetAQ40AI<npc_sartura_royal_guardAI>(creature); + _events.Reset(); } - struct npc_sartura_royal_guardAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { - npc_sartura_royal_guardAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + _events.ScheduleEvent(EVENT_KNOCKBACK, 5s, 10s); + _events.ScheduleEvent(EVENT_WHIRLWIND_GUARD, 10s, 15s); + } - void Initialize() - { - WhirlWind_Timer = 30000; - WhirlWindRandom_Timer = urand(3000, 7000); - WhirlWindEnd_Timer = 15000; - AggroReset_Timer = urand(45000, 55000); - AggroResetEnd_Timer = 5000; - KnockBack_Timer = 10000; - - WhirlWind = false; - AggroReset = false; - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - uint32 WhirlWind_Timer; - uint32 WhirlWindRandom_Timer; - uint32 WhirlWindEnd_Timer; - uint32 AggroReset_Timer; - uint32 AggroResetEnd_Timer; - uint32 KnockBack_Timer; + _events.Update(diff); - bool WhirlWind; - bool AggroReset; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void Reset() override + while (uint32 eventId = _events.ExecuteEvent()) { - Initialize(); - } + switch (eventId) + { + case EVENT_KNOCKBACK: + DoCastSelf(SPELL_KNOCKBACK); + _events.Repeat(20s, 30s); + break; + case EVENT_WHIRLWIND_GUARD: + DoCastSelf(SPELL_WHIRLWIND_GUARD); + _events.Repeat(10s, 20s); + break; + default: + break; + } - void JustEngagedWith(Unit* /*who*/) override - { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; + DoMeleeAttackIfReady(); + } - if (!WhirlWind && WhirlWind_Timer <= diff) - { - DoCast(me, SPELL_WHIRLWINDADD); - WhirlWind = true; - WhirlWind_Timer = urand(25000, 40000); - WhirlWindEnd_Timer = 15000; - } else WhirlWind_Timer -= diff; +private: + EventMap _events; +}; - if (WhirlWind) - { - if (WhirlWindRandom_Timer <= diff) - { - //Attack random Gamers - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true)) - { - AddThreat(target, 1.0f); - AttackStart(target); - } - - WhirlWindRandom_Timer = urand(3000, 7000); - } else WhirlWindRandom_Timer -= diff; - - if (WhirlWindEnd_Timer <= diff) - { - WhirlWind = false; - } else WhirlWindEnd_Timer -= diff; - } +// 26084 - Whirlwind +// 26686 - Whirlwind +class spell_sartura_whirlwind : public SpellScript +{ + PrepareSpellScript(spell_sartura_whirlwind); - if (!WhirlWind) - { - if (AggroReset_Timer <= diff) - { - //Attack random Gamers - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true)) - { - AddThreat(target, 1.0f); - AttackStart(target); - } - - AggroReset = true; - AggroReset_Timer = urand(2000, 5000); - } else AggroReset_Timer -= diff; - - if (KnockBack_Timer <= diff) - { - DoCast(me, SPELL_WHIRLWINDADD); - KnockBack_Timer = urand(10000, 20000); - } else KnockBack_Timer -= diff; - } + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (!caster) + return; + + SpellInfo const* spellInfo = GetTriggeringSpell(); + if (!spellInfo) + return; - if (AggroReset) + if (AuraEffect const* eff = caster->GetAuraEffect(spellInfo->Id, EFFECT_0)) + { + if (eff->GetTickNumber() != spellInfo->GetMaxTicks()) { - if (AggroResetEnd_Timer <= diff) - { - AggroReset = false; - AggroResetEnd_Timer = 5000; - AggroReset_Timer = urand(30000, 40000); - } else AggroResetEnd_Timer -= diff; + if (spellInfo->Id == SPELL_WHIRLWIND_GUARD) + if (urand(0, 2)) + return; + + // This requires additional research + caster->GetThreatManager().ResetAllThreat(); + if (Unit* target = caster->AI()->SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + caster->GetThreatManager().AddThreat(target, 100000.0f); } - - DoMeleeAttackIfReady(); + else + caster->GetThreatManager().ResetAllThreat(); } - }; + } + void Register() override + { + OnEffectHit += SpellEffectFn(spell_sartura_whirlwind::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } }; // 4052 @@ -333,7 +258,8 @@ public: void AddSC_boss_sartura() { - new boss_sartura(); - new npc_sartura_royal_guard(); + RegisterAQ40CreatureAI(boss_sartura); + RegisterAQ40CreatureAI(npc_sartura_royal_guard); + RegisterSpellScript(spell_sartura_whirlwind); new at_aq_battleguard_sartura(); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h index 15bbd45cbaa..cc8dd0c9431 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h @@ -89,4 +89,6 @@ inline AI* GetAQ40AI(T* obj) return GetInstanceAI<AI>(obj, AQ40ScriptName); } +#define RegisterAQ40CreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetAQ40AI) + #endif |