aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTeleqraph <nyrdeveloper@gmail.com>2023-10-22 05:23:04 +0200
committerGitHub <noreply@github.com>2023-10-22 05:23:04 +0200
commit3d3979f1cabf59321fbafcde1f0d1e600d29e974 (patch)
tree8820cd5ff0d829d1422d2a11416bc2651037bb97 /src
parent13b5e4990687b92ed2d1db20eb12eed182d5a6ff (diff)
Scripts/SOD: Implement Sylvanas Windrunner introduction (#28554)
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp489
-rw-r--r--src/server/scripts/Shadowlands/SanctumOfDomination/instance_sanctum_of_domination.cpp254
-rw-r--r--src/server/scripts/Shadowlands/SanctumOfDomination/sanctum_of_domination.h117
-rw-r--r--src/server/scripts/Shadowlands/shadowlands_script_loader.cpp9
4 files changed, 869 insertions, 0 deletions
diff --git a/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp b/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp
new file mode 100644
index 00000000000..4ed74a7b144
--- /dev/null
+++ b/src/server/scripts/Shadowlands/SanctumOfDomination/boss_sylvanas_windrunner.cpp
@@ -0,0 +1,489 @@
+/*
+ * This file is part of the TrinityCore 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 General Public License as published by the
+ * Free Software Foundation; either version 2 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 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "AreaTrigger.h"
+#include "AreaTriggerAI.h"
+#include "Conversation.h"
+#include "CreatureAI.h"
+#include "CreatureAIImpl.h"
+#include "InstanceScript.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "Player.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "sanctum_of_domination.h"
+
+Position const SylvanasIntroPos[4] =
+{
+ { 231.15799f, -832.816f, 4105.0386f },
+ { 242.00348f, -840.51215f, 4105.0386f },
+ { 241.23091f, -830.0955f, 4105.0386f },
+ { 225.73611f, -844.0746f, 4104.9882f, 1.3613f }
+};
+
+enum SylvanasSpells
+{
+ // Stances
+ SPELL_RANGER_BOW_STANCE = 347560,
+ SPELL_RANGER_DAGGERS_STANCE = 348010,
+
+ // Miscellanea
+ SPELL_GENERIC_ANCHOR_HERE = 45313,
+ SPELL_GENERIC_DUAL_WIELD = 42459,
+ SPELL_SYLVANAS_DISPLAY_POWER_SUFFERING = 352311,
+ SPELL_SYLVANAS_ROOT = 347608
+};
+
+enum SylvanasPhases
+{
+ PHASE_ONE = 1,
+ PHASE_INTERMISSION = 4,
+ PHASE_TWO = 2,
+ PHASE_THREE = 3,
+ PHASE_INTERMISSION_WORLD_STATE = 11
+};
+
+enum SylvanasEventGroups
+{
+ EVENT_GROUP_NORMAL_EVENTS = 1,
+ EVENT_GROUP_WINDRUNNER_EVENTS = 2
+};
+
+enum SylvanasEvents
+{
+ EVENT_INTRODUCTION = 1,
+ EVENT_SIZE_MAX = 200
+};
+
+enum SylvanasTexts
+{
+ SAY_ENGAGE = 0,
+ SAY_SLAY = 1,
+ SAY_DISENGAGE = 2
+};
+
+enum SylvanasConversations
+{
+ CONVERSATION_SYLVANAS_INTRODUCTION = 17368,
+ CONVERSATION_SYLVANAS_INTRODUCTION_ACTOR_SYLVANAS_ID = 0,
+ CONVERSATION_SYLVANAS_INTRODUCTION_ACTOR_BOLVAR_ID = 1
+};
+
+enum SylvanasSpawnGroups
+{
+ SPAWN_GROUP_CHAMPIONS_FIRST_PHASE = 0,
+ SPAWN_GROUP_CHAMPIONS_THIRD_PHASE,
+ SPAWN_GROUP_CHAMPIONS_OUTRODUCTION
+};
+
+enum SylvanasPoints
+{
+ POINT_INTRODUCTION = 1
+};
+
+enum SylvanasSpellVisualKits
+{
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_01 = 150067,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_02 = 150068,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_03 = 150069,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_04 = 150071,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_05 = 150072,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_06 = 150070,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_07 = 150074,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_08 = 150077,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_09 = 150076,
+ SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_10 = 150075,
+ SPELL_VISUAL_KIT_BOLVAR_INTRODUCTION_TALK_01 = 150073,
+
+ SPELL_VISUAL_KIT_SYLVANAS_TELEPORT = 150078
+};
+
+// 178355 - Sylvanas Shadowcopy (Riding)
+struct npc_sylvanas_windrunner_shadowcopy_riding : public ScriptedAI
+{
+ npc_sylvanas_windrunner_shadowcopy_riding(Creature* creature) : ScriptedAI(creature) { }
+
+ void JustAppeared() override
+ {
+ me->SetImmuneToAll(true, true);
+ me->SetUninteractible(true);
+ me->SetReactState(REACT_PASSIVE);
+ }
+};
+
+// 175732 - Sylvanas Windrunner
+struct boss_sylvanas_windrunner : public BossAI
+{
+ boss_sylvanas_windrunner(Creature* creature) : BossAI(creature, DATA_SYLVANAS_WINDRUNNER) { }
+
+ void JustAppeared() override
+ {
+ DoCastSelf(SPELL_GENERIC_DUAL_WIELD, true);
+ DoCastSelf(SPELL_SYLVANAS_DISPLAY_POWER_SUFFERING, true);
+
+ me->SetPower(me->GetPowerType(), 0);
+
+ if (instance->GetData(DATA_SYLVANAS_INTRODUCTION) == DONE)
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1);
+ me->SetImmuneToAll(false);
+ me->SetSpeed(MOVE_RUN, 14.0f);
+ }
+ else
+ {
+ me->SetUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1);
+ me->SetImmuneToAll(true);
+ me->SetSpeed(MOVE_RUN, 4.0f);
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ Talk(SAY_DISENGAGE);
+
+ _EnterEvadeMode();
+
+ summons.DespawnAll();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ _DespawnAtEvade();
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ // Note: every creature involved in the fight adds UNIT_FLAG_PET_IN_COMBAT or UNIT_FLAG_RENAME when engaging, meaning they're most likely summoned by Sylvanas.
+ me->SummonCreatureGroup(SPAWN_GROUP_CHAMPIONS_FIRST_PHASE);
+
+ instance->DoUpdateWorldState(WORLD_STATE_SYLVANAS_ENCOUNTER_PHASE, PHASE_ONE);
+
+ events.Reset();
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE)
+ return;
+
+ if (id == POINT_INTRODUCTION)
+ DoCastSelf(SPELL_GENERIC_ANCHOR_HERE, true);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (!victim->IsPlayer())
+ return;
+
+ Talk(SAY_SLAY);
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
+
+ Talk(SAY_ENGAGE);
+
+ instance->DoUpdateWorldState(WORLD_STATE_SYLVANAS_ENCOUNTER_PHASE, PHASE_ONE);
+
+ events.SetPhase(PHASE_ONE);
+
+ // Note: Sylvanas uses her root with 2s at the beginning of the encounter, most likely to avoid moving when engaging at stance switch.
+ DoCastSelf(SPELL_SYLVANAS_ROOT, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_DURATION, 2000));
+
+ // Note: we won't allow engaging until Phase 1 PR is merged.
+ me->Say("Only introduction is implemented so far, evading.", LANG_UNIVERSAL);
+ EnterEvadeMode(EvadeReason::Other);
+ }
+};
+
+// 45 - Sylvanas Windrunner's Position Z Check (Serverside)
+struct at_sylvanas_windrunner_z_check : AreaTriggerAI
+{
+ at_sylvanas_windrunner_z_check(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ if (!unit->IsAlive())
+ return;
+
+ if (Player* player = unit->ToPlayer())
+ {
+ if (player->IsGameMaster())
+ return;
+
+ if (player->IsAlive())
+ player->KillSelf(false);
+ }
+ }
+};
+
+// 46 - Sylvanas Windrunner's Conversation Introduction (Serverside)
+struct at_sylvanas_windrunner_introduction : AreaTriggerAI
+{
+ at_sylvanas_windrunner_introduction(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ InstanceScript* instance = at->GetInstanceScript();
+ if (!instance)
+ return;
+
+ Player* player = unit->ToPlayer();
+ if (!player || player->IsGameMaster())
+ return;
+
+ if (Creature* sylvanas = instance->GetCreature(DATA_SYLVANAS_WINDRUNNER))
+ Conversation::CreateConversation(CONVERSATION_SYLVANAS_INTRODUCTION, sylvanas, sylvanas->GetPosition(), ObjectGuid::Empty);
+
+ at->Remove();
+ }
+};
+
+// 17368 - Sylvanas Windrunner's Introduction (Conversation)
+class conversation_sylvanas_windrunner_introduction : public ConversationScript
+{
+public:
+ conversation_sylvanas_windrunner_introduction() : ConversationScript("conversation_sylvanas_windrunner_introduction") { }
+
+ void OnConversationCreate(Conversation* conversation, Unit* creator) override
+ {
+ InstanceScript* instance = creator->GetInstanceScript();
+ if (!instance)
+ return;
+
+ Creature* bolvar = instance->GetCreature(DATA_BOLVAR_FORDRAGON_PINNACLE);
+ if (!bolvar)
+ return;
+
+ instance->SetData(DATA_SYLVANAS_INTRODUCTION, IN_PROGRESS);
+ conversation->AddActor(NPC_BOLVAR_FORDRAGON_PINNACLE, CONVERSATION_SYLVANAS_INTRODUCTION_ACTOR_BOLVAR_ID, bolvar->GetGUID());
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION, 5s + 500ms);
+ }
+
+ void OnConversationUpdate(Conversation* conversation, uint32 diff) override
+ {
+ _events.Update(diff);
+
+ uint32 eventId = _events.ExecuteEvent();
+ Creature* sylvanas = nullptr;
+ Creature* bolvar = nullptr;
+
+ if (eventId)
+ {
+ sylvanas = conversation->GetActorCreature(CONVERSATION_SYLVANAS_INTRODUCTION_ACTOR_SYLVANAS_ID);
+ if (!sylvanas)
+ return;
+
+ bolvar = conversation->GetActorCreature(CONVERSATION_SYLVANAS_INTRODUCTION_ACTOR_BOLVAR_ID);
+ if (!bolvar)
+ return;
+ }
+
+ switch (eventId)
+ {
+ case EVENT_INTRODUCTION:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_01, 0, 0);
+ sylvanas->SetFacingToObject(bolvar);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 1, 1s + 140ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 1:
+ {
+ sylvanas->GetMotionMaster()->MovePoint(POINT_INTRODUCTION, SylvanasIntroPos[0], false);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 2, 1s + 500ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 2:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_02, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 3, 3s + 360ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 3:
+ {
+ sylvanas->GetMotionMaster()->MovePoint(POINT_INTRODUCTION, SylvanasIntroPos[1], false);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 4, 469ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 4:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_03, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 5, 3s + 500ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 5:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_04, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 6, 2s);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 6:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_05, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 7, 5s);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 7:
+ {
+ sylvanas->SetFacingToObject(bolvar);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 8, 750ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 8:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_06, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 9, 457ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 9:
+ {
+ sylvanas->GetMotionMaster()->MovePoint(POINT_INTRODUCTION, SylvanasIntroPos[2], false);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 10, 5s + 89ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 10:
+ {
+ bolvar->SetFacingToObject(sylvanas);
+ bolvar->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_BOLVAR_INTRODUCTION_TALK_01, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 11, 13s + 567ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 11:
+ {
+ sylvanas->SetFacingToObject(bolvar);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 12, 484ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 12:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_07, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 13, 5s + 516ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 13:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_08, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 14, 1s + 516ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 14:
+ {
+ sylvanas->NearTeleportTo(SylvanasIntroPos[3], false);
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_TELEPORT, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 15, 1s + 265ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 15:
+ {
+ sylvanas->SetFacingToObject(bolvar);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 16, 969ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 16:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_09, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 17, 4s + 766ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 17:
+ {
+ sylvanas->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SYLVANAS_INTRODUCTION_TALK_10, 0, 0);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 18, 3s + 250ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 18:
+ {
+ sylvanas->CastSpell(sylvanas, SPELL_RANGER_BOW_STANCE);
+
+ _events.ScheduleEvent(EVENT_INTRODUCTION + 19, 16ms);
+ break;
+ }
+
+ case EVENT_INTRODUCTION + 19:
+ {
+ sylvanas->CastSpell(sylvanas, SPELL_GENERIC_ANCHOR_HERE);
+
+ if (InstanceScript* instance = sylvanas->GetInstanceScript())
+ instance->SetData(DATA_SYLVANAS_INTRODUCTION, DONE);
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+private:
+ EventMap _events;
+};
+
+void AddSC_boss_sylvanas_windrunner()
+{
+ RegisterSanctumOfDominationCreatureAI(boss_sylvanas_windrunner);
+ RegisterSanctumOfDominationCreatureAI(npc_sylvanas_windrunner_shadowcopy_riding);
+
+ RegisterAreaTriggerAI(at_sylvanas_windrunner_z_check);
+ RegisterAreaTriggerAI(at_sylvanas_windrunner_introduction);
+
+ new conversation_sylvanas_windrunner_introduction();
+}
diff --git a/src/server/scripts/Shadowlands/SanctumOfDomination/instance_sanctum_of_domination.cpp b/src/server/scripts/Shadowlands/SanctumOfDomination/instance_sanctum_of_domination.cpp
new file mode 100644
index 00000000000..dfba70edc87
--- /dev/null
+++ b/src/server/scripts/Shadowlands/SanctumOfDomination/instance_sanctum_of_domination.cpp
@@ -0,0 +1,254 @@
+/*
+ * This file is part of the TrinityCore 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 General Public License as published by the
+ * Free Software Foundation; either version 2 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 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "Creature.h"
+#include "GameObject.h"
+#include "InstanceScript.h"
+#include "Map.h"
+#include "Player.h"
+#include "ScriptMgr.h"
+#include "sanctum_of_domination.h"
+
+ObjectData const creatureData[] =
+{
+ { BOSS_SYLVANAS_WINDRUNNER, DATA_SYLVANAS_WINDRUNNER },
+ { NPC_SYLVANAS_SHADOWCOPY_RIDING, DATA_SYLVANAS_SHADOWCOPY_RIDING },
+ { NPC_BOLVAR_FORDRAGON_PINNACLE, DATA_BOLVAR_FORDRAGON_PINNACLE },
+ { NPC_JAINA_PROUDMOORE_PINNACLE, DATA_JAINA_PROUDMOORE_PINNACLE },
+ { NPC_THRALL_PINNACLE, DATA_THRALL_PINNACLE },
+ { NPC_THRONE_OF_THE_DAMNED, DATA_THRONE_OF_THE_DAMNED },
+ { 0, 0 } // END
+};
+
+DungeonEncounterData const encounters[] =
+{
+ { DATA_THE_TARRAGRUE, {{ 2423 }} },
+ { DATA_THE_EYE_OF_THE_JAILER, {{ 2433 }} },
+ { DATA_THE_NINE, {{ 2429 }} },
+ { DATA_REMNANT_OF_NERZHUL, {{ 2432 }} },
+ { DATA_SOULRENDER_DORMAZAIN, {{ 2434 }} },
+ { DATA_PAINSMITH_RAZNAL, {{ 2430 }} },
+ { DATA_GUARDIAN_OF_THE_FIRST_ONES, {{ 2436 }} },
+ { DATA_FATESCRIBE_ROHKALO, {{ 2431 }} },
+ { DATA_KELTHUZAD, {{ 2422 }} },
+ { DATA_SYLVANAS_WINDRUNNER, {{ 2435 }} }
+};
+
+class instance_sanctum_of_domination : public InstanceMapScript
+{
+public:
+ instance_sanctum_of_domination() : InstanceMapScript(SODScriptName, 2450) { }
+
+ struct instance_sanctum_of_domination_InstanceMapScript : public InstanceScript
+ {
+ instance_sanctum_of_domination_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(EncounterCount);
+ LoadDungeonEncounterData(encounters);
+ LoadObjectData(creatureData, nullptr);
+
+ SylvanasIntroductionState = NOT_STARTED;
+ }
+
+ void OnCreatureCreate(Creature* creature) override
+ {
+ InstanceScript::OnCreatureCreate(creature);
+
+ switch (creature->GetEntry())
+ {
+ case BOSS_SYLVANAS_WINDRUNNER:
+ SylvanasGUID = creature->GetGUID();
+ break;
+
+ case NPC_SYLVANAS_SHADOWCOPY_RIDING:
+ SylvanasShadowcopyRidingGUID = creature->GetGUID();
+ break;
+
+ case NPC_BOLVAR_FORDRAGON_PINNACLE:
+ BolvarPinnacleGUID = creature->GetGUID();
+ break;
+
+ case NPC_JAINA_PROUDMOORE_PINNACLE:
+ JainaPinnacleGUID = creature->GetGUID();
+ break;
+
+ case NPC_THRALL_PINNACLE:
+ ThrallPinnacleGUID = creature->GetGUID();
+ break;
+
+ case NPC_THRONE_OF_THE_DAMNED:
+ ThroneOfTheDamnedGUID = creature->GetGUID();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void OnGameObjectCreate(GameObject* go) override
+ {
+ switch (go->GetEntry())
+ {
+ case GAMEOBJECT_TORGHAST_SPIKE_01:
+ case GAMEOBJECT_TORGHAST_SPIKE_02:
+ case GAMEOBJECT_TORGHAST_SPIKE_03:
+ case GAMEOBJECT_TORGHAST_SPIKE_04:
+ case GAMEOBJECT_TORGHAST_SPIKE_05:
+ case GAMEOBJECT_TORGHAST_SPIKE_06:
+ case GAMEOBJECT_TORGHAST_SPIKE_07:
+ case GAMEOBJECT_TORGHAST_SPIKE_08:
+ case GAMEOBJECT_TORGHAST_SPIKE_09:
+ case GAMEOBJECT_TORGHAST_SPIKE_10:
+ case GAMEOBJECT_TORGHAST_SPIKE_11:
+ case GAMEOBJECT_TORGHAST_SPIKE_12:
+ TorghastSpikeGUIDs.push_back(go->GetGUID());
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ObjectGuid GetGuidData(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_SYLVANAS_WINDRUNNER:
+ return SylvanasGUID;
+ case DATA_BOLVAR_FORDRAGON_PINNACLE:
+ return BolvarPinnacleGUID;
+ case DATA_JAINA_PROUDMOORE_PINNACLE:
+ return JainaPinnacleGUID;
+ case DATA_THRALL_PINNACLE:
+ return ThrallPinnacleGUID;
+ case DATA_THRONE_OF_THE_DAMNED:
+ return ThroneOfTheDamnedGUID;
+ default:
+ break;
+ }
+
+ return ObjectGuid::Empty;
+ }
+
+ bool SetBossState(uint32 id, EncounterState state) override
+ {
+ if (!InstanceScript::SetBossState(id, state))
+ return false;
+
+ switch (id)
+ {
+ case DATA_SYLVANAS_WINDRUNNER:
+ {
+ if (state == NOT_STARTED)
+ {
+ DoUpdateWorldState(WORLD_STATE_SYLVANAS_ENCOUNTER_STARTED, 0);
+
+ if (Creature* throneTeleporter = GetCreature(DATA_THRONE_OF_THE_DAMNED))
+ throneTeleporter->SetVisible(true);
+
+ for (ObjectGuid const& spikeGUID : TorghastSpikeGUIDs)
+ if (GameObject* torghastSpike = instance->GetGameObject(spikeGUID))
+ torghastSpike->SetSpellVisualId(0);
+ }
+ else if (state == IN_PROGRESS)
+ {
+ DoUpdateWorldState(WORLD_STATE_SYLVANAS_ENCOUNTER_STARTED, 1);
+
+ if (Creature* throneTeleporter = GetCreature(DATA_THRONE_OF_THE_DAMNED))
+ throneTeleporter->SetVisible(false);
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ void SetData(uint32 type, uint32 data) override
+ {
+ switch (type)
+ {
+ case DATA_SYLVANAS_INTRODUCTION:
+ {
+ switch (data)
+ {
+ case IN_PROGRESS:
+ SylvanasIntroductionState = IN_PROGRESS;
+ if (Creature* sylvanas = GetCreature(DATA_SYLVANAS_WINDRUNNER))
+ sylvanas->SetHomePosition(SylvanasRespawnPos);
+ break;
+
+ case DONE:
+ SylvanasIntroductionState = DONE;
+ if (Creature* sylvanas = GetCreature(DATA_SYLVANAS_WINDRUNNER))
+ {
+ sylvanas->RemoveUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1);
+ sylvanas->SetImmuneToAll(false);
+ sylvanas->SetSpeed(MOVE_RUN, 14.0f);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ uint32 GetData(uint32 type) const override
+ {
+ switch (type)
+ {
+ case DATA_SYLVANAS_INTRODUCTION:
+ return SylvanasIntroductionState;
+ default:
+ break;
+ }
+
+ return 0;
+ }
+
+ protected:
+ ObjectGuid SylvanasGUID;
+ ObjectGuid SylvanasShadowcopyRidingGUID;
+ ObjectGuid BolvarPinnacleGUID;
+ ObjectGuid JainaPinnacleGUID;
+ ObjectGuid ThrallPinnacleGUID;
+ ObjectGuid ThroneOfTheDamnedGUID;
+ std::vector<ObjectGuid> TorghastSpikeGUIDs;
+ uint8 SylvanasIntroductionState;
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_sanctum_of_domination_InstanceMapScript(map);
+ }
+};
+
+void AddSC_instance_sanctum_of_domination()
+{
+ new instance_sanctum_of_domination();
+}
diff --git a/src/server/scripts/Shadowlands/SanctumOfDomination/sanctum_of_domination.h b/src/server/scripts/Shadowlands/SanctumOfDomination/sanctum_of_domination.h
new file mode 100644
index 00000000000..498aecfd715
--- /dev/null
+++ b/src/server/scripts/Shadowlands/SanctumOfDomination/sanctum_of_domination.h
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the TrinityCore 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 General Public License as published by the
+ * Free Software Foundation; either version 2 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 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEF_SANCTUM_OF_DOMINATION_H_
+#define DEF_SANCTUM_OF_DOMINATION_H_
+
+#include "CreatureAIImpl.h"
+
+#define DataHeader "SanctumOfDomination"
+#define SODScriptName "instance_sanctum_of_domination"
+
+uint32 const EncounterCount = 10;
+
+Position const SylvanasRespawnPos = { 225.73611f, -844.0746f, 4104.9882f, 1.3613f };
+
+enum SanctumOfDominationDataTypes
+{
+ DATA_THE_TARRAGRUE = 0,
+ DATA_THE_EYE_OF_THE_JAILER = 1,
+ DATA_THE_NINE = 2,
+ DATA_REMNANT_OF_NERZHUL = 3,
+ DATA_SOULRENDER_DORMAZAIN = 4,
+ DATA_PAINSMITH_RAZNAL = 5,
+ DATA_GUARDIAN_OF_THE_FIRST_ONES = 6,
+ DATA_FATESCRIBE_ROHKALO = 7,
+ DATA_KELTHUZAD = 8,
+ DATA_SYLVANAS_WINDRUNNER = 9,
+
+ /* Encounter-related data */
+
+ /* Sylvanas Windrunner */
+ DATA_SYLVANAS_INTRODUCTION,
+ DATA_SYLVANAS_SHADOWCOPY_RIDING,
+ DATA_BOLVAR_FORDRAGON_PINNACLE,
+ DATA_JAINA_PROUDMOORE_PINNACLE,
+ DATA_THRALL_PINNACLE,
+ DATA_THRONE_OF_THE_DAMNED
+};
+
+enum SanctumOfDominationCreatureIds
+{
+ // Bosses
+ BOSS_SYLVANAS_WINDRUNNER = 175732,
+
+ /* Encounter-related creatures */
+
+ /* Sylvanas Windrunner Encounter */
+ NPC_SYLVANAS_SHADOWCOPY_RIDING = 178355,
+ NPC_BOLVAR_FORDRAGON_PINNACLE = 178081,
+ NPC_JAINA_PROUDMOORE_PINNACLE = 176533,
+ NPC_THRALL_PINNACLE = 176532,
+
+ NPC_THRONE_OF_THE_DAMNED = 180803
+};
+
+enum SanctumOfDominationGameObjectIds
+{
+ GAMEOBJECT_TORGHAST_SPIKE_01 = 368743,
+ GAMEOBJECT_TORGHAST_SPIKE_02 = 368744,
+ GAMEOBJECT_TORGHAST_SPIKE_03 = 368745,
+ GAMEOBJECT_TORGHAST_SPIKE_04 = 368746,
+ GAMEOBJECT_TORGHAST_SPIKE_05 = 368747,
+ GAMEOBJECT_TORGHAST_SPIKE_06 = 368748,
+ GAMEOBJECT_TORGHAST_SPIKE_07 = 368749,
+ GAMEOBJECT_TORGHAST_SPIKE_08 = 368750,
+ GAMEOBJECT_TORGHAST_SPIKE_09 = 368751,
+ GAMEOBJECT_TORGHAST_SPIKE_10 = 368752,
+ GAMEOBJECT_TORGHAST_SPIKE_11 = 368753,
+ GAMEOBJECT_TORGHAST_SPIKE_12 = 368754
+};
+
+enum SanctumOfDominationAreas
+{
+ AREA_PINNACLE_OF_DOMINANCE = 13653,
+ AREA_EDGE_OF_THE_ABYSS = 13654,
+ AREA_THE_CRUCIBLE = 13655
+};
+
+enum SanctumofDominationWorldStates
+{
+ WORLD_STATE_SYLVANAS_ENCOUNTER_STARTED = 20346,
+ WORLD_STATE_SYLVANAS_ENCOUNTER_COMPLETED = 20347,
+ WORLD_STATE_SYLVANAS_ENCOUNTER_PHASE = 20348,
+ WORLD_STATE_SYLVANAS_UNK_01 = 21210, // Info: sets to 0 several times on phase 3.
+ WORLD_STATE_SYLVANAS_UNK_02 = 21166, // Info: sets to 1 when SPELL_FINAL_SCENE is cast on players.
+ WORLD_STATE_SYLVANAS_UNK_03 = 21120, // Info: sets to 1 when 353687 spell is cast by NPC 179262.
+ WORLD_STATE_SYLVANAS_ACHIEVEMENT_COMPLETED = 21134,
+ WORLD_STATE_SYLVANAS_UNK_04 = 20439, // Info: this is always 1 on INIT and the following are 0.
+ WORLD_STATE_SYLVANAS_UNK_05 = 20440,
+ WORLD_STATE_SYLVANAS_UNK_06 = 20441,
+ WORLD_STATE_SYLVANAS_UNK_07 = 20442,
+ WORLD_STATE_SYLVANAS_UNK_08 = 20443
+};
+
+template <class AI, class T>
+inline AI* GetSanctumOfDominationAI(T* obj)
+{
+ return GetInstanceAI<AI>(obj, SODScriptName);
+}
+
+#define RegisterSanctumOfDominationCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSanctumOfDominationAI)
+
+#endif
diff --git a/src/server/scripts/Shadowlands/shadowlands_script_loader.cpp b/src/server/scripts/Shadowlands/shadowlands_script_loader.cpp
index c6452c75c37..a21eae2a9f4 100644
--- a/src/server/scripts/Shadowlands/shadowlands_script_loader.cpp
+++ b/src/server/scripts/Shadowlands/shadowlands_script_loader.cpp
@@ -19,8 +19,17 @@
void AddSC_covenant_spell_scripts();
void AddSC_torghast_spell_scripts();
+void AddSC_boss_sylvanas_windrunner();
+void AddSC_instance_sanctum_of_domination();
+
+// The name of this function should match:
+// void Add${NameOfDirectory}Scripts()
void AddShadowlandsScripts()
{
AddSC_covenant_spell_scripts();
AddSC_torghast_spell_scripts();
+
+ // Sanctum of Domination
+ AddSC_boss_sylvanas_windrunner();
+ AddSC_instance_sanctum_of_domination();
}