diff options
Diffstat (limited to 'src')
5 files changed, 1008 insertions, 623 deletions
diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp index 58dc74d0f0a..9d266c77b77 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp @@ -19,7 +19,7 @@ #include "ScriptedCreature.h" #include "halls_of_reflection.h" -enum Yells +enum Texts { SAY_AGGRO = 0, SAY_SLAY = 1, @@ -68,14 +68,14 @@ public: uiHopelessnessCount = 0; if (instance) - instance->SetData(DATA_FALRIC_EVENT, NOT_STARTED); + instance->SetBossState(DATA_FALRIC_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) { Talk(SAY_AGGRO); if (instance) - instance->SetData(DATA_FALRIC_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_FALRIC_EVENT, IN_PROGRESS); events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000); events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000); @@ -87,7 +87,7 @@ public: Talk(SAY_DEATH); if (instance) - instance->SetData(DATA_FALRIC_EVENT, DONE); + instance->SetBossState(DATA_FALRIC_EVENT, DONE); } void KilledUnit(Unit* /*victim*/) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index 08d5cf70ee1..e82f0d48ebd 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -19,7 +19,7 @@ #include "ScriptedCreature.h" #include "halls_of_reflection.h" -enum Yells +enum Texts { SAY_AGGRO = 0, SAY_SLAY = 1, @@ -63,14 +63,14 @@ public: boss_horAI::Reset(); if (instance) - instance->SetData(DATA_MARWYN_EVENT, NOT_STARTED); + instance->SetBossState(DATA_MARWYN_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) { Talk(SAY_AGGRO); if (instance) - instance->SetData(DATA_MARWYN_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_MARWYN_EVENT, IN_PROGRESS); events.ScheduleEvent(EVENT_OBLITERATE, 30000); /// @todo Check timer events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); @@ -83,7 +83,7 @@ public: Talk(SAY_DEATH); if (instance) - instance->SetData(DATA_MARWYN_EVENT, DONE); + instance->SetBossState(DATA_MARWYN_EVENT, DONE); } void KilledUnit(Unit* /*victim*/) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index b140801d8f1..eab4b100da2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -17,11 +17,9 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "ScriptedGossip.h" #include "halls_of_reflection.h" -#include "Player.h" -enum Yells +enum Text { SAY_JAINA_INTRO_1 = 0, SAY_JAINA_INTRO_2 = 1, @@ -66,17 +64,19 @@ enum Yells SAY_LK_INTRO_1 = 0, SAY_LK_INTRO_2 = 1, SAY_LK_INTRO_3 = 2, + SAY_LK_JAINA_INTRO_END = 3, + SAY_LK_SYLVANAS_INTRO_END = 4, SAY_FALRIC_INTRO_1 = 5, SAY_FALRIC_INTRO_2 = 6, - SAY_MARWYN_INTRO_1 = 4 + SAY_MARWYN_INTRO_1 = 4, }; enum Events { - EVENT_NONE, - + EVENT_WALK_INTRO1 = 1, + EVENT_WALK_INTRO2, EVENT_START_INTRO, EVENT_SKIP_INTRO, @@ -125,8 +125,13 @@ enum Events EVENT_INTRO_LK_7, EVENT_INTRO_LK_8, EVENT_INTRO_LK_9, + EVENT_INTRO_LK_10, + EVENT_INTRO_LK_11, EVENT_INTRO_END, + + EVENT_OPEN_FROSTWORN_DOOR, + EVENT_CLOSE_FROSTWORN_DOOR, }; enum eEnum @@ -140,6 +145,17 @@ enum eEnum QUEST_WRATH_OF_THE_LICH_KING_H2 = 24802, }; +enum Spells +{ + SPELL_CAST_VISUAL = 65633, // Jaina/Sylavana + SPELL_BOSS_SPAWN_AURA = 72712, // Falric and Marwyn + SPELL_UTHER_DESPAWN = 70693, + SPELL_TAKE_FROSTMOURNE = 72729, + SPELL_FROSTMOURNE_DESPAWN = 72726, + SPELL_FROSTMOURNE_VISUAL = 73220, + SPELL_FROSTMOURNE_SOUNDS = 70667, +}; + const Position HallsofReflectionLocs[]= { {5283.234863f, 1990.946777f, 707.695679f, 0.929097f}, // 2 Loralen Follows @@ -147,7 +163,7 @@ const Position HallsofReflectionLocs[]= {5401.866699f, 2110.837402f, 707.695251f, 0.800610f}, // 10 Loralen follows }; -const Position SpawnPos = {5262.540527f, 1949.693726f, 707.695007f, 0.808736f}; // Jaina/Sylvanas Beginning Position +const Position IntroPos = {5265.89f, 1952.98f, 707.6978f, 0.0f}; // Jaina/Sylvanas Intro Start Position const Position MoveThronePos = {5306.952148f, 1998.499023f, 709.341431f, 1.277278f}; // Jaina/Sylvanas walks to throne const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f}; const Position LichKingSpawnPos = {5362.917480f, 2062.307129f, 707.695374f, 3.945812f}; @@ -156,58 +172,10 @@ const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, class npc_jaina_or_sylvanas_hor : public CreatureScript { -private: - bool m_isSylvana; - -public: - npc_jaina_or_sylvanas_hor(bool isSylvana, const char* name) : CreatureScript(name), m_isSylvana(isSylvana) { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - if (creature->AI()) - creature->AI()->DoAction(ACTION_START_INTRO); - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - if (creature->AI()) - creature->AI()->DoAction(ACTION_SKIP_INTRO); - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - break; - } - - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (creature->isQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - QuestStatus status = player->GetQuestStatus(m_isSylvana ? QUEST_DELIVRANCE_FROM_THE_PIT_H2 : QUEST_DELIVRANCE_FROM_THE_PIT_A2); - if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - player->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 - status = player->GetQuestStatus(m_isSylvana ? QUEST_WRATH_OF_THE_LICH_KING_H2 : QUEST_WRATH_OF_THE_LICH_KING_A2); - if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - player->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); - - player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); - return true; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_jaina_or_sylvanas_horAI(creature); - } + public: + npc_jaina_or_sylvanas_hor() : CreatureScript("npc_jaina_or_sylvanas_hor") { } - // AI of Part1: handle the intro till start of gauntlet event. + // AI of Part1 struct npc_jaina_or_sylvanas_horAI : public ScriptedAI { npc_jaina_or_sylvanas_horAI(Creature* creature) : ScriptedAI(creature) @@ -221,6 +189,24 @@ public: EventMap events; + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) + { + player->PlayerTalkClass->ClearMenus(); + switch (action) + { + case 0: + player->CLOSE_GOSSIP_MENU(); + events.ScheduleEvent(EVENT_START_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; + case 1: + player->CLOSE_GOSSIP_MENU(); + events.ScheduleEvent(EVENT_SKIP_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; + } + } + void Reset() { events.Reset(); @@ -228,22 +214,9 @@ public: utherGUID = 0; lichkingGUID = 0; - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetVisible(true); - } - - void DoAction(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; - } + events.ScheduleEvent(EVENT_WALK_INTRO1, 3000); } void UpdateAI(uint32 diff) @@ -251,6 +224,26 @@ public: events.Update(diff); switch (events.ExecuteEvent()) { + case EVENT_WALK_INTRO1: + me->GetMotionMaster()->MovePoint(0, IntroPos); + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + { + Talk(SAY_JAINA_INTRO_1); + events.ScheduleEvent(EVENT_WALK_INTRO2, 7000); + } + else + { + Talk(SAY_SYLVANAS_INTRO_1); + events.ScheduleEvent(EVENT_WALK_INTRO2, 9000); + } + break; + case EVENT_WALK_INTRO2: + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + Talk(SAY_JAINA_INTRO_2); + else + Talk(SAY_SYLVANAS_INTRO_2); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; case EVENT_START_INTRO: me->GetMotionMaster()->MovePoint(0, MoveThronePos); // Begining of intro is differents between fActions as the speech sequence and timers are differents. @@ -259,27 +252,25 @@ public: else events.ScheduleEvent(EVENT_INTRO_H2_1, 0); break; - - // A2 Intro Events + // A2 Intro Events case EVENT_INTRO_A2_1: Talk(SAY_JAINA_INTRO_3); - events.ScheduleEvent(EVENT_INTRO_A2_2, 5000); + events.ScheduleEvent(EVENT_INTRO_A2_2, 7000); break; case EVENT_INTRO_A2_2: Talk(SAY_JAINA_INTRO_4); events.ScheduleEvent(EVENT_INTRO_A2_3, 10000); break; case EVENT_INTRO_A2_3: - /// @todo she's doing some kind of spell casting emote + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); instance->HandleGameObject(instance->GetData64(DATA_FROSTMOURNE), true); events.ScheduleEvent(EVENT_INTRO_A2_4, 10000); break; case EVENT_INTRO_A2_4: - // spawn UTHER during speach 2 if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { uther->GetMotionMaster()->MoveIdle(); - uther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas utherGUID = uther->GetGUID(); } events.ScheduleEvent(EVENT_INTRO_A2_5, 2000); @@ -291,57 +282,57 @@ public: break; case EVENT_INTRO_A2_6: Talk(SAY_JAINA_INTRO_5); - events.ScheduleEvent(EVENT_INTRO_A2_7, 6000); + events.ScheduleEvent(EVENT_INTRO_A2_7, 7000); break; case EVENT_INTRO_A2_7: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_2); - events.ScheduleEvent(EVENT_INTRO_A2_8, 6500); + events.ScheduleEvent(EVENT_INTRO_A2_8, 7000); break; case EVENT_INTRO_A2_8: Talk(SAY_JAINA_INTRO_6); - events.ScheduleEvent(EVENT_INTRO_A2_9, 2000); + events.ScheduleEvent(EVENT_INTRO_A2_9, 1200); break; case EVENT_INTRO_A2_9: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_3); - events.ScheduleEvent(EVENT_INTRO_A2_10, 9000); + events.ScheduleEvent(EVENT_INTRO_A2_10, 11000); break; case EVENT_INTRO_A2_10: Talk(SAY_JAINA_INTRO_7); - events.ScheduleEvent(EVENT_INTRO_A2_11, 5000); + events.ScheduleEvent(EVENT_INTRO_A2_11, 6000); break; case EVENT_INTRO_A2_11: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_4); - events.ScheduleEvent(EVENT_INTRO_A2_12, 11000); + events.ScheduleEvent(EVENT_INTRO_A2_12, 12000); break; case EVENT_INTRO_A2_12: Talk(SAY_JAINA_INTRO_8); - events.ScheduleEvent(EVENT_INTRO_A2_13, 4000); + events.ScheduleEvent(EVENT_INTRO_A2_13, 6000); break; case EVENT_INTRO_A2_13: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_5); - events.ScheduleEvent(EVENT_INTRO_A2_14, 12500); + events.ScheduleEvent(EVENT_INTRO_A2_14, 13000); break; case EVENT_INTRO_A2_14: Talk(SAY_JAINA_INTRO_9); - events.ScheduleEvent(EVENT_INTRO_A2_15, 10000); + events.ScheduleEvent(EVENT_INTRO_A2_15, 12000); break; case EVENT_INTRO_A2_15: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_6); - events.ScheduleEvent(EVENT_INTRO_A2_16, 22000); + events.ScheduleEvent(EVENT_INTRO_A2_16, 25000); break; case EVENT_INTRO_A2_16: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_7); - events.ScheduleEvent(EVENT_INTRO_A2_17, 4000); + events.ScheduleEvent(EVENT_INTRO_A2_17, 6000); break; case EVENT_INTRO_A2_17: Talk(SAY_JAINA_INTRO_10); - events.ScheduleEvent(EVENT_INTRO_A2_18, 2000); + events.ScheduleEvent(EVENT_INTRO_A2_18, 5000); break; case EVENT_INTRO_A2_18: if (Creature* uther = me->GetCreature(*me, utherGUID)) @@ -349,14 +340,13 @@ public: uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); uther->AI()->Talk(SAY_UTHER_INTRO_A2_8); } - events.ScheduleEvent(EVENT_INTRO_A2_19, 11000); + events.ScheduleEvent(EVENT_INTRO_A2_19, 12000); break; case EVENT_INTRO_A2_19: Talk(SAY_JAINA_INTRO_11); - events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_1, 3000); break; - - // H2 Intro Events + // H2 Intro Events case EVENT_INTRO_H2_1: Talk(SAY_SYLVANAS_INTRO_1); events.ScheduleEvent(EVENT_INTRO_H2_2, 8000); @@ -367,7 +357,9 @@ public: break; case EVENT_INTRO_H2_3: Talk(SAY_SYLVANAS_INTRO_3); - /// @todo she's doing some kind of spell casting emote + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); + instance->HandleGameObject(instance->GetData64(DATA_FROSTMOURNE), true); events.ScheduleEvent(EVENT_INTRO_H2_4, 6000); break; case EVENT_INTRO_H2_4: @@ -375,7 +367,6 @@ public: if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { uther->GetMotionMaster()->MoveIdle(); - uther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas utherGUID = uther->GetGUID(); } events.ScheduleEvent(EVENT_INTRO_H2_5, 2000); @@ -433,126 +424,160 @@ public: Talk(SAY_SYLVANAS_INTRO_8); events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); break; - - // Remaining Intro Events common for both faction + // 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* lichking = me->SummonCreature(NPC_LICH_KING_EVENT, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); - lichking->SetReactState(REACT_PASSIVE); + //lichking->SetReactState(REACT_PASSIVE); lichkingGUID = lichking->GetGUID(); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); } - if (Creature* uther = me->GetCreature(*me, utherGUID)) { + uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) uther->AI()->Talk(SAY_UTHER_INTRO_A2_9); else uther->AI()->Talk(SAY_UTHER_INTRO_H2_7); } - - events.ScheduleEvent(EVENT_INTRO_LK_2, 11000); + events.ScheduleEvent(EVENT_INTRO_LK_2, 10000); break; - case EVENT_INTRO_LK_2: - if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_1); - events.ScheduleEvent(EVENT_INTRO_LK_3, 2000); - break; - + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_1); + events.ScheduleEvent(EVENT_INTRO_LK_3, 1000); + break; case EVENT_INTRO_LK_3: - // The Lich King banishes Uther to the abyss. - if (Creature* uther = me->GetCreature(*me, utherGUID)) - { - uther->DisappearAndDie(); - utherGUID = 0; - } - - // He steps forward and removes the runeblade from the heap of skulls. - - events.ScheduleEvent(EVENT_INTRO_LK_4, 4000); - break; - + // The Lich King banishes Uther to the abyss. + if (Creature* uther = me->GetCreature(*me, utherGUID)) + { + uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true); + uther->DespawnOrUnsummon(5000); + utherGUID = 0; + } + events.ScheduleEvent(EVENT_INTRO_LK_4, 9000); + break; case EVENT_INTRO_LK_4: - if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_2); - events.ScheduleEvent(EVENT_INTRO_LK_5, 10000); + // He steps forward and removes the runeblade from the heap of skulls. + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + if (GameObject* frostmourne = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTMOURNE))) + frostmourne->SetPhaseMask(2, true); + lichking->CastSpell(lichking, SPELL_TAKE_FROSTMOURNE, true); + lichking->CastSpell(lichking, SPELL_FROSTMOURNE_VISUAL, true); + } + events.ScheduleEvent(EVENT_INTRO_LK_5, 8000); break; - case EVENT_INTRO_LK_5: + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_2); + events.ScheduleEvent(EVENT_INTRO_LK_6, 8000); + break; + case EVENT_INTRO_LK_6: // summon Falric and Marwyn. then go back to the door - if (Creature* pFalric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - pFalric->SetVisible(true); - if (Creature* pMarwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) - pMarwyn->SetVisible(true); - + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + { + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); + } + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MARWYN_EVENT))) + { + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); + } if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) { - lichking->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); lichking->AI()->Talk(SAY_LK_INTRO_3); + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + lichking->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); } - - events.ScheduleEvent(EVENT_INTRO_LK_6, 8000); - break; - - case EVENT_INTRO_LK_6: - if (Creature* falric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - falric->AI()->Talk(SAY_FALRIC_INTRO_1); - - events.ScheduleEvent(EVENT_INTRO_LK_7, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_7, 10000); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 5000); break; - case EVENT_INTRO_LK_7: - if (Creature* marwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MARWYN_EVENT))) marwyn->AI()->Talk(SAY_MARWYN_INTRO_1); - - events.ScheduleEvent(EVENT_INTRO_LK_8, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_8, 1000); break; - case EVENT_INTRO_LK_8: - if (Creature* falric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - falric->AI()->Talk(SAY_FALRIC_INTRO_2); - + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + falric->AI()->Talk(SAY_FALRIC_INTRO_1); events.ScheduleEvent(EVENT_INTRO_LK_9, 5000); break; - case EVENT_INTRO_LK_9: + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + falric->AI()->Talk(SAY_FALRIC_INTRO_2); + events.ScheduleEvent(EVENT_INTRO_LK_10, 7000); + break; + case EVENT_INTRO_LK_10: if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) Talk(SAY_JAINA_INTRO_END); else Talk(SAY_SYLVANAS_INTRO_END); - - me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); + me->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); /// @todo Loralen/Koreln shall run also - events.ScheduleEvent(EVENT_INTRO_END, 10000); + events.ScheduleEvent(EVENT_INTRO_LK_11, 5000); + break; + case EVENT_INTRO_LK_11: + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + lichking->AI()->Talk(SAY_LK_JAINA_INTRO_END); + else + lichking->AI()->Talk(SAY_LK_SYLVANAS_INTRO_END); + } + events.ScheduleEvent(EVENT_INTRO_END, 5000); break; - case EVENT_INTRO_END: if (instance) - instance->SetData(DATA_WAVE_COUNT, SPECIAL); // start first wave - + { + instance->SetData(DATA_INTRO_EVENT, DONE); + instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + //instance->SetData(DATA_WAVE_COUNT, SPECIAL); // start first wave + } // Loralen or Koreln disappearAndDie() - me->DisappearAndDie(); + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + lichking->DespawnOrUnsummon(5000); + lichkingGUID = 0; + } + me->DespawnOrUnsummon(10000); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 7000); break; - case EVENT_SKIP_INTRO: - /// @todo implement - - if (Creature* pFalric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - pFalric->SetVisible(true); - if (Creature* pMarwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) - pMarwyn->SetVisible(true); - - me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); + me->GetMotionMaster()->MovePoint(0, MoveThronePos); /// @todo Loralen/Koreln shall run also - - events.ScheduleEvent(EVENT_INTRO_END, 15000); + if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + { + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); + lichking->SetReactState(REACT_PASSIVE); + lichkingGUID = lichking->GetGUID(); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); + } + events.ScheduleEvent(EVENT_INTRO_LK_4, 15000); + break; + case EVENT_OPEN_FROSTWORN_DOOR: + if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTWORN_DOOR))) + instance->HandleGameObject(0 ,true, gate); + break; + case EVENT_CLOSE_FROSTWORN_DOOR: + if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTWORN_DOOR))) + instance->HandleGameObject(0 ,false, gate); break; } } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_jaina_or_sylvanas_horAI(creature); + } }; enum TrashSpells @@ -640,13 +665,19 @@ public: { npc_ghostly_priestAI(Creature* creature) : ScriptedAI(creature) { + instance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); } + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) @@ -667,39 +698,36 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SHADOW_WORD_PAIN: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHADOW_WORD_PAIN); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); - return; - case EVENT_CIRCLE_OF_DESTRUCTION: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); - events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); - return; - case EVENT_COWER_IN_FEAR: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_COWER_IN_FEAR); - events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); - return; - case EVENT_DARK_MENDING: - // find an ally with missing HP - if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) - { - DoCast(target, 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; - } + case EVENT_SHADOW_WORD_PAIN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_SHADOW_WORD_PAIN); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); + break; + case EVENT_CIRCLE_OF_DESTRUCTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); + events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); + break; + case EVENT_COWER_IN_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_COWER_IN_FEAR); + events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); + break; + case EVENT_DARK_MENDING: + // find an ally with missing HP + if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) + { + DoCast(target, 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); + } + break; } DoMeleeAttackIfReady(); @@ -722,13 +750,19 @@ public: { npc_phantom_mageAI(Creature* creature) : ScriptedAI(creature) { + instance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); } + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) @@ -750,33 +784,30 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, 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* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FROSTBOLT); - events.ScheduleEvent(EVENT_FROSTBOLT, 15000); - return; - case EVENT_CHAINS_OF_ICE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CHAINS_OF_ICE); - events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); - return; - case EVENT_HALLUCINATION: - DoCast(SPELL_HALLUCINATION); - return; - } + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 15000); + break; + case EVENT_FLAMESTRIKE: + DoCast(SPELL_FLAMESTRIKE); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000); + break; + case EVENT_FROSTBOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FROSTBOLT); + events.ScheduleEvent(EVENT_FROSTBOLT, 15000); + break; + case EVENT_CHAINS_OF_ICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CHAINS_OF_ICE); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); + break; + case EVENT_HALLUCINATION: + DoCast(SPELL_HALLUCINATION); + break; } DoMeleeAttackIfReady(); @@ -797,9 +828,7 @@ public: struct npc_phantom_hallucinationAI : public npc_phantom_mage::npc_phantom_mageAI { - npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) - { - } + npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) {} void JustDied(Unit* /*killer*/) { @@ -823,13 +852,19 @@ public: { npc_shadowy_mercenaryAI(Creature* creature) : ScriptedAI(creature) { + instance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); } + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) @@ -850,28 +885,25 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (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* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, 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; - } + case EVENT_SHADOW_STEP: + DoCast(SPELL_SHADOW_STEP); + events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); + break; + case EVENT_DEADLY_POISON: + DoCast(me->getVictim(), SPELL_DEADLY_POISON); + events.ScheduleEvent(EVENT_DEADLY_POISON, 10000); + break; + case EVENT_ENVENOMED_DAGGER_THROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); + events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); + break; + case EVENT_KIDNEY_SHOT: + DoCast(me->getVictim(), SPELL_KIDNEY_SHOT); + events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000); + break; } DoMeleeAttackIfReady(); @@ -894,13 +926,19 @@ public: { npc_spectral_footmanAI(Creature* creature) : ScriptedAI(creature) { + instance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); } + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) @@ -920,23 +958,20 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (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; - } + case EVENT_SPECTRAL_STRIKE: + DoCast(me->getVictim(), SPELL_SPECTRAL_STRIKE); + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); + break; + case EVENT_SHIELD_BASH: + DoCast(me->getVictim(), SPELL_SHIELD_BASH); + events.ScheduleEvent(EVENT_SHIELD_BASH, 5000); + break; + case EVENT_TORTURED_ENRAGE: + DoCast(SPELL_TORTURED_ENRAGE); + events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + break; } DoMeleeAttackIfReady(); @@ -959,13 +994,19 @@ public: { npc_tortured_riflemanAI(Creature* creature) : ScriptedAI(creature) { + instance = me->GetInstanceScript(); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); } + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) @@ -986,46 +1027,273 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SHOOT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHOOT); - events.ScheduleEvent(EVENT_SHOOT, 2000); - return; - case EVENT_CURSED_ARROW: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, 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* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_ICE_SHOT); - events.ScheduleEvent(EVENT_ICE_SHOT, 15000); - return; - } + case EVENT_SHOOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_SHOOT); + events.ScheduleEvent(EVENT_SHOOT, 2000); + break; + case EVENT_CURSED_ARROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CURSED_ARROW); + events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); + break; + case EVENT_FROST_TRAP: + DoCast(SPELL_FROST_TRAP); + events.ScheduleEvent(EVENT_FROST_TRAP, 30000); + break; + case EVENT_ICE_SHOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_ICE_SHOT); + events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + break; + } + + DoMeleeAttackIfReady(); + } + }; + +}; + + +enum GeneralEvents +{ + //General + EVENT_SHIELD = 0, + EVENT_SPIKE = 1, + EVENT_CLONE = 2, + + SAY_AGGRO = 0, + SAY_DEATH = 1, + + SPELL_SHIELD_THROWN = 69222, // 73076 on hc + SPELL_SPIKE = 69184, // 70399 on hc + SPELL_CLONE_NAME = 57507, + SPELL_CLONE_MODEL = 45204, + + // Reflection + EVENT_BALEFUL_STRIKE = 0, + + SPELL_BALEFUL_STRIKE = 69933, // 70400 on hc + SPELL_SPIRIT_BURST = 69900, // 73046 on hc +}; + +class npc_frostworn_general : public CreatureScript +{ +public: + npc_frostworn_general() : CreatureScript("npc_frostworn_general") { } + + struct npc_frostworn_generalAI : public ScriptedAI + { + npc_frostworn_generalAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + Reset(); + } + + InstanceScript* instance; + + EventMap events; + + void Reset() + { + events.Reset(); + instance->SetData(DATA_FROSWORN_EVENT, NOT_STARTED); + } + + void JustDied(Unit* /*killer*/) + { + Talk(SAY_DEATH); + instance->SetData(DATA_FROSWORN_EVENT, DONE); + } + + void EnterCombat(Unit* /*victim*/) + { + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_SHIELD, 5000); + events.ScheduleEvent(EVENT_SPIKE, 14000); + events.ScheduleEvent(EVENT_CLONE, 22000); + instance->SetData(DATA_FROSWORN_EVENT, IN_PROGRESS); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SHIELD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SHIELD_THROWN); + events.ScheduleEvent(EVENT_SHIELD, urand(8000, 12000)); + break; + case EVENT_SPIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SPIKE); + events.ScheduleEvent(EVENT_SPIKE, urand(15000, 20000)); + break; + case EVENT_CLONE: + SummonClones(); + events.ScheduleEvent(EVENT_CLONE, 60000); + break; } DoMeleeAttackIfReady(); } + + void SummonClones() + { + std::list<Unit *> playerList; + SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0, true); + for (std::list<Unit*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) + { + Unit* temp = (*itr); + Creature* reflection = me->SummonCreature(NPC_REFLECTION, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), temp->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); + reflection->SetName(temp->GetName()); + temp->CastSpell(reflection, SPELL_CLONE_NAME, true); + temp->CastSpell(reflection, SPELL_CLONE_MODEL, true); + reflection->setFaction(me->getFaction()); + reflection->AI()->AttackStart(temp); + } + + } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_frostworn_generalAI(creature); + } +}; + +class npc_spiritual_reflection : public CreatureScript +{ +public: + npc_spiritual_reflection() : CreatureScript("npc_spiritual_reflection") { } + + struct npc_spiritual_reflectionAI : public ScriptedAI + { + npc_spiritual_reflectionAI(Creature *creature) : ScriptedAI(creature) + { + Reset(); + } + + EventMap events; + + void Reset() + { + events.Reset(); + } + + void EnterCombat(Unit* /*victim*/) + { + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 3000); + } + + void JustDied(Unit* killer) + { + DoCast(killer, SPELL_SPIRIT_BURST); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_BALEFUL_STRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_BALEFUL_STRIKE); + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, urand(3000, 8000)); + } + + DoMeleeAttackIfReady(); + } + }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_spiritual_reflectionAI(creature); + } +}; + +class at_hor_intro_start : public AreaTriggerScript +{ + public: + at_hor_intro_start() : AreaTriggerScript("at_hor_intro_start") {} + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) + { + InstanceScript* instance = player->GetInstanceScript(); + + if (player->isGameMaster()) + return true; + + if (instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED) + { + instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS); + } + + return true; + } +}; + +class at_hor_waves_restarter : public AreaTriggerScript +{ + public: + at_hor_waves_restarter() : AreaTriggerScript("at_hor_waves_restarter") {} + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) + { + InstanceScript* instance = player->GetInstanceScript(); + + if (player->isGameMaster()) + return true; + + if (instance->GetData(DATA_WAVE_COUNT)) + return true; + + if (instance->GetData(DATA_INTRO_EVENT) == DONE && instance->GetBossState(DATA_MARWYN_EVENT) != DONE && instance->GetData(DATA_WAVE_COUNT) == NOT_STARTED) + { + instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + //instance->SetData(DATA_WAVE_COUNT, SPECIAL); + + if (Creature* falric = player->GetCreature(*player, instance->GetData64(DATA_FALRIC_EVENT))) + { + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); + } + if (Creature* marwyn = player->GetCreature(*player, instance->GetData64(DATA_MARWYN_EVENT))) + { + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); + } + } + return true; + } }; void AddSC_halls_of_reflection() { - new npc_jaina_or_sylvanas_hor(true, "npc_sylvanas_hor_part1"); - new npc_jaina_or_sylvanas_hor(false, "npc_jaina_hor_part1"); + new npc_jaina_or_sylvanas_hor(); new npc_ghostly_priest(); new npc_phantom_mage(); new npc_phantom_hallucination(); new npc_shadowy_mercenary(); new npc_spectral_footman(); new npc_tortured_rifleman(); + new at_hor_intro_start(); + new at_hor_waves_restarter(); + new npc_frostworn_general(); + new npc_spiritual_reflection(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h index 2cab1cca214..958ecc24aa1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -18,49 +18,78 @@ #ifndef DEF_HALLS_OF_REFLECTION_H #define DEF_HALLS_OF_REFLECTION_H -enum Data -{ - DATA_FALRIC_EVENT, - DATA_MARWYN_EVENT, - DATA_LICHKING_EVENT, - DATA_WAVE_COUNT, - DATA_TEAM_IN_INSTANCE, -}; +#define HoRScriptName "instance_halls_of_reflection" +#define MAX_ENCOUNTER 3 -enum Data64 +/* Halls of Reflection encounters: +0- Falric +1- Marwyn +2- The Lich King +*/ + +enum Data { - DATA_FALRIC, - DATA_MARWYN, - DATA_LICHKING, - DATA_FROSTMOURNE, + DATA_FALRIC_EVENT = 0, + DATA_MARWYN_EVENT = 1, + DATA_LICHKING_EVENT = 2, + DATA_INTRO_EVENT = 3, + DATA_FROSWORN_EVENT = 4, + + DATA_WAVE_COUNT = 5, + DATA_TEAM_IN_INSTANCE = 6, + DATA_FROSTMOURNE = 7, + DATA_FROSTWORN_DOOR = 8, }; enum Creatures { - 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_UTHER = 37225, + NPC_LICH_KING_PART1 = 37226, + NPC_LORALEN = 37779, + NPC_KORELN = 37582, + NPC_FALRIC = 38112, + NPC_MARWYN = 38113, NPC_WAVE_MERCENARY = 38177, NPC_WAVE_FOOTMAN = 38173, NPC_WAVE_RIFLEMAN = 38176, NPC_WAVE_PRIEST = 38175, NPC_WAVE_MAGE = 38172, + + NPC_FROSTWORN_GENERAL = 36723, + NPC_REFLECTION = 37068, // 37107 for tank only? + + NPC_JAINA_PART2 = 36955, + NPC_SYLVANAS_PART2 = 37554, + NPC_LICH_KING_PART2 = 36954, + NPC_BARTLETT = 37182, // High Captain Justin Bartlett + NPC_KORM = 37833, // Sky-Reaver Korm Blackscar + NPC_ICE_WALL = 37014, // Ice Wall Target }; enum GameObjects { GO_FROSTMOURNE = 202302, - GO_FROSTMOURNE_ALTAR = 202236, - GO_FRONT_DOOR = 201976, - GO_ARTHAS_DOOR = 197341, + GO_ENTRANCE_DOOR = 201976, + GO_FROSTWORN_DOOR = 197341, + GO_ARTHAS_DOOR = 197342, + //GO_ESCAPE_DOOR = 197343, // always open ? + + GO_ICE_WALL = 201385, + GO_CAVE = 201596, + + GO_STAIRS_SKYBREAKER = 201709, + GO_SKYBREAKER = 201598, + GO_STAIRS_ORGRIM_HAMMER = 202211, + GO_ORGRIM_HAMMER = 201599, + GO_PORTAL = 202079, + + GO_CAPTAIN_CHEST_1 = 202212, //3145 + GO_CAPTAIN_CHEST_2 = 201710, //30357 + GO_CAPTAIN_CHEST_3 = 202337, //3246 + GO_CAPTAIN_CHEST_4 = 202336, //3333 }; enum HorWorldStates @@ -75,6 +104,21 @@ enum Actions ACTION_ENTER_COMBAT, }; +enum TrashGeneralSpells +{ + // General spells + SPELL_WELL_OF_SOULS = 72630, // cast when spawn(become visible) + SPELL_SPIRIT_ACTIVATE = 72130, // cast when unit activates +}; + +enum InstanceEvents +{ + EVENT_SPAWN_WAVES = 1, + EVENT_NEXT_WAVE = 2, + EVENT_DO_WIPE = 3, + EVENT_ADD_WAVE = 4, +}; + // Base class for FALRIC and MARWYN // handled the summonList and the notification events to/from the InstanceScript struct boss_horAI : ScriptedAI @@ -92,14 +136,10 @@ struct boss_horAI : ScriptedAI { events.Reset(); me->SetVisible(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_PASSIVE); - } - - void DamageTaken(Unit* /*who*/, uint32 &uiDamage) - { - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - uiDamage = 0; + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->ProcessEvent(0, EVENT_DO_WIPE); } void DoAction(int32 actionID) @@ -107,11 +147,7 @@ struct boss_horAI : ScriptedAI switch (actionID) { case ACTION_ENTER_COMBAT: // called by InstanceScript when boss shall enter in combat. - // Just in case. Should have been done by InstanceScript - me->SetVisible(true); - - // Reset flags - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_AGGRESSIVE); if (Unit* unit = me->SelectNearestTarget()) @@ -125,32 +161,6 @@ struct boss_horAI : ScriptedAI void JustSummoned(Creature* summoned) { summons.Summon(summoned); - - if (Unit* target = summoned->SelectNearestTarget()) - { - if (summoned->AI()) - summoned->AI()->AttackStart(target); - else - { - summoned->GetMotionMaster()->MoveChase(target); - summoned->Attack(target, true); - } - } - - if (summoned->AI()) - summoned->AI()->DoZoneInCombat(); - } - - void SummonedCreatureDespawn(Creature* summoned) - { - summons.Despawn(summoned); - if (summons.empty()) - { - if (summoned->isAlive()) - instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); - else - instance->SetData(DATA_WAVE_COUNT, SPECIAL); - } } }; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index dde3f7acc67..82d270fdb95 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -19,84 +19,47 @@ #include "ScriptedCreature.h" #include "InstanceScript.h" #include "halls_of_reflection.h" -#include "Player.h" -#define MAX_ENCOUNTER 3 +const Position JainaSpawnPos = {5236.659f, 1929.894f, 707.7781f, 0.8726646f}; // Jaina Spawn Position +const Position SylvanasSpawnPos = {5236.667f, 1929.906f, 707.7781f, 0.8377581f}; // Sylvanas Spawn Position +const Position GeneralSpawnPos = {5415.538f, 2117.842f, 707.7781f, 3.944444f}; // Frostsworn General -/* Halls of Reflection encounters: -0- Falric -1- Marwyn -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 +static Position SpawnPos[] = { - EVENT_NONE, - EVENT_NEXT_WAVE, - EVENT_START_LICH_KING, -}; - -static Position PriestSpawnPos[ENCOUNTER_WAVE_PRIEST] = -{ - {5277.74f, 2016.88f, 707.778f, 5.96903f}, - {5295.88f, 2040.34f, 707.778f, 5.07891f}, - {5320.37f, 1980.13f, 707.778f, 2.00713f}, - {5280.51f, 1997.84f, 707.778f, 0.296706f}, - {5302.45f, 2042.22f, 707.778f, 4.90438f}, - {5306.57f, 1977.47f, 707.778f, 1.50098f}, -}; - -static Position MageSpawnPos[ENCOUNTER_WAVE_MAGE] = -{ - {5312.75f, 2037.12f, 707.778f, 4.59022f}, - {5309.58f, 2042.67f, 707.778f, 4.69494f}, - {5275.08f, 2008.72f, 707.778f, 6.21337f}, - {5279.65f, 2004.66f, 707.778f, 0.069813f}, - {5275.48f, 2001.14f, 707.778f, 0.174533f}, - {5316.7f, 2041.55f, 707.778f, 4.50295f}, -}; - -static Position MercenarySpawnPos[ENCOUNTER_WAVE_MERCENARY] = -{ - {5302.25f, 1972.41f, 707.778f, 1.37881f}, - {5311.03f, 1972.23f, 707.778f, 1.64061f}, - {5277.36f, 1993.23f, 707.778f, 0.401426f}, - {5318.7f, 2036.11f, 707.778f, 4.2237f}, - {5335.72f, 1996.86f, 707.778f, 2.74017f}, - {5299.43f, 1979.01f, 707.778f, 1.23918f}, -}; - -static Position FootmenSpawnPos[ENCOUNTER_WAVE_FOOTMAN] = -{ - {5306.06f, 2037, 707.778f, 4.81711f}, - {5344.15f, 2007.17f, 707.778f, 3.15905f}, - {5337.83f, 2010.06f, 707.778f, 3.22886f}, - {5343.29f, 1999.38f, 707.778f, 2.9147f}, - {5340.84f, 1992.46f, 707.778f, 2.75762f}, - {5325.07f, 1977.6f, 707.778f, 2.07694f}, - {5336.6f, 2017.28f, 707.778f, 3.47321f}, - {5313.82f, 1978.15f, 707.778f, 1.74533f}, - {5280.63f, 2012.16f, 707.778f, 6.05629f}, - {5322.96f, 2040.29f, 707.778f, 4.34587f}, -}; - -static Position RiflemanSpawnPos[ENCOUNTER_WAVE_RIFLEMAN] = -{ - {5343.47f, 2015.95f, 707.778f, 3.49066f}, - {5337.86f, 2003.4f, 707.778f, 2.98451f}, - {5319.16f, 1974, 707.778f, 1.91986f}, - {5299.25f, 2036, 707.778f, 5.02655f}, - {5295.64f, 1973.76f, 707.778f, 1.18682f}, - {5282.9f, 2019.6f, 707.778f, 5.88176f}, + {5309.577f, 2042.668f, 707.7781f, 4.694936f}, + {5295.885f, 2040.342f, 707.7781f, 5.078908f}, + {5340.836f, 1992.458f, 707.7781f, 2.757620f}, + {5325.072f, 1977.597f, 707.7781f, 2.076942f}, + {5277.365f, 1993.229f, 707.7781f, 0.401426f}, + {5275.479f, 2001.135f, 707.7781f, 0.174533f}, + {5302.448f, 2042.222f, 707.7781f, 4.904375f}, + {5343.293f, 1999.384f, 707.7781f, 2.914700f}, + {5295.635f, 1973.757f, 707.7781f, 1.186824f}, + {5311.031f, 1972.229f, 707.7781f, 1.640610f}, + {5275.076f, 2008.724f, 707.7781f, 6.213372f}, + {5316.701f, 2041.550f, 707.7781f, 4.502949f}, + {5344.150f, 2007.168f, 707.7781f, 3.159046f}, + {5319.158f, 1973.998f, 707.7781f, 1.919862f}, + {5302.247f, 1972.415f, 707.7781f, 1.378810f}, + {5277.739f, 2016.882f, 707.7781f, 5.969026f}, + {5322.964f, 2040.288f, 707.7781f, 4.345870f}, + {5343.467f, 2015.951f, 707.7781f, 3.490659f}, + {5313.820f, 1978.146f, 707.7781f, 1.745329f}, + {5279.649f, 2004.656f, 707.7781f, 0.069814f}, + {5306.057f, 2037.002f, 707.7781f, 4.817109f}, + {5337.865f, 2003.403f, 707.7781f, 2.984513f}, + {5299.434f, 1979.009f, 707.7781f, 1.239184f}, + {5312.752f, 2037.122f, 707.7781f, 4.590216f}, + {5335.724f, 1996.859f, 707.7781f, 2.740167f}, + {5280.632f, 2012.156f, 707.7781f, 6.056293f}, + {5320.369f, 1980.125f, 707.7781f, 2.007129f}, + {5306.572f, 1977.474f, 707.7781f, 1.500983f}, + {5336.599f, 2017.278f, 707.7781f, 3.473205f}, + {5282.897f, 2019.597f, 707.7781f, 5.881760f}, + {5318.704f, 2036.108f, 707.7781f, 4.223697f}, + {5280.513f, 1997.842f, 707.7781f, 0.296706f}, + {5337.833f, 2010.057f, 707.7781f, 3.228859f}, + {5299.250f, 2035.998f, 707.7781f, 5.026548f}, }; class instance_halls_of_reflection : public InstanceMapScript @@ -104,53 +67,37 @@ class instance_halls_of_reflection : public InstanceMapScript public: instance_halls_of_reflection() : InstanceMapScript("instance_halls_of_reflection", 668) { } - InstanceScript* GetInstanceScript(InstanceMap* map) const - { - return new instance_halls_of_reflection_InstanceMapScript(map); - } - struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript { - instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) {}; - - uint64 uiFalric; - uint64 uiMarwyn; - uint64 uiLichKingEvent; - uint64 uiJainaPart1; - uint64 uiSylvanasPart1; - - uint64 uiFrostmourne; - uint64 uiFrostmourneAltar; - uint64 uiArthasDoor; - uint64 uiFrontDoor; - - uint32 uiEncounter[MAX_ENCOUNTER]; - uint32 uiTeamInInstance; - uint32 uiWaveCount; - bool bIntroDone; - - EventMap events; + instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) {} void Initialize() { + SetBossNumber(MAX_ENCOUNTER); events.Reset(); + _falricGUID = 0; + _marwynGUID = 0; + _jainaOrSylvanasPart1GUID = 0; + _frostwornGeneralGUID = 0; + _frostmourneGUID = 0; + _entranceDoorGUID = 0; + _frostwornDoorGUID = 0; + _arthasDoorGUID = 0; + _teamInInstance = 0; + _waveCount = 0; + _introEvent = NOT_STARTED; + _frostwornGeneral = NOT_STARTED; + + for (uint8 i = 0; i < 8; i++) + { + waveGuidList[i].clear(); + } + } - uiFalric = 0; - uiMarwyn = 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) - uiEncounter[i] = NOT_STARTED; + void OnPlayerEnter(Player* player) + { + if (!_teamInInstance) + _teamInInstance = player->GetTeam(); } void OnCreatureCreate(Creature* creature) @@ -158,53 +105,57 @@ public: Map::PlayerList const &players = instance->GetPlayers(); if (!players.isEmpty()) if (Player* player = players.begin()->getSource()) - uiTeamInInstance = player->GetTeam(); + _teamInInstance = player->GetTeam(); switch (creature->GetEntry()) { + case NPC_JAINA_PART1: + case NPC_SYLVANAS_PART1: + _jainaOrSylvanasPart1GUID = creature->GetGUID(); + break; case NPC_FALRIC: - uiFalric = creature->GetGUID(); + _falricGUID = creature->GetGUID(); break; case NPC_MARWYN: - uiMarwyn = creature->GetGUID(); + _marwynGUID = creature->GetGUID(); break; - case NPC_LICH_KING_EVENT: - uiLichKingEvent = creature->GetGUID(); - break; - case NPC_JAINA_PART1: - uiJainaPart1 = creature->GetGUID(); - break; - case NPC_SYLVANAS_PART1: - uiSylvanasPart1 = creature->GetGUID(); + case NPC_FROSTWORN_GENERAL: + _frostwornGeneralGUID = creature->GetGUID(); + if (GetBossState(DATA_MARWYN_EVENT) == DONE) + if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) + general->SetPhaseMask(1, true); break; } } void OnGameObjectCreate(GameObject* go) { - /// @todo init state depending on encounters switch (go->GetEntry()) { case GO_FROSTMOURNE: - uiFrostmourne = go->GetGUID(); + _frostmourneGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); HandleGameObject(0, false, go); + if (GetData(DATA_INTRO_EVENT) == DONE) + go->SetPhaseMask(2, true); break; - case GO_FROSTMOURNE_ALTAR: - uiFrostmourneAltar = go->GetGUID(); + case GO_ENTRANCE_DOOR: + _entranceDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); HandleGameObject(0, true, go); break; - case GO_FRONT_DOOR: - uiFrontDoor = go->GetGUID(); + case GO_FROSTWORN_DOOR: + _frostwornDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - HandleGameObject(0, true, go); + if (GetBossState(DATA_MARWYN_EVENT) == DONE) + HandleGameObject(0, true, go); + else + HandleGameObject(0, false, go); break; case GO_ARTHAS_DOOR: - uiArthasDoor = go->GetGUID(); + _arthasDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - - if (uiEncounter[1] == DONE) + if (GetBossState(DATA_FROSWORN_EVENT) == DONE) HandleGameObject(0, true, go); else HandleGameObject(0, false, go); @@ -212,61 +163,108 @@ public: } } - void SetData(uint32 type, uint32 data) + bool SetBossState(uint32 type, EncounterState state) { - if (type == DATA_WAVE_COUNT && data == SPECIAL) - { - bIntroDone = true; - events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); - return; - } - - if (uiWaveCount && data == NOT_STARTED) - DoWipe(); + if (!InstanceScript::SetBossState(type, state)) + return false; switch (type) { case DATA_FALRIC_EVENT: - uiEncounter[0] = data; - if (data == DONE) + if (state == DONE) events.ScheduleEvent(EVENT_NEXT_WAVE, 60000); break; case DATA_MARWYN_EVENT: - uiEncounter[1] = data; - if (data == DONE) - HandleGameObject(uiArthasDoor, true); + if (state == DONE) + { + HandleGameObject(_entranceDoorGUID, true); + HandleGameObject(_frostwornDoorGUID, true); + if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) + general->SetPhaseMask(1, true); + } break; case DATA_LICHKING_EVENT: - uiEncounter[2] = data; + break; + default: + break; + } + + return true; + } + + void SetData(uint32 type, uint32 data) + { + if (_waveCount && data == NOT_STARTED) + ProcessEvent(0, EVENT_DO_WIPE); + + switch (type) + { + case DATA_INTRO_EVENT: + if (data == IN_PROGRESS) + { + if (!_introEvent) + { + if (_teamInInstance == ALLIANCE) + instance->SummonCreature(NPC_JAINA_PART1, JainaSpawnPos); + else + instance->SummonCreature(NPC_SYLVANAS_PART1, SylvanasSpawnPos); + } + } + _introEvent = data; + break; + case DATA_WAVE_COUNT: + if (data == SPECIAL) + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + break; + case DATA_FROSWORN_EVENT: + if (data == DONE) + { + HandleGameObject(_arthasDoorGUID, true); + // spawn Jaina part 2 + // spawn LK part 2 + } + _frostwornGeneral = data; break; } - if (data == DONE) - SaveToDB(); + SaveToDB(); } uint32 GetData(uint32 type) const { switch (type) { - 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; + case DATA_WAVE_COUNT: + return _waveCount; + case DATA_TEAM_IN_INSTANCE: + return _teamInInstance; + case DATA_INTRO_EVENT: + return _introEvent; + case DATA_FROSWORN_EVENT: + return _frostwornGeneral; + default: + break; } return 0; } - uint64 GetData64(uint32 identifier) const + uint64 GetData64(uint32 type) const { - switch (identifier) + switch (type) { - case DATA_FALRIC: return uiFalric; - case DATA_MARWYN: return uiMarwyn; - case DATA_LICHKING: return uiLichKingEvent; - case DATA_FROSTMOURNE: return uiFrostmourne; + case DATA_FALRIC_EVENT: + return _falricGUID; + case DATA_MARWYN_EVENT: + return _marwynGUID; + case DATA_FROSWORN_EVENT: + return _frostwornGeneralGUID; + case DATA_FROSTWORN_DOOR: + return _frostwornDoorGUID; + case DATA_FROSTMOURNE: + return _frostmourneGUID; + default: + break; } return 0; @@ -277,7 +275,7 @@ public: OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << "H R 1 " << uiEncounter[0] << ' ' << uiEncounter[1] << ' ' << uiEncounter[2]; + saveStream << "H R " << GetBossSaveData() << _introEvent << ' ' << _frostwornGeneral; OUT_SAVE_INST_DATA_COMPLETE; return saveStream.str(); @@ -294,115 +292,82 @@ public: OUT_LOAD_INST_DATA(in); char dataHead1, dataHead2; - uint16 version; - uint16 data0, data1, data2; std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2 >> version >> data0 >> data1 >> data2; + loadStream >> dataHead1 >> dataHead2; if (dataHead1 == 'H' && dataHead2 == 'R') { - uiEncounter[0] = data0; - uiEncounter[1] = data1; - uiEncounter[2] = data2; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (uiEncounter[i] == IN_PROGRESS) - uiEncounter[i] = NOT_STARTED; - - } else OUT_LOAD_INST_DATA_FAIL; - - if (uiEncounter[0] == DONE || uiEncounter[1] == DONE) - bIntroDone = true; + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + + SetBossState(i, EncounterState(tmpState)); + } + + uint32 temp = 0; + loadStream >> temp; + if (temp == DONE) + SetData(DATA_INTRO_EVENT, DONE); + else + SetData(DATA_INTRO_EVENT, NOT_STARTED); + + loadStream >> temp; + if (temp == DONE) + SetData(DATA_FROSWORN_EVENT, DONE); + else + SetData(DATA_FROSWORN_EVENT, NOT_STARTED); + } + else + OUT_LOAD_INST_DATA_FAIL; OUT_LOAD_INST_DATA_COMPLETE; } - void AddWave() + // wave scheduling,checked when wave npcs die + void OnUnitDeath(Unit* unit) { - DoUpdateWorldState(WORLD_STATE_HOR, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount); + Creature* creature = unit->ToCreature(); + if (!creature) + return; - switch (uiWaveCount) + switch (creature->GetEntry()) { - 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); + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: + uint32 deadNpcs = 0; + if (_waveCount < 5) + { + for (std::set<uint64>::const_iterator itr = waveGuidList[_waveCount-1].begin(); itr != waveGuidList[_waveCount-1].end(); ++itr) + if ((instance->GetCreature(*itr)->isDying()) || (instance->GetCreature(*itr)->isDead())) + deadNpcs++; + + // because the current npc returns isAlive when OnUnitDeath happens + // we check if the number of dead npcs is equal to the list-1 + if (deadNpcs == waveGuidList[_waveCount-1].size() - 1) + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + } + else + { + for (std::set<uint64>::const_iterator itr = waveGuidList[_waveCount-2].begin(); itr != waveGuidList[_waveCount-2].end(); ++itr) + if ((instance->GetCreature(*itr)->isDying()) || (instance->GetCreature(*itr)->isDead())) + deadNpcs++; + + // because the current npc returns isAlive when OnUnitDeath happens + // we check if the number of dead npcs is equal to the list-1 + if (deadNpcs == waveGuidList[_waveCount-2].size() - 1) + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + } 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->SetVisible(false); - if (Creature* pMarwyn = instance->GetCreature(uiMarwyn)) - pMarwyn->SetVisible(false); - } - - // spawn a wave on behalf of the summoner. - void SpawnWave(Creature* summoner) - { - uint32 index; - - summoner->SetVisible(true); - - /// @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); - summoner->SummonCreature(NPC_WAVE_MERCENARY, MercenarySpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_FOOTMAN-1); - summoner->SummonCreature(NPC_WAVE_FOOTMAN, FootmenSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_RIFLEMAN-1); - summoner->SummonCreature(NPC_WAVE_RIFLEMAN, RiflemanSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_PRIEST-1); - summoner->SummonCreature(NPC_WAVE_PRIEST, PriestSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_MAGE-1); - summoner->SummonCreature(NPC_WAVE_MAGE, MageSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - } - void Update(uint32 diff) { if (!instance->HavePlayers()) @@ -413,16 +378,158 @@ public: switch (events.ExecuteEvent()) { case EVENT_NEXT_WAVE: - uiWaveCount++; - AddWave(); + _waveCount++; + ProcessEvent(0, EVENT_ADD_WAVE); + break; + } + } + + void ProcessEvent(WorldObject* /*go*/, uint32 eventId) + { + switch (eventId) + { + // spawning all wave npcs at once + case EVENT_SPAWN_WAVES: + DoUpdateWorldState(WORLD_STATE_HOR, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + { + std::vector<uint32> possibilityList,tempList; + uint32 posIndex = 0; + + possibilityList.push_back(NPC_WAVE_MERCENARY); + possibilityList.push_back(NPC_WAVE_FOOTMAN); + possibilityList.push_back(NPC_WAVE_RIFLEMAN); + possibilityList.push_back(NPC_WAVE_PRIEST); + possibilityList.push_back(NPC_WAVE_MAGE); + + // iterate each wave + for (uint8 i = 0; i < 8; i++) + { + tempList = possibilityList; + + uint64 guid = i <= 3 ? _falricGUID : _marwynGUID; + + if (i == 0) + { + tempList.erase(tempList.begin() + urand(0, tempList.size() - 1)); + tempList.erase(tempList.begin() + urand(0, tempList.size() - 1)); + } + else if (i == 1 || i == 2 || i == 4 || i == 5) + tempList.erase(tempList.begin() + urand(0, tempList.size() - 1)); + + for (uint8 itr = 0; itr < tempList.size(); ++itr) + { + if (Creature* falric = instance->GetCreature(guid)) + if (Creature* temp = falric->SummonCreature(tempList[itr], SpawnPos[posIndex], TEMPSUMMON_DEAD_DESPAWN)) + waveGuidList[i].insert(temp->GetGUID()); + posIndex++; + } + + tempList.clear(); + } + } + SetData(DATA_WAVE_COUNT, SPECIAL); + break; + case EVENT_ADD_WAVE: + DoUpdateWorldState(WORLD_STATE_HOR, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(_entranceDoorGUID, false); + + switch (_waveCount) + { + case 1: + case 2: + case 3: + case 4: + for (std::set<uint64>::const_iterator itr = waveGuidList[_waveCount-1].begin(); itr != waveGuidList[_waveCount-1].end(); ++itr) + { + if (Creature* temp = instance->GetCreature(*itr)) + { + temp->CastSpell(temp, SPELL_SPIRIT_ACTIVATE, true); + temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC|UNIT_FLAG_NOT_SELECTABLE); + temp->AI()->DoZoneInCombat(); + } + } + break; + case 5: + if (GetBossState(DATA_FALRIC_EVENT) == DONE) + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + else + if (Creature* falric = instance->GetCreature(_falricGUID)) + if (falric->AI()) + falric->AI()->DoAction(ACTION_ENTER_COMBAT); + break; + case 6: + case 7: + case 8: + case 9: + for (std::set<uint64>::const_iterator itr = waveGuidList[_waveCount-2].begin(); itr != waveGuidList[_waveCount-2].end(); ++itr) + { + if (Creature* temp = instance->GetCreature(*itr)) + { + temp->CastSpell(temp, SPELL_SPIRIT_ACTIVATE, true); + temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC|UNIT_FLAG_NOT_SELECTABLE); + temp->AI()->DoZoneInCombat(); + } + } + break; + case 10: + if (GetBossState(DATA_MARWYN_EVENT) != DONE) // wave should not have been started if DONE. Check anyway to avoid bug exploit! + if (Creature* marwyn = instance->GetCreature(_marwynGUID)) + if (marwyn->AI()) + marwyn->AI()->DoAction(ACTION_ENTER_COMBAT); + break; + } break; - case EVENT_START_LICH_KING: - /// @todo + case EVENT_DO_WIPE: + //SetData(DATA_WAVE_COUNT, NOT_STARTED); + _waveCount = 0; + events.Reset(); + DoUpdateWorldState(WORLD_STATE_HOR, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(_entranceDoorGUID, true); + + if (Creature* falric = instance->GetCreature(_falricGUID)) + falric->SetVisible(false); + if (Creature* marwyn = instance->GetCreature(_marwynGUID)) + marwyn->SetVisible(false); + + //despawn wave npcs + for (uint8 i = 0; i < 8; i++) + { + for (std::set<uint64>::const_iterator itr = waveGuidList[i].begin(); itr != waveGuidList[i].end(); ++itr) + instance->GetCreature(*itr)->DespawnOrUnsummon(); + } break; } } + + private: + uint64 _falricGUID; + uint64 _marwynGUID; + uint64 _jainaOrSylvanasPart1GUID; + uint64 _frostwornGeneralGUID; + + uint64 _frostmourneGUID; + uint64 _entranceDoorGUID; + uint64 _frostwornDoorGUID; + uint64 _arthasDoorGUID; + uint64 _escapeDoorGUID; + + uint32 _teamInInstance; + uint32 _waveCount; + uint32 _introEvent; + uint32 _frostwornGeneral; + + EventMap events; + + std::set<uint64> waveGuidList[8]; }; + InstanceScript* GetInstanceScript(InstanceMap* map) const + { + return new instance_halls_of_reflection_InstanceMapScript(map); + } }; void AddSC_instance_halls_of_reflection() |