aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTrazom62 <none@none>2010-05-20 20:09:18 +0200
committerTrazom62 <none@none>2010-05-20 20:09:18 +0200
commitd2cad4b14e27c8c7b7ba5be7449dbb908f34497d (patch)
tree722ed1fb40c1b90ff5668cbe8be6063d2233026b /src
parentce7886aeb0df0257aa953bdf83ef51c4251a6ebf (diff)
Script HoR instance. 1st part.
Fixes issue #1311. - Intro event. - 10 waves including Falric and Marwyn. - Script based on proposal of Synric on trinitycore forum (submitted by Skarabex on GC). --HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/game/ScriptLoader.cpp8
-rw-r--r--src/game/SpellAuras.cpp23
-rw-r--r--src/game/SpellMgr.cpp1
-rw-r--r--src/scripts/CMakeLists.txt3
-rw-r--r--src/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp142
-rw-r--r--src/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp133
-rw-r--r--src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp1022
-rw-r--r--src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h133
-rw-r--r--src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp321
9 files changed, 1751 insertions, 35 deletions
diff --git a/src/game/ScriptLoader.cpp b/src/game/ScriptLoader.cpp
index 971ff4cbe35..20bda66a611 100644
--- a/src/game/ScriptLoader.cpp
+++ b/src/game/ScriptLoader.cpp
@@ -416,6 +416,10 @@ void AddSC_pit_of_saron();
void AddSC_boss_garfrost();
void AddSC_boss_ick();
void AddSC_boss_tyrannus();
+void AddSC_instance_halls_of_reflection(); // Halls of Reflection
+void AddSC_halls_of_reflection();
+void AddSC_boss_falric();
+void AddSC_boss_marwyn();
void AddSC_dalaran();
void AddSC_borean_tundra();
@@ -912,6 +916,10 @@ void AddScripts()
AddSC_boss_garfrost();
AddSC_boss_ick();
AddSC_boss_tyrannus();
+ AddSC_instance_halls_of_reflection(); // Halls of Reflection
+ AddSC_halls_of_reflection();
+ AddSC_boss_falric();
+ AddSC_boss_marwyn();
AddSC_dalaran();
AddSC_borean_tundra();
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index a531f24922e..1b2e0f5b6fd 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -1089,9 +1089,26 @@ void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster,
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
- // Remove the immunity shield marker on Avenging Wrath removal if Forbearance is not present
- if (GetId() == 61987 && target->HasAura(61988) && !target->HasAura(25771))
- target->RemoveAura(61988);
+ switch(GetId())
+ {
+ case 61987: // Avenging Wrath
+ // Remove the immunity shield marker on Avenging Wrath removal if Forbearance is not present
+ if (target->HasAura(61988) && !target->HasAura(25771))
+ target->RemoveAura(61988);
+ break;
+ case 72368: // Shared Suffering
+ case 72369:
+ if (caster)
+ {
+ if (AuraEffect* aurEff = GetEffect(0))
+ {
+ int32 remainingDamage = aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber());
+ if (remainingDamage > 0)
+ caster->CastCustomSpell(caster, 72373, NULL, &remainingDamage, NULL, true);
+ }
+ }
+ break;
+ }
break;
case SPELLFAMILY_MAGE:
switch(GetId())
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 81c4ebaa76f..d7da9bb1e3b 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -3629,6 +3629,7 @@ void SpellMgr::LoadSpellCustomAttr()
case 42384: // Brutal Swipe
case 45150: // Meteor Slash
case 64422: case 64688: // Sonic Screech
+ case 72373: // Shared Suffering
// ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE
mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
count++;
diff --git a/src/scripts/CMakeLists.txt b/src/scripts/CMakeLists.txt
index e51130881f6..47dffe924dc 100644
--- a/src/scripts/CMakeLists.txt
+++ b/src/scripts/CMakeLists.txt
@@ -346,7 +346,10 @@ SET(scripts_STAT_SRCS
northrend/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp
northrend/frozen_halls/forge_of_souls/forge_of_souls.h
northrend/frozen_halls/forge_of_souls/forge_of_souls.cpp
+ northrend/frozen_halls/halls_of_reflection/boss_falric.cpp
+ northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp
northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp
+ northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp
northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h
northrend/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp
northrend/frozen_halls/pit_of_saron/boss_krickandick.cpp
diff --git a/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp b/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp
new file mode 100644
index 00000000000..c9978faca6e
--- /dev/null
+++ b/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_falric.cpp
@@ -0,0 +1,142 @@
+/* Copyright (C) 2006 - 2010 TrinityCore <https://www.trinitycore.org/>
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ScriptedPch.h"
+#include "halls_of_reflection.h"
+
+enum Yells
+{
+ SAY_AGGRO = -1668050,
+ SAY_SLAY_1 = -1668051,
+ SAY_SLAY_2 = -1668052,
+ SAY_DEATH = -1668053,
+ SAY_IMPENDING_DESPAIR = -1668054,
+ SAY_DEFILING_HORROR = -1668055,
+};
+
+enum Spells
+{
+ SPELL_QUIVERING_STRIKE = 72422,
+ SPELL_IMPENDING_DESPAIR = 72426,
+ SPELL_DEFILING_HORROR = 72435,
+ SPELL_HOPELESSNESS = 72395,
+ H_SPELL_HOPELESSNESS = 72390, // TODO: not in dbc. Add in DB.
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_QUIVERING_STRIKE,
+ EVENT_IMPENDING_DESPAIR,
+ EVENT_DEFILING_HORROR,
+};
+
+struct boss_falricAI : public boss_horAI
+{
+ boss_falricAI(Creature *pCreature) : boss_horAI(pCreature) {}
+
+ uint8 uiHopelessnessCount;
+
+ void Reset()
+ {
+ boss_horAI::Reset();
+
+ uiHopelessnessCount = 0;
+
+ if (pInstance)
+ pInstance->SetData(DATA_FALRIC_EVENT, NOT_STARTED);
+ }
+
+ void EnterCombat(Unit* who)
+ {
+ DoScriptText(SAY_AGGRO, me);
+ if (pInstance)
+ pInstance->SetData(DATA_FALRIC_EVENT, IN_PROGRESS);
+
+ events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000);
+ events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000);
+ events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000,45000)); // TODO adjust timer.
+ }
+
+ void JustDied(Unit* killer)
+ {
+ DoScriptText(SAY_DEATH, me);
+
+ if (pInstance)
+ pInstance->SetData(DATA_FALRIC_EVENT, DONE);
+ }
+
+ void KilledUnit(Unit *victim)
+ {
+ DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), me);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ // Return since we have no target
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_QUIVERING_STRIKE:
+ DoCast(SPELL_QUIVERING_STRIKE);
+ events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 10000);
+ break;
+ case EVENT_IMPENDING_DESPAIR:
+ if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ {
+ DoScriptText(SAY_IMPENDING_DESPAIR, me);
+ DoCast(pTarget, SPELL_IMPENDING_DESPAIR);
+ }
+ events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 13000);
+ break;
+ case EVENT_DEFILING_HORROR:
+ DoCast(SPELL_DEFILING_HORROR);
+ events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000,45000)); // TODO adjust timer.
+ break;
+ }
+
+ if ((uiHopelessnessCount < 1 && HealthBelowPct(66))
+ || (uiHopelessnessCount < 2 && HealthBelowPct(33))
+ || (uiHopelessnessCount < 3 && HealthBelowPct(10)))
+ {
+ uiHopelessnessCount++;
+ DoCast(DUNGEON_MODE(SPELL_HOPELESSNESS,H_SPELL_HOPELESSNESS));
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+CreatureAI* GetAI_boss_falric(Creature* pCreature)
+{
+ return new boss_falricAI(pCreature);
+}
+
+void AddSC_boss_falric()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name="boss_falric";
+ newscript->GetAI = &GetAI_boss_falric;
+ newscript->RegisterSelf();
+}
diff --git a/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp b/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp
new file mode 100644
index 00000000000..95fb2737ce9
--- /dev/null
+++ b/src/scripts/northrend/frozen_halls/halls_of_reflection/boss_marwyn.cpp
@@ -0,0 +1,133 @@
+/* Copyright (C) 2006 - 2010 TrinityCore <https://www.trinitycore.org/>
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ScriptedPch.h"
+#include "halls_of_reflection.h"
+
+enum Yells
+{
+ SAY_AGGRO = -1668060,
+ SAY_SLAY_1 = -1668061,
+ SAY_SLAY_2 = -1668062,
+ SAY_DEATH = -1668063,
+ SAY_CORRUPTED_FLESH_1 = -1668064,
+ SAY_CORRUPTED_FLESH_2 = -1668065,
+};
+
+enum Spells
+{
+ SPELL_OBLITERATE = 72360,
+ SPELL_WELL_OF_CORRUPTION = 72362,
+ SPELL_CORRUPTED_FLESH = 72363,
+ SPELL_SHARED_SUFFERING = 72368,
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_OBLITERATE,
+ EVENT_WELL_OF_CORRUPTION,
+ EVENT_CORRUPTED_FLESH,
+ EVENT_SHARED_SUFFERING,
+};
+
+struct boss_marwynAI : public boss_horAI
+{
+ boss_marwynAI(Creature *pCreature) : boss_horAI(pCreature) {}
+
+ void Reset()
+ {
+ boss_horAI::Reset();
+
+ if (pInstance)
+ pInstance->SetData(DATA_MARWYN_EVENT, NOT_STARTED);
+ }
+
+ void EnterCombat(Unit* who)
+ {
+ DoScriptText(SAY_AGGRO, me);
+ if (pInstance)
+ pInstance->SetData(DATA_MARWYN_EVENT, IN_PROGRESS);
+
+ events.ScheduleEvent(EVENT_OBLITERATE, 30000); // TODO Check timer
+ events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000);
+ events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000);
+ events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000); // TODO Check timer
+ }
+
+ void JustDied(Unit* killer)
+ {
+ DoScriptText(SAY_DEATH, me);
+
+ if (pInstance)
+ pInstance->SetData(DATA_MARWYN_EVENT, DONE);
+ }
+
+ void KilledUnit(Unit *victim)
+ {
+ DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), me);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ // Return since we have no target
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_OBLITERATE:
+ DoCast(SPELL_OBLITERATE);
+ events.ScheduleEvent(EVENT_OBLITERATE, 30000);
+ break;
+ case EVENT_WELL_OF_CORRUPTION:
+ DoCast(SPELL_WELL_OF_CORRUPTION);
+ events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000);
+ break;
+ case EVENT_CORRUPTED_FLESH:
+ DoScriptText(RAND(SAY_CORRUPTED_FLESH_1,SAY_CORRUPTED_FLESH_2), me);
+ DoCast(SPELL_CORRUPTED_FLESH);
+ events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000);
+ break;
+ case EVENT_SHARED_SUFFERING:
+ if (Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_SHARED_SUFFERING);
+ events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+CreatureAI* GetAI_boss_marwyn(Creature* pCreature)
+{
+ return new boss_marwynAI(pCreature);
+}
+
+void AddSC_boss_marwyn()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name="boss_marwyn";
+ newscript->GetAI = &GetAI_boss_marwyn;
+ newscript->RegisterSelf();
+}
diff --git a/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp b/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp
new file mode 100644
index 00000000000..fb3d3d5d752
--- /dev/null
+++ b/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.cpp
@@ -0,0 +1,1022 @@
+/* Copyright (C) 2006 - 2010 TrinityCore <https://www.trinitycore.org/>
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ScriptedPch.h"
+#include "halls_of_reflection.h"
+
+enum Yells
+{
+ SAY_JAINA_INTRO_1 = -1668001,
+ SAY_JAINA_INTRO_2 = -1668002,
+ SAY_JAINA_INTRO_3 = -1668003,
+ SAY_JAINA_INTRO_4 = -1668004,
+ SAY_UTHER_INTRO_A2_1 = -1668005,
+ SAY_JAINA_INTRO_5 = -1668006,
+ SAY_UTHER_INTRO_A2_2 = -1668007,
+ SAY_JAINA_INTRO_6 = -1668008,
+ SAY_UTHER_INTRO_A2_3 = -1668009,
+ SAY_JAINA_INTRO_7 = -1668010,
+ SAY_UTHER_INTRO_A2_4 = -1668011,
+ SAY_JAINA_INTRO_8 = -1668012,
+ SAY_UTHER_INTRO_A2_5 = -1668013,
+ SAY_JAINA_INTRO_9 = -1668014,
+ SAY_UTHER_INTRO_A2_6 = -1668015,
+ SAY_UTHER_INTRO_A2_7 = -1668016,
+ SAY_JAINA_INTRO_10 = -1668017,
+ SAY_UTHER_INTRO_A2_8 = -1668018,
+ SAY_JAINA_INTRO_11 = -1668019,
+ SAY_UTHER_INTRO_A2_9 = -1668020,
+
+ SAY_SYLVANAS_INTRO_1 = -1668021,
+ SAY_SYLVANAS_INTRO_2 = -1668022,
+ SAY_SYLVANAS_INTRO_3 = -1668023,
+ SAY_UTHER_INTRO_H2_1 = -1668024,
+ SAY_SYLVANAS_INTRO_4 = -1668025,
+ SAY_UTHER_INTRO_H2_2 = -1668026,
+ SAY_SYLVANAS_INTRO_5 = -1668027,
+ SAY_UTHER_INTRO_H2_3 = -1668028,
+ SAY_SYLVANAS_INTRO_6 = -1668029,
+ SAY_UTHER_INTRO_H2_4 = -1668030,
+ SAY_SYLVANAS_INTRO_7 = -1668031,
+ SAY_UTHER_INTRO_H2_5 = -1668032,
+ SAY_UTHER_INTRO_H2_6 = -1668033,
+ SAY_SYLVANAS_INTRO_8 = -1668034,
+ SAY_UTHER_INTRO_H2_7 = -1668035,
+
+ SAY_LK_INTRO_1 = -1668036,
+ SAY_LK_INTRO_2 = -1668037,
+ SAY_LK_INTRO_3 = -1668038,
+ SAY_FALRIC_INTRO_1 = -1668039,
+ SAY_MARWYN_INTRO_1 = -1668040,
+ SAY_FALRIC_INTRO_2 = -1668041,
+
+ SAY_JAINA_INTRO_END = -1668042,
+ SAY_SYLVANAS_INTRO_END = -1668043,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ EVENT_START_INTRO,
+ EVENT_SKIP_INTRO,
+
+ EVENT_INTRO_A2_1,
+ EVENT_INTRO_A2_2,
+ EVENT_INTRO_A2_3,
+ EVENT_INTRO_A2_4,
+ EVENT_INTRO_A2_5,
+ EVENT_INTRO_A2_6,
+ EVENT_INTRO_A2_7,
+ EVENT_INTRO_A2_8,
+ EVENT_INTRO_A2_9,
+ EVENT_INTRO_A2_10,
+ EVENT_INTRO_A2_11,
+ EVENT_INTRO_A2_12,
+ EVENT_INTRO_A2_13,
+ EVENT_INTRO_A2_14,
+ EVENT_INTRO_A2_15,
+ EVENT_INTRO_A2_16,
+ EVENT_INTRO_A2_17,
+ EVENT_INTRO_A2_18,
+ EVENT_INTRO_A2_19,
+
+ EVENT_INTRO_H2_1,
+ EVENT_INTRO_H2_2,
+ EVENT_INTRO_H2_3,
+ EVENT_INTRO_H2_4,
+ EVENT_INTRO_H2_5,
+ EVENT_INTRO_H2_6,
+ EVENT_INTRO_H2_7,
+ EVENT_INTRO_H2_8,
+ EVENT_INTRO_H2_9,
+ EVENT_INTRO_H2_10,
+ EVENT_INTRO_H2_11,
+ EVENT_INTRO_H2_12,
+ EVENT_INTRO_H2_13,
+ EVENT_INTRO_H2_14,
+ EVENT_INTRO_H2_15,
+
+ EVENT_INTRO_LK_1,
+ EVENT_INTRO_LK_2,
+ EVENT_INTRO_LK_3,
+ EVENT_INTRO_LK_4,
+ EVENT_INTRO_LK_5,
+ EVENT_INTRO_LK_6,
+ EVENT_INTRO_LK_7,
+ EVENT_INTRO_LK_8,
+ EVENT_INTRO_LK_9,
+
+ EVENT_INTRO_END,
+};
+
+enum eEnum
+{
+ ACTION_START_INTRO,
+ ACTION_SKIP_INTRO,
+
+ QUEST_DELIVRANCE_FROM_THE_PIT_A2 = 24710,
+ QUEST_DELIVRANCE_FROM_THE_PIT_H2 = 24712,
+ QUEST_WRATH_OF_THE_LICH_KING_A2 = 24500,
+ QUEST_WRATH_OF_THE_LICH_KING_H2 = 24802,
+};
+
+static Position HallsofReflectionLocs[]=
+{
+ {5283.234863, 1990.946777, 707.695679, 0.929097}, // 2 Loralen Follows
+ {5408.031250, 2102.918213, 707.695251, 0.792756}, // 9 Sylvanas Follows
+ {5401.866699, 2110.837402, 707.695251, 0.800610}, // 10 Loralen follows
+};
+
+static Position SpawnPos = {5262.540527, 1949.693726, 707.695007, 0.808736}; // Jaina/Sylvanas Beginning Position
+static Position MoveThronePos = {5306.952148, 1998.499023, 709.341431, 1.277278}; // Jaina/Sylvanas walks to throne
+static Position UtherSpawnPos = {5308.310059, 2003.857178, 709.341431, 4.650315};
+static Position LichKingSpawnPos = {5362.917480, 2062.307129, 707.695374, 3.945812};
+static Position LichKingMoveThronePos = {5312.080566, 2009.172119, 709.341431, 3.973301}; // Lich King walks to throne
+static Position LichKingMoveAwayPos = {5400.069824, 2102.7131689, 707.69525, 0.843803}; // Lich King walks away
+
+// AI of Part1: handle the intro till start of gauntlet event.
+struct npc_jaina_or_sylvanas_horAI : public ScriptedAI
+{
+ npc_jaina_or_sylvanas_horAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceData();
+ }
+
+ ScriptedInstance* pInstance;
+ uint64 uiUther;
+ uint64 uiLichKing;
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+
+ uiUther = 0;
+ uiLichKing = 0;
+
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->SetVisibility(VISIBILITY_ON);
+ }
+
+ void DoAction(const int32 actionId)
+ {
+ switch(actionId)
+ {
+ case ACTION_START_INTRO:
+ events.ScheduleEvent(EVENT_START_INTRO, 0);
+ break;
+ case ACTION_SKIP_INTRO:
+ events.ScheduleEvent(EVENT_SKIP_INTRO, 0);
+ break;
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ events.Update(diff);
+ switch(events.ExecuteEvent())
+ {
+ case EVENT_START_INTRO:
+ me->GetMotionMaster()->MovePoint(0, MoveThronePos);
+ // Begining of intro is differents between factions as the speech sequence and timers are differents.
+ if (pInstance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ events.ScheduleEvent(EVENT_INTRO_A2_1, 0);
+ else
+ events.ScheduleEvent(EVENT_INTRO_H2_1, 0);
+ break;
+
+ // A2 Intro Events
+ case EVENT_INTRO_A2_1:
+ DoScriptText(SAY_JAINA_INTRO_3, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_2, 5000);
+ break;
+ case EVENT_INTRO_A2_2:
+ DoScriptText(SAY_JAINA_INTRO_4, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_3, 10000);
+ break;
+ case EVENT_INTRO_A2_3:
+ // TODO: she's doing some kind of spell casting emote
+ pInstance->HandleGameObject(pInstance->GetData64(DATA_FROSTMOURNE), true);
+ events.ScheduleEvent(EVENT_INTRO_A2_4, 10000);
+ break;
+ case EVENT_INTRO_A2_4:
+ // spawn UTHER during speach 2
+ if (Creature* pUther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ pUther->GetMotionMaster()->MoveIdle();
+ pUther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas
+ uiUther = pUther->GetGUID();
+ }
+ events.ScheduleEvent(EVENT_INTRO_A2_5, 2000);
+ break;
+ case EVENT_INTRO_A2_5:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_1, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_6, 3000);
+ break;
+ case EVENT_INTRO_A2_6:
+ DoScriptText(SAY_JAINA_INTRO_5, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_7, 6000);
+ break;
+ case EVENT_INTRO_A2_7:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_2, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_8, 6500);
+ break;
+ case EVENT_INTRO_A2_8:
+ DoScriptText(SAY_JAINA_INTRO_6, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_9, 2000);
+ break;
+ case EVENT_INTRO_A2_9:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_3, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_10, 9000);
+ break;
+ case EVENT_INTRO_A2_10:
+ DoScriptText(SAY_JAINA_INTRO_7, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_11, 5000);
+ break;
+ case EVENT_INTRO_A2_11:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_4, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_12, 11000);
+ break;
+ case EVENT_INTRO_A2_12:
+ DoScriptText(SAY_JAINA_INTRO_8, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_13, 4000);
+ break;
+ case EVENT_INTRO_A2_13:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_5, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_14, 12500);
+ break;
+ case EVENT_INTRO_A2_14:
+ DoScriptText(SAY_JAINA_INTRO_9, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_15, 10000);
+ break;
+ case EVENT_INTRO_A2_15:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_6, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_16, 22000);
+ break;
+ case EVENT_INTRO_A2_16:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_A2_7, pUther);
+ events.ScheduleEvent(EVENT_INTRO_A2_17, 4000);
+ break;
+ case EVENT_INTRO_A2_17:
+ DoScriptText(SAY_JAINA_INTRO_10, me);
+ events.ScheduleEvent(EVENT_INTRO_A2_18, 2000);
+ break;
+ case EVENT_INTRO_A2_18:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ {
+ pUther->HandleEmoteCommand(EMOTE_ONESHOT_NO);
+ DoScriptText(SAY_UTHER_INTRO_A2_8, pUther);
+ }
+ events.ScheduleEvent(EVENT_INTRO_A2_19, 11000);
+ break;
+ case EVENT_INTRO_A2_19:
+ DoScriptText(SAY_JAINA_INTRO_11, me);
+ events.ScheduleEvent(EVENT_INTRO_LK_1, 2000);
+ break;
+
+ // H2 Intro Events
+ case EVENT_INTRO_H2_1:
+ DoScriptText(SAY_SYLVANAS_INTRO_1, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_2, 8000);
+ break;
+ case EVENT_INTRO_H2_2:
+ DoScriptText(SAY_SYLVANAS_INTRO_2, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_3, 6000);
+ break;
+ case EVENT_INTRO_H2_3:
+ DoScriptText(SAY_SYLVANAS_INTRO_3, me);
+ // TODO: she's doing some kind of spell casting emote
+ events.ScheduleEvent(EVENT_INTRO_H2_4, 6000);
+ break;
+ case EVENT_INTRO_H2_4:
+ // spawn UTHER during speach 2
+ if (Creature* pUther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ pUther->GetMotionMaster()->MoveIdle();
+ pUther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas
+ uiUther = pUther->GetGUID();
+ }
+ events.ScheduleEvent(EVENT_INTRO_H2_5, 2000);
+ break;
+ case EVENT_INTRO_H2_5:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_H2_1, pUther);
+ events.ScheduleEvent(EVENT_INTRO_H2_6, 11000);
+ break;
+ case EVENT_INTRO_H2_6:
+ DoScriptText(SAY_SYLVANAS_INTRO_4, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_7, 3000);
+ break;
+ case EVENT_INTRO_H2_7:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_H2_2, pUther);
+ events.ScheduleEvent(EVENT_INTRO_H2_8, 6000);
+ break;
+ case EVENT_INTRO_H2_8:
+ DoScriptText(SAY_SYLVANAS_INTRO_5, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_9, 5000);
+ break;
+ case EVENT_INTRO_H2_9:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_H2_3, pUther);
+ events.ScheduleEvent(EVENT_INTRO_H2_10, 19000);
+ break;
+ case EVENT_INTRO_H2_10:
+ DoScriptText(SAY_SYLVANAS_INTRO_6, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_11, 1500);
+ break;
+ case EVENT_INTRO_H2_11:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_H2_4, pUther);
+ events.ScheduleEvent(EVENT_INTRO_H2_12, 19500);
+ break;
+ case EVENT_INTRO_H2_12:
+ DoScriptText(SAY_SYLVANAS_INTRO_7, me);
+ events.ScheduleEvent(EVENT_INTRO_H2_13, 2000);
+ break;
+ case EVENT_INTRO_H2_13:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ {
+ pUther->HandleEmoteCommand(EMOTE_ONESHOT_NO);
+ DoScriptText(SAY_UTHER_INTRO_H2_5, pUther);
+ }
+ events.ScheduleEvent(EVENT_INTRO_H2_14, 12000);
+ break;
+ case EVENT_INTRO_H2_14:
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ DoScriptText(SAY_UTHER_INTRO_H2_6, pUther);
+ events.ScheduleEvent(EVENT_INTRO_H2_15, 8000);
+ break;
+ case EVENT_INTRO_H2_15:
+ DoScriptText(SAY_SYLVANAS_INTRO_8, me);
+ events.ScheduleEvent(EVENT_INTRO_LK_1, 2000);
+ break;
+
+ // Remaining Intro Events common for both faction
+ case EVENT_INTRO_LK_1:
+ // Spawn LK in front of door, and make him move to the sword.
+ if (Creature* pLichKing = me->SummonCreature(NPC_LICH_KING_EVENT, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ pLichKing->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos);
+ pLichKing->SetReactState(REACT_PASSIVE);
+ uiLichKing = pLichKing->GetGUID();
+ }
+
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ if (pInstance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ DoScriptText(SAY_UTHER_INTRO_A2_9, pUther);
+ else
+ DoScriptText(SAY_UTHER_INTRO_H2_7, pUther);
+
+ events.ScheduleEvent(EVENT_INTRO_LK_2, 11000);
+ break;
+
+ case EVENT_INTRO_LK_2:
+ if (Creature* pLichKing = me->GetCreature(*me, uiLichKing))
+ DoScriptText(SAY_LK_INTRO_1, pLichKing);
+ events.ScheduleEvent(EVENT_INTRO_LK_3, 2000);
+ break;
+
+ case EVENT_INTRO_LK_3:
+ // The Lich King banishes Uther to the abyss.
+ if (Creature* pUther = me->GetCreature(*me, uiUther))
+ {
+ pUther->DisappearAndDie();
+ uiUther = 0;
+ }
+
+ // He steps forward and removes the runeblade from the heap of skulls.
+
+ events.ScheduleEvent(EVENT_INTRO_LK_4, 4000);
+ break;
+
+ case EVENT_INTRO_LK_4:
+ if (Creature* pLichKing = me->GetCreature(*me, uiLichKing))
+ DoScriptText(SAY_LK_INTRO_2, pLichKing);
+ events.ScheduleEvent(EVENT_INTRO_LK_5, 10000);
+ break;
+
+ case EVENT_INTRO_LK_5:
+ // summon Falric and Marwyn. then go back to the door
+ if (Creature* pFalric = me->GetCreature(*me, pInstance->GetData64(DATA_FALRIC)))
+ pFalric->SetVisibility(VISIBILITY_ON);
+ if (Creature* pMarwyn = me->GetCreature(*me, pInstance->GetData64(DATA_MARWYN)))
+ pMarwyn->SetVisibility(VISIBILITY_ON);
+
+ if (Creature* pLichKing = me->GetCreature(*me, uiLichKing))
+ {
+ pLichKing->GetMotionMaster()->MovePoint(0, LichKingSpawnPos);
+ DoScriptText(SAY_LK_INTRO_3, pLichKing);
+ }
+
+ events.ScheduleEvent(EVENT_INTRO_LK_6, 8000);
+ break;
+
+ case EVENT_INTRO_LK_6:
+ if (Creature* pFalric = me->GetCreature(*me, pInstance->GetData64(DATA_FALRIC)))
+ DoScriptText(SAY_FALRIC_INTRO_1, pFalric);
+
+ events.ScheduleEvent(EVENT_INTRO_LK_7, 2000);
+ break;
+
+ case EVENT_INTRO_LK_7:
+ if (Creature* pMarwyn = me->GetCreature(*me, pInstance->GetData64(DATA_MARWYN)))
+ DoScriptText(SAY_MARWYN_INTRO_1, pMarwyn);
+
+ events.ScheduleEvent(EVENT_INTRO_LK_8, 2000);
+ break;
+
+ case EVENT_INTRO_LK_8:
+ if (Creature* pFalric = me->GetCreature(*me, pInstance->GetData64(DATA_FALRIC)))
+ DoScriptText(SAY_FALRIC_INTRO_2, pFalric);
+
+ events.ScheduleEvent(EVENT_INTRO_LK_9, 5000);
+ break;
+
+ case EVENT_INTRO_LK_9:
+ if (pInstance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
+ DoScriptText(SAY_JAINA_INTRO_END, me);
+ else
+ DoScriptText(SAY_SYLVANAS_INTRO_END, me);
+
+ me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos);
+ // TODO: Loralen/Koreln shall run also
+ events.ScheduleEvent(EVENT_INTRO_END, 10000);
+ break;
+
+ case EVENT_INTRO_END:
+ if (pInstance)
+ pInstance->SetData(DATA_WAVE_COUNT, SPECIAL); // start first wave
+
+ // Loralen or Koreln disappearAndDie()
+ me->DisappearAndDie();
+ break;
+
+ case EVENT_SKIP_INTRO:
+ // TODO: implement
+
+ if (Creature* pFalric = me->GetCreature(*me, pInstance->GetData64(DATA_FALRIC)))
+ pFalric->SetVisibility(VISIBILITY_ON);
+ if (Creature* pMarwyn = me->GetCreature(*me, pInstance->GetData64(DATA_MARWYN)))
+ pMarwyn->SetVisibility(VISIBILITY_ON);
+
+ me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos);
+ // TODO: Loralen/Koreln shall run also
+
+ events.ScheduleEvent(EVENT_INTRO_END, 15000);
+ break;
+ }
+ }
+};
+
+bool GossipHello_npc_sylvanas_hor(Player* pPlayer, Creature* pCreature)
+{
+ if (pCreature->isQuestGiver())
+ pPlayer->PrepareQuestMenu(pCreature->GetGUID());
+
+ if (pPlayer->GetQuestStatus(QUEST_DELIVRANCE_FROM_THE_PIT_H2) == QUEST_STATUS_COMPLETE)
+ pPlayer->ADD_GOSSIP_ITEM( 0, "Can you remove the sword?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
+
+ // once last quest is completed, she offers this shortcut of the starting event
+ if (pPlayer->GetQuestStatus(QUEST_WRATH_OF_THE_LICH_KING_H2) == QUEST_STATUS_COMPLETE)
+ pPlayer->ADD_GOSSIP_ITEM( 0, "Dark Lady, I think I hear Arthas coming. Whatever you're going to do, do it quickly.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
+
+ pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetGUID());
+
+ return true;
+}
+
+bool GossipHello_npc_jaina_hor(Player* pPlayer, Creature* pCreature)
+{
+ if (pCreature->isQuestGiver())
+ pPlayer->PrepareQuestMenu(pCreature->GetGUID());
+
+ if (pPlayer->GetQuestStatus(QUEST_DELIVRANCE_FROM_THE_PIT_A2) == QUEST_STATUS_COMPLETE)
+ pPlayer->ADD_GOSSIP_ITEM( 0, "Can you remove the sword?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
+
+ // once last quest of the series is completed, she offers this shortcut of the starting event
+ if (pPlayer->GetQuestStatus(QUEST_WRATH_OF_THE_LICH_KING_A2) == QUEST_STATUS_COMPLETE)
+ pPlayer->ADD_GOSSIP_ITEM( 0, "My Lady, I think I hear Arthas coming. Whatever you're going to do, do it quickly.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
+
+ pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetGUID());
+ return true;
+}
+
+bool GossipSelect_npc_jaina_or_sylvanas_hor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction)
+{
+ switch (uiAction)
+ {
+ case GOSSIP_ACTION_INFO_DEF+1:
+ pPlayer->CLOSE_GOSSIP_MENU();
+ if (pCreature->AI())
+ pCreature->AI()->DoAction(ACTION_START_INTRO);
+ pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ break;
+ case GOSSIP_ACTION_INFO_DEF+2:
+ pPlayer->CLOSE_GOSSIP_MENU();
+ if (pCreature->AI())
+ pCreature->AI()->DoAction(ACTION_SKIP_INTRO);
+ pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
+ break;
+ }
+
+ return true;
+}
+
+enum TrashSpells
+{
+ // Ghostly Priest
+ SPELL_SHADOW_WORD_PAIN = 72318,
+ SPELL_CIRCLE_OF_DESTRUCTION = 72320,
+ SPELL_COWER_IN_FEAR = 72321,
+ SPELL_DARK_MENDING = 72322,
+
+ // Phantom Mage
+ SPELL_FIREBALL = 72163,
+ SPELL_FLAMESTRIKE = 72169,
+ SPELL_FROSTBOLT = 72166,
+ SPELL_CHAINS_OF_ICE = 72121,
+ SPELL_HALLUCINATION = 72342,
+
+ // Phantom Hallucination (same as phantom mage + HALLUCINATION_2 when dies)
+ SPELL_HALLUCINATION_2 = 72344,
+
+ // Shadowy Mercenary
+ SPELL_SHADOW_STEP = 72326,
+ SPELL_DEADLY_POISON = 72329,
+ SPELL_ENVENOMED_DAGGER_THROW = 72333,
+ SPELL_KIDNEY_SHOT = 72335,
+
+ // Spectral Footman
+ SPELL_SPECTRAL_STRIKE = 72198,
+ SPELL_SHIELD_BASH = 72194,
+ SPELL_TORTURED_ENRAGE = 72203,
+
+ // Tortured Rifleman
+ SPELL_SHOOT = 72208,
+ SPELL_CURSED_ARROW = 72222,
+ SPELL_FROST_TRAP = 72215,
+ SPELL_ICE_SHOT = 72268,
+};
+
+enum TrashEvents
+{
+ EVENT_TRASH_NONE,
+
+ // Ghostly Priest
+ EVENT_SHADOW_WORD_PAIN,
+ EVENT_CIRCLE_OF_DESTRUCTION,
+ EVENT_COWER_IN_FEAR,
+ EVENT_DARK_MENDING,
+
+ // Phantom Mage
+ EVENT_FIREBALL,
+ EVENT_FLAMESTRIKE,
+ EVENT_FROSTBOLT,
+ EVENT_CHAINS_OF_ICE,
+ EVENT_HALLUCINATION,
+
+ // Shadowy Mercenary
+ EVENT_SHADOW_STEP,
+ EVENT_DEADLY_POISON,
+ EVENT_ENVENOMED_DAGGER_THROW,
+ EVENT_KIDNEY_SHOT,
+
+ // Spectral Footman
+ EVENT_SPECTRAL_STRIKE,
+ EVENT_SHIELD_BASH,
+ EVENT_TORTURED_ENRAGE,
+
+ // Tortured Rifleman
+ EVENT_SHOOT,
+ EVENT_CURSED_ARROW,
+ EVENT_FROST_TRAP,
+ EVENT_ICE_SHOT,
+};
+
+struct npc_ghostly_priestAI: public ScriptedAI
+{
+ npc_ghostly_priestAI(Creature *c) : ScriptedAI(c)
+ {
+ }
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); // TODO: adjust timers
+ events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000);
+ events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000);
+ events.ScheduleEvent(EVENT_DARK_MENDING, 20000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_SHADOW_WORD_PAIN:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_SHADOW_WORD_PAIN);
+ events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000);
+ return;
+ case EVENT_CIRCLE_OF_DESTRUCTION:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_CIRCLE_OF_DESTRUCTION);
+ events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000);
+ return;
+ case EVENT_COWER_IN_FEAR:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_COWER_IN_FEAR);
+ events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000);
+ return;
+ case EVENT_DARK_MENDING:
+ // find an ally with missing HP
+ if (Unit *pTarget = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000,50000)))
+ {
+ DoCast(pTarget, SPELL_DARK_MENDING);
+ events.ScheduleEvent(EVENT_DARK_MENDING, 20000);
+ }
+ else
+ {
+ // no friendly unit with missing hp. re-check in just 5 sec.
+ events.ScheduleEvent(EVENT_DARK_MENDING, 5000);
+ }
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_phantom_mageAI: public ScriptedAI
+{
+ npc_phantom_mageAI(Creature *c) : ScriptedAI(c)
+ {
+ }
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ events.ScheduleEvent(EVENT_FIREBALL, 3000); // TODO: adjust timers
+ events.ScheduleEvent(EVENT_FLAMESTRIKE, 6000);
+ events.ScheduleEvent(EVENT_FROSTBOLT, 9000);
+ events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12000);
+ events.ScheduleEvent(EVENT_HALLUCINATION, 40000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_FIREBALL:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_FIREBALL);
+ events.ScheduleEvent(EVENT_FIREBALL, 15000);
+ return;
+ case EVENT_FLAMESTRIKE:
+ DoCast(SPELL_FLAMESTRIKE);
+ events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000);
+ return;
+ case EVENT_FROSTBOLT:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_FROSTBOLT);
+ events.ScheduleEvent(EVENT_FROSTBOLT, 15000);
+ return;
+ case EVENT_CHAINS_OF_ICE:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_CHAINS_OF_ICE);
+ events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000);
+ return;
+ case EVENT_HALLUCINATION:
+ DoCast(SPELL_HALLUCINATION);
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_phantom_hallucinationAI: public npc_phantom_mageAI
+{
+ npc_phantom_hallucinationAI(Creature *c) : npc_phantom_mageAI(c)
+ {
+ }
+
+ void JustDied(Unit * /*pWho*/)
+ {
+ DoCast(SPELL_HALLUCINATION_2);
+ }
+};
+
+struct npc_shadowy_mercenaryAI: public ScriptedAI
+{
+ npc_shadowy_mercenaryAI(Creature *c) : ScriptedAI(c)
+ {
+ }
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); // TODO: adjust timers
+ events.ScheduleEvent(EVENT_DEADLY_POISON, 5000);
+ events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000);
+ events.ScheduleEvent(EVENT_KIDNEY_SHOT, 12000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_SHADOW_STEP:
+ DoCast(SPELL_SHADOW_STEP);
+ events.ScheduleEvent(EVENT_SHADOW_STEP, 8000);
+ return;
+ case EVENT_DEADLY_POISON:
+ DoCast(me->getVictim(), SPELL_DEADLY_POISON);
+ events.ScheduleEvent(EVENT_DEADLY_POISON, 10000);
+ return;
+ case EVENT_ENVENOMED_DAGGER_THROW:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_ENVENOMED_DAGGER_THROW);
+ events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000);
+ return;
+ case EVENT_KIDNEY_SHOT:
+ DoCast(me->getVictim(), SPELL_KIDNEY_SHOT);
+ events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000);
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_spectral_footmanAI: public ScriptedAI
+{
+ npc_spectral_footmanAI(Creature *c) : ScriptedAI(c)
+ {
+ }
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); // TODO: adjust timers
+ events.ScheduleEvent(EVENT_SHIELD_BASH, 10000);
+ events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_SPECTRAL_STRIKE:
+ DoCast(me->getVictim(), SPELL_SPECTRAL_STRIKE);
+ events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000);
+ return;
+ case EVENT_SHIELD_BASH:
+ DoCast(me->getVictim(), SPELL_SHIELD_BASH);
+ events.ScheduleEvent(EVENT_SHIELD_BASH, 5000);
+ return;
+ case EVENT_TORTURED_ENRAGE:
+ DoCast(SPELL_TORTURED_ENRAGE);
+ events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000);
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_tortured_riflemanAI : public ScriptedAI
+{
+ npc_tortured_riflemanAI(Creature *c) : ScriptedAI(c)
+ {
+ }
+
+ EventMap events;
+
+ void Reset()
+ {
+ events.Reset();
+ }
+
+ void EnterCombat(Unit* /*who*/)
+ {
+ events.ScheduleEvent(EVENT_SHOOT, 2000); // TODO: adjust timers
+ events.ScheduleEvent(EVENT_CURSED_ARROW, 10000);
+ events.ScheduleEvent(EVENT_FROST_TRAP, 1000);
+ events.ScheduleEvent(EVENT_ICE_SHOT, 15000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_SHOOT:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_SHOOT);
+ events.ScheduleEvent(EVENT_SHOOT, 2000);
+ return;
+ case EVENT_CURSED_ARROW:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_CURSED_ARROW);
+ events.ScheduleEvent(EVENT_CURSED_ARROW, 10000);
+ return;
+ case EVENT_FROST_TRAP:
+ DoCast(SPELL_FROST_TRAP);
+ events.ScheduleEvent(EVENT_FROST_TRAP, 30000);
+ return;
+ case EVENT_ICE_SHOT:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM))
+ DoCast(pTarget, SPELL_ICE_SHOT);
+ events.ScheduleEvent(EVENT_ICE_SHOT, 15000);
+ return;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+CreatureAI* GetAI_npc_jaina_or_sylvanas_horAI(Creature* pCreature)
+{
+ return new npc_jaina_or_sylvanas_horAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_ghostly_priestAI(Creature* pCreature)
+{
+ return new npc_ghostly_priestAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_phantom_mageAI(Creature* pCreature)
+{
+ return new npc_phantom_mageAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_phantom_hallucinationAI(Creature* pCreature)
+{
+ return new npc_phantom_hallucinationAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_shadowy_mercenaryAI(Creature* pCreature)
+{
+ return new npc_shadowy_mercenaryAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_spectral_footmanAI(Creature* pCreature)
+{
+ return new npc_spectral_footmanAI(pCreature);
+}
+
+CreatureAI* GetAI_npc_tortured_riflemanAI(Creature* pCreature)
+{
+ return new npc_tortured_riflemanAI(pCreature);
+}
+
+void AddSC_halls_of_reflection()
+{
+ Script *newscript;
+
+ newscript = new Script;
+ newscript->Name = "npc_sylvanas_hor_part1";
+ newscript->GetAI = &GetAI_npc_jaina_or_sylvanas_horAI;
+ newscript->pGossipHello = &GossipHello_npc_sylvanas_hor;
+ newscript->pGossipSelect = &GossipSelect_npc_jaina_or_sylvanas_hor;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_jaina_hor_part1";
+ newscript->GetAI = &GetAI_npc_jaina_or_sylvanas_horAI;
+ newscript->pGossipHello = &GossipHello_npc_jaina_hor;
+ newscript->pGossipSelect = &GossipSelect_npc_jaina_or_sylvanas_hor;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_ghostly_priest";
+ newscript->GetAI = &GetAI_npc_ghostly_priestAI;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_phantom_mage";
+ newscript->GetAI = &GetAI_npc_phantom_mageAI;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_phantom_hallucination";
+ newscript->GetAI = &GetAI_npc_phantom_hallucinationAI;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_shadowy_mercenary";
+ newscript->GetAI = &GetAI_npc_shadowy_mercenaryAI;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_spectral_footman";
+ newscript->GetAI = &GetAI_npc_spectral_footmanAI;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "npc_tortured_rifleman";
+ newscript->GetAI = &GetAI_npc_tortured_riflemanAI;
+ newscript->RegisterSelf();
+}
diff --git a/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h b/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h
index ac7ddc09b6d..46ae0cb283c 100644
--- a/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h
+++ b/src/scripts/northrend/frozen_halls/halls_of_reflection/halls_of_reflection.h
@@ -16,16 +16,141 @@
#ifndef DEF_HALLS_OF_REFLECTION_H
#define DEF_HALLS_OF_REFLECTION_H
+
enum Data
{
DATA_FALRIC_EVENT,
DATA_MARWYN_EVENT,
- DATA_LICHKING_EVENT
+ DATA_LICHKING_EVENT,
+ DATA_WAVE_COUNT,
+ DATA_TEAM_IN_INSTANCE,
+};
+
+enum Data64
+{
+ DATA_FALRIC,
+ DATA_MARWYN,
+ DATA_LICHKING,
+ DATA_FROSTMOURNE,
};
+
enum Creatures
{
- CREATURE_FALRIC = 36494,
- CREATURE_MARWYN = 36476,
- CREATURE_LICHKING = 36658
+ NPC_FALRIC = 38112,
+ NPC_MARWYN = 38113,
+ NPC_LICH_KING_EVENT = 37226,
+ NPC_LICH_KING_BOSS = 36954,
+
+ NPC_UTHER = 37225,
+ NPC_JAINA_PART1 = 37221,
+ NPC_JAINA_PART2 = 36955,
+ NPC_SYLVANAS_PART1 = 37223,
+ NPC_SYLVANAS_PART2 = 37554,
+
+ NPC_WAVE_MERCENARY = 38177,
+ NPC_WAVE_FOOTMAN = 38173,
+ NPC_WAVE_RIFLEMAN = 38176,
+ NPC_WAVE_PRIEST = 38175,
+ NPC_WAVE_MAGE = 38172,
+};
+
+enum GameObjects
+{
+ GO_FROSTMOURNE = 202302,
+ GO_FROSTMOURNE_ALTAR = 202236,
+ GO_FRONT_DOOR = 201976,
+ GO_ARTHAS_DOOR = 197341,
};
+
+enum HorWorldStates
+{
+ WORLD_STATE_HOR = 4884,
+ WORLD_STATE_HOR_WAVE_COUNT = 4882,
+};
+
+// Common actions from Instance Script to Boss Script
+enum Actions
+{
+ ACTION_ENTER_COMBAT,
+};
+
+// Base class for FALRIC and MARWYN
+// handled the summonList and the notification events to/from the InstanceData
+struct boss_horAI : ScriptedAI
+{
+ boss_horAI(Creature *pCreature) : ScriptedAI(pCreature), summons(pCreature)
+ {
+ pInstance = me->GetInstanceData();
+ }
+
+ InstanceData* pInstance;
+ EventMap events;
+ SummonList summons;
+
+ void Reset()
+ {
+ events.Reset();
+ me->SetVisibility(VISIBILITY_OFF);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void DamageTaken(Unit *pWho, uint32 &uiDamage)
+ {
+ if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
+ uiDamage = 0;
+ }
+
+ void DoAction(const int32 actionID)
+ {
+ switch(actionID)
+ {
+ case ACTION_ENTER_COMBAT: // called by InstanceData when boss shall enter in combat.
+ // Just in case. Should have been done by InstanceData
+ me->SetVisibility(VISIBILITY_ON);
+
+ // Reset flags
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ if (Unit *pUnit = me->SelectNearestTarget())
+ AttackStart(pUnit);
+
+ DoZoneInCombat();
+ break;
+ }
+ }
+
+ void JustSummoned(Creature *pSummoned)
+ {
+ summons.Summon(pSummoned);
+
+ if (Unit *pUnit = pSummoned->SelectNearestTarget())
+ {
+ if (pSummoned->AI())
+ pSummoned->AI()->AttackStart(pUnit);
+ else
+ {
+ pSummoned->GetMotionMaster()->MoveChase(pUnit);
+ pSummoned->Attack(pUnit, true);
+ }
+ }
+
+ if (pSummoned->AI())
+ pSummoned->AI()->DoZoneInCombat();
+ }
+
+ void SummonedCreatureDespawn(Creature *pSummoned)
+ {
+ summons.Despawn(pSummoned);
+ if (summons.empty())
+ {
+ if (pSummoned->isAlive())
+ pInstance->SetData(DATA_WAVE_COUNT, NOT_STARTED);
+ else
+ pInstance->SetData(DATA_WAVE_COUNT, SPECIAL);
+ }
+ }
+};
+
#endif
diff --git a/src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp b/src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp
index 3c0c1321a77..7a5d2479b7c 100644
--- a/src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp
+++ b/src/scripts/northrend/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp
@@ -25,61 +25,212 @@
2- The Lich King
*/
+enum eEnum
+{
+ ENCOUNTER_WAVE_MERCENARY = 6,
+ ENCOUNTER_WAVE_FOOTMAN = 10,
+ ENCOUNTER_WAVE_RIFLEMAN = 6,
+ ENCOUNTER_WAVE_PRIEST = 6,
+ ENCOUNTER_WAVE_MAGE = 6,
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_NEXT_WAVE,
+ EVENT_START_LICH_KING,
+};
+
+static Position PriestSpawnPos[ENCOUNTER_WAVE_PRIEST] =
+{
+ {5277.74,2016.88,707.778,5.96903},
+ {5295.88,2040.34,707.778,5.07891},
+ {5320.37,1980.13,707.778,2.00713},
+ {5280.51,1997.84,707.778,0.296706},
+ {5302.45,2042.22,707.778,4.90438},
+ {5306.57,1977.47,707.778,1.50098},
+};
+
+static Position MageSpawnPos[ENCOUNTER_WAVE_MAGE] =
+{
+ {5312.75,2037.12,707.778,4.59022},
+ {5309.58,2042.67,707.778,4.69494},
+ {5275.08,2008.72,707.778,6.21337},
+ {5279.65,2004.66,707.778,0.069813},
+ {5275.48,2001.14,707.778,0.174533},
+ {5316.7,2041.55,707.778,4.50295},
+};
+
+static Position MercenarySpawnPos[ENCOUNTER_WAVE_MERCENARY] =
+{
+ {5302.25,1972.41,707.778,1.37881},
+ {5311.03,1972.23,707.778,1.64061},
+ {5277.36,1993.23,707.778,0.401426},
+ {5318.7,2036.11,707.778,4.2237},
+ {5335.72,1996.86,707.778,2.74017},
+ {5299.43,1979.01,707.778,1.23918},
+};
+
+static Position FootmenSpawnPos[ENCOUNTER_WAVE_FOOTMAN] =
+{
+ {5306.06,2037,707.778,4.81711},
+ {5344.15,2007.17,707.778,3.15905},
+ {5337.83,2010.06,707.778,3.22886},
+ {5343.29,1999.38,707.778,2.9147},
+ {5340.84,1992.46,707.778,2.75762},
+ {5325.07,1977.6,707.778,2.07694},
+ {5336.6,2017.28,707.778,3.47321},
+ {5313.82,1978.15,707.778,1.74533},
+ {5280.63,2012.16,707.778,6.05629},
+ {5322.96,2040.29,707.778,4.34587},
+};
+
+static Position RiflemanSpawnPos[ENCOUNTER_WAVE_RIFLEMAN] =
+{
+ {5343.47,2015.95,707.778,3.49066},
+ {5337.86,2003.4,707.778,2.98451},
+ {5319.16,1974,707.778,1.91986},
+ {5299.25,2036,707.778,5.02655},
+ {5295.64,1973.76,707.778,1.18682},
+ {5282.9,2019.6,707.778,5.88176},
+};
+
struct instance_halls_of_reflection : public ScriptedInstance
{
- instance_halls_of_reflection(Map* pMap) : ScriptedInstance(pMap) {Initialize();};
+ instance_halls_of_reflection(Map* pMap) : ScriptedInstance(pMap) {};
uint64 uiFalric;
uint64 uiMarwyn;
- uint64 uiLichKing;
+ uint64 uiLichKingEvent;
+ uint64 uiJainaPart1;
+ uint64 uiSylvanasPart1;
- uint32 m_auiEncounter[MAX_ENCOUNTER];
+ uint64 uiFrostmourne;
+ uint64 uiFrostmourneAltar;
+ uint64 uiArthasDoor;
+ uint64 uiFrontDoor;
+
+ uint32 uiEncounter[MAX_ENCOUNTER];
+ uint32 uiTeamInInstance;
+ uint32 uiWaveCount;
+ bool bIntroDone;
+
+ EventMap events;
void Initialize()
{
+ events.Reset();
+
uiFalric = 0;
uiMarwyn = 0;
- uiLichKing = 0;
+ uiLichKingEvent = 0;
+ uiJainaPart1 = 0;
+ uiSylvanasPart1 = 0;
+
+ uiFrostmourne = 0;
+ uiFrostmourneAltar = 0;
+ uiArthasDoor = 0;
+ uiFrontDoor = 0;
+ uiTeamInInstance = 0;
+ uiWaveCount = 0;
+ bIntroDone = false;
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- m_auiEncounter[i] = NOT_STARTED;
+ uiEncounter[i] = NOT_STARTED;
}
- void OnCreatureCreate(Creature* pCreature, bool /*add*/)
+ void OnCreatureCreate(Creature* pCreature, bool add)
{
+ if (!add)
+ return;
+
+ Map::PlayerList const &players = instance->GetPlayers();
+ if (!players.isEmpty())
+ if (Player* pPlayer = players.begin()->getSource())
+ uiTeamInInstance = pPlayer->GetTeam();
+
switch(pCreature->GetEntry())
{
- case CREATURE_FALRIC:
+ case NPC_FALRIC:
uiFalric = pCreature->GetGUID();
break;
- case CREATURE_MARWYN:
+ case NPC_MARWYN:
uiMarwyn = pCreature->GetGUID();
break;
- case CREATURE_LICHKING:
- uiLichKing = pCreature->GetGUID();
+ case NPC_LICH_KING_EVENT:
+ uiLichKingEvent = pCreature->GetGUID();
+ break;
+ case NPC_JAINA_PART1:
+ uiJainaPart1 = pCreature->GetGUID();
+ break;
+ case NPC_SYLVANAS_PART1:
+ uiSylvanasPart1 = pCreature->GetGUID();
break;
}
}
-/*
+
void OnGameObjectCreate(GameObject* pGo, bool add)
{
+ if (!add)
+ return;
+
+ // TODO: init state depending on encounters
switch(pGo->GetEntry())
{
+ case GO_FROSTMOURNE:
+ uiFrostmourne = pGo->GetGUID();
+ pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND);
+ HandleGameObject(0, false, pGo);
+ break;
+ case GO_FROSTMOURNE_ALTAR:
+ uiFrostmourneAltar = pGo->GetGUID();
+ pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND);
+ HandleGameObject(0, true, pGo);
+ break;
+ case GO_FRONT_DOOR:
+ uiFrontDoor = pGo->GetGUID();
+ pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND);
+ HandleGameObject(0, true, pGo);
+ break;
+ case GO_ARTHAS_DOOR:
+ uiArthasDoor = pGo->GetGUID();
+ pGo->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND);
+
+ if (uiEncounter[1] == DONE)
+ HandleGameObject(0, true, pGo);
+ else
+ HandleGameObject(0, false, pGo);
+ break;
}
}
-*/
+
void SetData(uint32 type, uint32 data)
{
+ if (type == DATA_WAVE_COUNT && data == SPECIAL)
+ {
+ bIntroDone = true;
+ events.ScheduleEvent(EVENT_NEXT_WAVE, 10000);
+ return;
+ }
+
+
+ if (uiWaveCount && data == NOT_STARTED)
+ DoWipe();
+
switch(type)
{
case DATA_FALRIC_EVENT:
- m_auiEncounter[0] = data;
+ uiEncounter[0] = data;
+ if (data == DONE)
+ events.ScheduleEvent(EVENT_NEXT_WAVE, 60000);
break;
case DATA_MARWYN_EVENT:
- m_auiEncounter[1] = data;
+ uiEncounter[1] = data;
+ if (data == DONE)
+ HandleGameObject(uiArthasDoor, true);
break;
case DATA_LICHKING_EVENT:
- m_auiEncounter[2] = data;
+ uiEncounter[2] = data;
break;
}
@@ -91,29 +242,35 @@ struct instance_halls_of_reflection : public ScriptedInstance
{
switch(type)
{
- case DATA_FALRIC_EVENT: return m_auiEncounter[0];
- case DATA_MARWYN_EVENT: return m_auiEncounter[1];
- case DATA_LICHKING_EVENT: return m_auiEncounter[2];
+ case DATA_FALRIC_EVENT: return uiEncounter[0];
+ case DATA_MARWYN_EVENT: return uiEncounter[1];
+ case DATA_LICHKING_EVENT: return uiEncounter[2];
+ case DATA_WAVE_COUNT: return uiWaveCount;
+ case DATA_TEAM_IN_INSTANCE: return uiTeamInInstance;
}
return 0;
}
-/*
+
uint64 GetData64(uint32 identifier)
{
switch(identifier)
{
+ case DATA_FALRIC: return uiFalric;
+ case DATA_MARWYN: return uiMarwyn;
+ case DATA_LICHKING: return uiLichKingEvent;
+ case DATA_FROSTMOURNE: return uiFrostmourne;
}
return 0;
}
-*/
+
std::string GetSaveData()
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
- saveStream << "H R " << m_auiEncounter[0] << " " << m_auiEncounter[1] << m_auiEncounter[2];
+ saveStream << "H R 1 " << uiEncounter[0] << " " << uiEncounter[1] << " " << uiEncounter[2];
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
@@ -130,25 +287,133 @@ struct instance_halls_of_reflection : public ScriptedInstance
OUT_LOAD_INST_DATA(in);
char dataHead1, dataHead2;
+ uint16 version;
uint16 data0, data1, data2;
std::istringstream loadStream(in);
- loadStream >> dataHead1 >> dataHead2 >> data0 >> data1 >> data2;
+ loadStream >> dataHead1 >> dataHead2 >> version >> data0 >> data1 >> data2;
if (dataHead1 == 'H' && dataHead2 == 'R')
{
- m_auiEncounter[0] = data0;
- m_auiEncounter[1] = data1;
- m_auiEncounter[2] = data2;
+ uiEncounter[0] = data0;
+ uiEncounter[1] = data1;
+ uiEncounter[2] = data2;
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
- if (m_auiEncounter[i] == IN_PROGRESS)
- m_auiEncounter[i] = NOT_STARTED;
+ if (uiEncounter[i] == IN_PROGRESS)
+ uiEncounter[i] = NOT_STARTED;
} else OUT_LOAD_INST_DATA_FAIL;
+ if (uiEncounter[0] == DONE || uiEncounter[1] == DONE)
+ bIntroDone = true;
+
OUT_LOAD_INST_DATA_COMPLETE;
}
+
+ void AddWave()
+ {
+ DoUpdateWorldState(WORLD_STATE_HOR, 1);
+ DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount);
+
+ switch(uiWaveCount)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ if (Creature *pFalric = instance->GetCreature(uiFalric))
+ SpawnWave(pFalric);
+ break;
+ case 5:
+ if (GetData(DATA_FALRIC_EVENT) == DONE)
+ events.ScheduleEvent(EVENT_NEXT_WAVE, 10000);
+ else if (Creature *pFalric = instance->GetCreature(uiFalric))
+ if (pFalric->AI())
+ pFalric->AI()->DoAction(ACTION_ENTER_COMBAT);
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ if (Creature *pMarwyn = instance->GetCreature(uiMarwyn))
+ SpawnWave(pMarwyn);
+ break;
+ case 10:
+ if (GetData(DATA_MARWYN_EVENT) != DONE) // wave should not have been started if DONE. Check anyway to avoid bug exploit!
+ if (Creature *pMarwyn = instance->GetCreature(uiMarwyn))
+ if (pMarwyn->AI())
+ pMarwyn->AI()->DoAction(ACTION_ENTER_COMBAT);
+ break;
+ }
+ }
+
+ // Wipe has been detected. Perform cleanup and reset.
+ void DoWipe()
+ {
+ uiWaveCount = 0;
+ events.Reset();
+ DoUpdateWorldState(WORLD_STATE_HOR, 1);
+ DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount);
+ HandleGameObject(uiFrontDoor, true);
+
+ // TODO
+ // in case of wipe, the event is normally restarted by jumping into the center of the room.
+ // As I can't find a trigger area there, just respawn Jaina/Sylvanas so the event may be restarted.
+ if (Creature* pJaina = instance->GetCreature(uiJainaPart1))
+ pJaina->Respawn();
+ if (Creature* pSylvanas = instance->GetCreature(uiSylvanasPart1))
+ pSylvanas->Respawn();
+
+ if (Creature* pFalric = instance->GetCreature(uiFalric))
+ pFalric->SetVisibility(VISIBILITY_OFF);
+ if (Creature* pMarwyn = instance->GetCreature(uiMarwyn))
+ pMarwyn->SetVisibility(VISIBILITY_OFF);
+ }
+
+ // spawn a wave on behalf of the summoner.
+ void SpawnWave(Creature *pSummoner)
+ {
+ uint32 index;
+
+ pSummoner->SetVisibility(VISIBILITY_ON);
+
+ // TODO: do composition at random. # of spawn also depends on uiWaveCount
+ // As of now, it is just one of each.
+ index = urand(0,ENCOUNTER_WAVE_MERCENARY-1);
+ pSummoner->SummonCreature(NPC_WAVE_MERCENARY, MercenarySpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ index = urand(0,ENCOUNTER_WAVE_FOOTMAN-1);
+ pSummoner->SummonCreature(NPC_WAVE_FOOTMAN, FootmenSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ index = urand(0,ENCOUNTER_WAVE_RIFLEMAN-1);
+ pSummoner->SummonCreature(NPC_WAVE_RIFLEMAN, RiflemanSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ index = urand(0,ENCOUNTER_WAVE_PRIEST-1);
+ pSummoner->SummonCreature(NPC_WAVE_PRIEST, PriestSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+
+ index = urand(0,ENCOUNTER_WAVE_MAGE-1);
+ pSummoner->SummonCreature(NPC_WAVE_MAGE, MageSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
+ }
+
+ void Update(uint32 diff)
+ {
+ if (!instance->HavePlayers())
+ return;
+
+ events.Update(diff);
+
+ switch(uint32 eventId = events.ExecuteEvent())
+ {
+ case EVENT_NEXT_WAVE:
+ uiWaveCount++;
+ AddWave();
+ break;
+ case EVENT_START_LICH_KING:
+ // TODO
+ break;
+ }
+ }
};
InstanceData* GetInstanceData_instance_halls_of_reflection(Map* pMap)
@@ -156,7 +421,7 @@ InstanceData* GetInstanceData_instance_halls_of_reflection(Map* pMap)
return new instance_halls_of_reflection(pMap);
}
-void AddSC_halls_of_reflection()
+void AddSC_instance_halls_of_reflection()
{
Script *newscript;
newscript = new Script;