From 728aa460a4d29bcadc4bd7d05cc7e57ee5f96254 Mon Sep 17 00:00:00 2001 From: Nefertumm Date: Fri, 3 Dec 2021 04:31:40 -0800 Subject: [PATCH] fix(Scripts/Stratholme): Rewrite Jarien and Sothos fight (#9391) --- .../rev_1638053041040101600.sql | 24 ++ .../Stratholme/boss_jarien_and_sothos.cpp | 355 ++++++++++++++++++ .../EasternKingdoms/Stratholme/stratholme.h | 9 + .../eastern_kingdoms_script_loader.cpp | 2 + 4 files changed, 390 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1638053041040101600.sql create mode 100644 src/server/scripts/EasternKingdoms/Stratholme/boss_jarien_and_sothos.cpp diff --git a/data/sql/updates/pending_db_world/rev_1638053041040101600.sql b/data/sql/updates/pending_db_world/rev_1638053041040101600.sql new file mode 100644 index 000000000..fac8e1b3a --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1638053041040101600.sql @@ -0,0 +1,24 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1638053041040101600'); + +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_jarien' WHERE `entry` = 16101; +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_sothos' WHERE `entry` = 16102; + +DELETE FROM `creature_text` WHERE `CreatureID` IN (16101, 16102, 16103, 16104); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(16101, 0, 0, 'Hello, brother.', 14, 0, 100, 0, 0, 0, 11971, 0, 'Jarien - ON SUMMON'), +(16101, 1, 0, 'Would-be interlopers, I\'m afraid.', 14, 0, 100, 0, 0, 0, 11973, 0, 'Jarien - ON SUMMON - 1'), +(16101, 2, 0, 'Yes, we shall!', 14, 0, 100, 0, 0, 0, 11975, 0, 'Jarien - ON SUMMON - 2'), +(16101, 3, 0, '%s goes into a rage after seeing $n fall in battle!', 16, 0, 100, 0, 0, 0, 11939, 0, 'Jarien - ON SOTHOS DEATH'), +(16102, 0, 0, 'Hello, sister. What have we here?', 14, 0, 100, 0, 0, 0, 11972, 0, 'Sothos - ON SUMMON'), +(16102, 1, 0, 'Shall we slay them for the impertinence of disturbing our sleep?', 14, 0, 100, 0, 0, 0, 11974, 0, 'Sothos - ON SUMMON - 1'), +(16102, 2, 0, '%s goes into a rage after seeing $n fall in battle!', 16, 0, 100, 0, 0, 0, 11939, 0, 'Sothos - ON JARIEN DEATH'), +(16103, 0, 0, 'Thank you for freeing me, my brother, and all of you! We can finally rest in peace now.', 14, 0, 100, 0, 0, 0, 11819, 0, 'Spirit of Jarien - ON BOTH DEATHS'), +(16104, 0, 0, 'Thank you for freeing me, my sister, and all of you! We can finally rest in peace now.', 14, 0, 100, 0, 0, 0, 11859, 0, 'Spirit of Sothos - ON BOTH DEATHS'); + +DELETE FROM `smart_scripts` WHERE `source_type` = 0 AND `entryorguid` IN (16101, 16102); + +-- Fix Jarien and Sothos spawn position +DELETE FROM `smart_scripts` WHERE `entryorguid` = 16046 AND `source_type` = 0; +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(16046, 0, 0, 1, 38, 0, 100, 1, 1, 1, 0, 0, 0, 12, 16101, 8, 0, 0, 0, 0, 8, 0, 0, 0, 0, 3420.13452, -3056.939697, 136.4981, 0.208907, 'Jarien and Sothos Trigger - On Data Set - Spawn Jarien'), +(16046, 0, 1, 0, 61, 0, 100, 1, 1, 1, 0, 0, 0, 12, 16102, 8, 0, 0, 0, 0, 8, 0, 0, 0, 0, 3427.82251, -3055.582764, 136.4981, 3.319085, 'Jarien and Sothos Trigger - Linked with Previous Event - Spawn Sothos'); diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_jarien_and_sothos.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_jarien_and_sothos.cpp new file mode 100644 index 000000000..e3658a3c6 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_jarien_and_sothos.cpp @@ -0,0 +1,355 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "stratholme.h" +#include "TaskScheduler.h" + +enum Texts +{ + // Sothos + SAY_SOTHOS_ON_SUMMON_0 = 0, + SAY_SOTHOS_ON_SUMMON_1 = 1, + EMOTE_SOTHOS_VENGEANCE = 2, + + // Jarien + SAY_JARIEN_ON_SUMMON_0 = 0, + SAY_JARIEN_ON_SUMMON_1 = 1, + SAY_JARIEN_ON_SUMMON_2 = 2, + EMOTE_JARIEN_VENGEANCE = 3, + + // Spirit + SAY_SPIRIT_BOTH_DEAD = 0 +}; + +enum Spells +{ + // Jarien + SPELL_MORTAL_STRIKE = 16856, + SPELL_SHADOW_SHOCK = 22575, + SPELL_CRIPPLE = 20812, + SPELL_CLEAVE = 15284, + + // Sothos + SPELL_SHIELD_CHARGE = 15749, + SPELL_SHIELD_SLAM = 15655, + SPELL_SHIELD_BLOCK = 12169, + SPELL_SHADOW_BOLT = 27646, + SPELL_FEAR = 27641, + + // Both + SPELL_VENGEANCE = 27650 +}; + +enum Phases +{ + PHASE_TALK = 0, + PHASE_FIGHT +}; + +enum Actions +{ + ACTION_PARTNER_DEAD = 0 +}; + +const Position heirloomsPosition = { 3423.389893f, -3055.571045f, 136.49837f, 5.707379f }; + +void HandleBothDead(Creature* creature, bool jarien, Unit* killer) +{ + // Spirit talk + if (jarien) + { + if (Creature* spirit = creature->FindNearestCreature(NPC_SPIRIT_OF_JARIEN, 100.f)) + { + spirit->AttackStop(); + spirit->SetReactState(REACT_PASSIVE); + spirit->AI()->Talk(SAY_SPIRIT_BOTH_DEAD); + } + } + else + { + if (Creature* spirit = creature->FindNearestCreature(NPC_SPIRIT_OF_SOTHOS, 100.f)) + { + spirit->AttackStop(); + spirit->SetReactState(REACT_PASSIVE); + spirit->AI()->Talk(SAY_SPIRIT_BOTH_DEAD); + } + } + + // chest spawn + if (GameObject* chest = killer->SummonGameObject(GO_JARIEN_AND_SOTHOS_HEIRLOOMS, heirloomsPosition.GetPositionX(), heirloomsPosition.GetPositionY(), heirloomsPosition.GetPositionZ(), heirloomsPosition.GetOrientation(), 0.f, 0.f, 0.f, 0.f, 0)) + { + chest->setActive(true); + chest->SetGoState(GO_STATE_READY); + chest->SetLootState(GO_READY); + chest->SetUInt32Value(GAMEOBJECT_FACTION, 35); + } +} + +struct boss_jarien : public BossAI +{ + boss_jarien(Creature* creature) : BossAI(creature, DATA_JARIEN) + { + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + + _talked = false; + _phase = PHASE_TALK; + } + + void Reset() override + { + _scheduler.CancelAll(); + _phase = _talked ? PHASE_FIGHT : PHASE_TALK; + if (_sothosDied) + { + if (Creature* sothos = me->FindNearestCreature(NPC_SOTHOS, 200.f, false)) + { + sothos->Respawn(); + } + } + _sothosDied = false; + _Reset(); + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + Talk(SAY_JARIEN_ON_SUMMON_0); + + _scheduler.Schedule(6s, [this](TaskContext /*context*/) + { + Talk(SAY_JARIEN_ON_SUMMON_1); + }) + .Schedule(12s, [this](TaskContext /*context*/) + { + Talk(SAY_JARIEN_ON_SUMMON_2); + _talked = true; + _phase = PHASE_FIGHT; + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + }); + } + + void JustDied(Unit* killer) override + { + _JustDied(); + if (Creature * sothos = me->FindNearestCreature(NPC_SOTHOS, 200.f)) + { + sothos->AI()->DoAction(ACTION_PARTNER_DEAD); + } + + me->SummonCreature(NPC_SPIRIT_OF_JARIEN, me->GetPosition()); + + if (_sothosDied) + { + HandleBothDead(me, true, killer); + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_PARTNER_DEAD) + { + me->SetFullHealth(); + DoCastSelf(SPELL_VENGEANCE); + Talk(EMOTE_JARIEN_VENGEANCE); + _sothosDied = true; + } + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + _scheduler.Schedule(5s, [this](TaskContext context) + { + DoCastVictim(SPELL_SHADOW_SHOCK); + context.Repeat(10s, 12s); + }) + .Schedule(3s, [this](TaskContext context) + { + DoCastVictim(SPELL_CLEAVE); + context.Repeat(10s); + }) + .Schedule(11s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_CRIPPLE); + context.Repeat(30s); + }) + .Schedule(10s, [this](TaskContext context) + { + DoCastVictim(SPELL_MORTAL_STRIKE); + context.Repeat(15s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && _phase != PHASE_TALK) + { + return; + } + + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + + protected: + TaskScheduler _scheduler; + uint8 _phase; + bool _talked; + bool _sothosDied; +}; + +struct boss_sothos : public BossAI +{ + boss_sothos(Creature* creature) : BossAI(creature, DATA_SOTHOS) + { + _scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + + _talked = false; + _phase = PHASE_TALK; + } + + void Reset() override + { + _scheduler.CancelAll(); + _phase = _talked ? PHASE_FIGHT : PHASE_TALK; + if (_jarienDied) + { + if (Creature* jarien = me->FindNearestCreature(NPC_JARIEN, 200.f, false)) + { + jarien->Respawn(); + } + } + _jarienDied = false; + _Reset(); + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + _scheduler.Schedule(12s, [this](TaskContext /*context*/) + { + _talked = true; + _phase = PHASE_FIGHT; + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + }) + .Schedule(3s, [this](TaskContext /*context*/) + { + Talk(SAY_SOTHOS_ON_SUMMON_0); + }) + .Schedule(9s, [this](TaskContext /*context*/) + { + Talk(SAY_SOTHOS_ON_SUMMON_1); + }); + } + + void JustDied(Unit* killer) override + { + _JustDied(); + if (Creature* jarien = me->FindNearestCreature(NPC_JARIEN, 200.f)) + { + jarien->AI()->DoAction(ACTION_PARTNER_DEAD); + } + + me->SummonCreature(NPC_SPIRIT_OF_SOTHOS, me->GetPosition()); + + if (_jarienDied) + { + HandleBothDead(me, false, killer); + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_PARTNER_DEAD) + { + me->SetFullHealth(); + DoCastSelf(SPELL_VENGEANCE); + Talk(EMOTE_SOTHOS_VENGEANCE); + _jarienDied = true; + } + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + _scheduler.Schedule(10s, [this](TaskContext context) + { + DoCastAOE(SPELL_FEAR); + context.Repeat(18s, 20s); + }) + .Schedule(9s, [this](TaskContext context) + { + DoCastAOE(SPELL_SHADOW_BOLT); + context.Repeat(10s, 11s); + }) + .Schedule(15s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_SHIELD_CHARGE); + context.Repeat(); + }) + .Schedule(3s, [this](TaskContext context) + { + DoCastSelf(SPELL_SHIELD_BLOCK); + context.Repeat(10s, 12s); + }) + .Schedule(4s, [this](TaskContext context) + { + DoCastVictim(SPELL_SHIELD_SLAM); + context.Repeat(14s); + }); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && _phase != PHASE_TALK) + { + return; + } + + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + + protected: + TaskScheduler _scheduler; + uint8 _phase; + bool _talked; + bool _jarienDied; +}; + +void AddSC_boss_jarien_and_sothos() +{ + RegisterStratholmeCreatureAI(boss_jarien); + RegisterStratholmeCreatureAI(boss_sothos); +} diff --git a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.h b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.h index 1f94dc2ce..c51eb32ec 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.h +++ b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.h @@ -33,6 +33,8 @@ enum DataTypes DATA_BARON_RUN_NONE = 0, DATA_BARON_RUN_GATE = 1, + DATA_JARIEN = 2, + DATA_SOTHOS = 3 }; enum CreatureIds @@ -47,6 +49,10 @@ enum CreatureIds NPC_PLAGUED_RAT = 10441, NPC_PLAGUED_INSECT = 10461, NPC_PLAGUED_MAGGOT = 10536, + NPC_JARIEN = 16101, + NPC_SOTHOS = 16102, + NPC_SPIRIT_OF_JARIEN = 16103, + NPC_SPIRIT_OF_SOTHOS = 16104 }; enum GameobjectIds @@ -64,6 +70,7 @@ enum GameobjectIds GO_PORT_TRAP_GATE_2 = 175350, // Gate trap scarlet side GO_PORT_TRAP_GATE_3 = 175355, // Gate trap undead side GO_PORT_TRAP_GATE_4 = 175354, + GO_JARIEN_AND_SOTHOS_HEIRLOOMS = 181083 }; enum MiscIds @@ -98,4 +105,6 @@ inline AI* GetStratholmeAI(T* obj) return GetInstanceAI(obj, StratholmeScriptName); } +#define RegisterStratholmeCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetStratholmeAI) + #endif diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 40ab731a0..58cc5fa7f 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -100,6 +100,7 @@ void AddSC_boss_darkmaster_gandling(); void AddSC_instance_scholomance(); //Scholomance void AddSC_instance_shadowfang_keep(); //Shadowfang keep void AddSC_boss_baroness_anastari(); +void AddSC_boss_jarien_and_sothos(); void AddSC_instance_stratholme(); //Stratholme void AddSC_instance_sunken_temple(); //Sunken Temple void AddSC_instance_sunwell_plateau(); //Sunwell Plateau @@ -242,6 +243,7 @@ void AddEasternKingdomsScripts() AddSC_instance_scholomance(); //Scholomance AddSC_instance_shadowfang_keep(); //Shadowfang keep AddSC_boss_baroness_anastari(); + AddSC_boss_jarien_and_sothos(); AddSC_instance_stratholme(); //Stratholme AddSC_instance_sunken_temple(); //Sunken Temple AddSC_instance_sunwell_plateau(); //Sunwell Plateau