diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 5b72b94647..94b367e61c 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -134,6 +134,11 @@ void InstanceScript::HandleGameObject(ObjectGuid GUID, bool open, GameObject* go } } +void InstanceScript::HandleGameObject(uint32 type, bool open) +{ + HandleGameObject(ObjectGuid::Empty, open, GetGameObject(type)); +} + bool InstanceScript::IsEncounterInProgress() const { for (std::vector::const_iterator itr = bosses.begin(); itr != bosses.end(); ++itr) diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index b10db66e9e..ba05588eea 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -193,11 +193,21 @@ public: //Called when a player enters/leaves water bodies. virtual void OnPlayerInWaterStateUpdate(Player* /*player*/, bool /*inWater*/) {} - //Handle open / close objects - //use HandleGameObject(ObjectGuid::Empty, boolen, GO); in OnObjectCreate in instance scripts - //use HandleGameObject(GUID, boolen, nullptr); in any other script + /** + * @brief Open or close a GameObject by GUID. + * @param guid The GUID of the GameObject. Pass ObjectGuid::Empty when providing the go pointer directly. + * @param open true to open (GO_STATE_ACTIVE), false to close (GO_STATE_READY). + * @param go Optional pointer to the GameObject. If nullptr, the object is looked up by GUID. + */ void HandleGameObject(ObjectGuid guid, bool open, GameObject* go = nullptr); + /** + * @brief Open or close a GameObject registered via LoadObjectData. + * @param type The ObjectData type constant (e.g. GO_FRONT_DOOR) used in the gameObjectData array. + * @param open true to open (GO_STATE_ACTIVE), false to close (GO_STATE_READY). + */ + void HandleGameObject(uint32 type, bool open); + //change active state of doors or buttons void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime = 0, bool useAlternativeState = false); diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp index 12772dceda..699581697c 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp @@ -16,173 +16,151 @@ */ #include "CreatureScript.h" -#include "halls_of_reflection.h" #include "ScriptedCreature.h" #include "SpellMgr.h" +#include "halls_of_reflection.h" enum Yells { - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_DEATH = 2, - SAY_IMPENDING_DESPAIR = 3, - SAY_DEFILING_HORROR = 4, + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2, + SAY_IMPENDING_DESPAIR = 3, + SAY_DEFILING_HORROR = 4, }; enum Spells { - SPELL_QUIVERING_STRIKE = 72422, - SPELL_IMPENDING_DESPAIR = 72426, - SPELL_DEFILING_HORROR = 72435, + SPELL_QUIVERING_STRIKE = 72422, + SPELL_IMPENDING_DESPAIR = 72426, + SPELL_DEFILING_HORROR = 72435, }; enum Events { - EVENT_NONE, - EVENT_QUIVERING_STRIKE, + EVENT_QUIVERING_STRIKE = 1, EVENT_IMPENDING_DESPAIR, EVENT_DEFILING_HORROR, EVENT_UNROOT, }; -const uint32 hopelessnessId[3] = { 72395, 72396, 72397 }; +constexpr uint32 hopelessnessId[3] = { 72395, 72396, 72397 }; -class boss_falric : public CreatureScript +struct boss_falric : public BossAI { -public: - boss_falric() : CreatureScript("boss_falric") { } + boss_falric(Creature* creature) : BossAI(creature, DATA_FALRIC) { } - struct boss_falricAI : public ScriptedAI + void Reset() override { - boss_falricAI(Creature* creature) : ScriptedAI(creature) - { - pInstance = creature->GetInstanceScript(); - } - - InstanceScript* pInstance; - EventMap events; - uint8 uiHopelessnessCount; - uint16 startFightTimer; - - void Reset() override - { - startFightTimer = 0; - uiHopelessnessCount = 0; - me->SetImmuneToAll(true); - me->SetControlled(false, UNIT_STATE_ROOT); - events.Reset(); - if (pInstance) - pInstance->SetData(DATA_FALRIC, NOT_STARTED); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SetImmuneToAll(false); - - events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 5s); - events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 11s); - events.ScheduleEvent(EVENT_DEFILING_HORROR, 20s); - } - - void DoAction(int32 a) override - { - if (a == 1) - { - Talk(SAY_AGGRO); - startFightTimer = 8000; - } - } - - void UpdateAI(uint32 diff) override - { - if (startFightTimer) - { - if (startFightTimer <= diff) - { - startFightTimer = 0; - me->SetInCombatWithZone(); - } - else - startFightTimer -= diff; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_QUIVERING_STRIKE: - me->CastSpell(me->GetVictim(), SPELL_QUIVERING_STRIKE, false); - events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 5s); - break; - case EVENT_IMPENDING_DESPAIR: - if (Unit* target = SelectTargetFromPlayerList(45.0f, 0, true)) - { - Talk(SAY_IMPENDING_DESPAIR); - me->CastSpell(target, SPELL_IMPENDING_DESPAIR, false); - } - events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 12s); - break; - case EVENT_DEFILING_HORROR: - Talk(SAY_DEFILING_HORROR); - me->CastSpell((Unit*)nullptr, SPELL_DEFILING_HORROR, false); - me->SetControlled(true, UNIT_STATE_ROOT); - events.DelayEventsToMax(5s, 0); - events.ScheduleEvent(EVENT_UNROOT, 4s); - events.ScheduleEvent(EVENT_DEFILING_HORROR, 20s); - break; - case EVENT_UNROOT: - me->SetControlled(false, UNIT_STATE_ROOT); - break; - } - - if ((uiHopelessnessCount == 0 && HealthBelowPct(67)) || (uiHopelessnessCount == 1 && HealthBelowPct(34)) || (uiHopelessnessCount == 2 && HealthBelowPct(11))) - { - if (uiHopelessnessCount) - me->RemoveOwnedAura(sSpellMgr->GetSpellIdForDifficulty(hopelessnessId[uiHopelessnessCount - 1], me)); - - me->CastSpell((Unit*)nullptr, hopelessnessId[uiHopelessnessCount], true); - ++uiHopelessnessCount; - } - - if (!me->HasUnitState(UNIT_STATE_ROOT)) - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - if (pInstance) - pInstance->SetData(DATA_FALRIC, DONE); - } - - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - Talk(SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason why) override - { - me->SetControlled(false, UNIT_STATE_ROOT); - ScriptedAI::EnterEvadeMode(why); - if (startFightTimer) - Reset(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); + BossAI::Reset(); + _hopelessnessCount = 0; + _startingFight = false; + me->SetImmuneToAll(true); + me->SetControlled(false, UNIT_STATE_ROOT); } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + me->SetImmuneToAll(false); + + events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 5s); + events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 11s); + events.ScheduleEvent(EVENT_DEFILING_HORROR, 20s); + } + + void DoAction(int32 action) override + { + if (action == 1) + { + Talk(SAY_AGGRO); + _startingFight = true; + me->m_Events.AddEventAtOffset([this]() + { + _startingFight = false; + me->SetInCombatWithZone(); + }, 8s); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_QUIVERING_STRIKE: + DoCastVictim(SPELL_QUIVERING_STRIKE); + events.Repeat(5s); + break; + case EVENT_IMPENDING_DESPAIR: + if (Unit* target = SelectTargetFromPlayerList(45.0f, 0, true)) + { + Talk(SAY_IMPENDING_DESPAIR); + DoCast(target, SPELL_IMPENDING_DESPAIR); + } + events.Repeat(12s); + break; + case EVENT_DEFILING_HORROR: + Talk(SAY_DEFILING_HORROR); + DoCastAOE(SPELL_DEFILING_HORROR); + me->SetControlled(true, UNIT_STATE_ROOT); + events.DelayEventsToMax(5s, 0); + events.ScheduleEvent(EVENT_UNROOT, 4s); + events.Repeat(20s); + break; + case EVENT_UNROOT: + me->SetControlled(false, UNIT_STATE_ROOT); + break; + } + + if ((_hopelessnessCount == 0 && HealthBelowPct(67)) + || (_hopelessnessCount == 1 && HealthBelowPct(34)) + || (_hopelessnessCount == 2 && HealthBelowPct(11))) + { + if (_hopelessnessCount) + me->RemoveOwnedAura(sSpellMgr->GetSpellIdForDifficulty(hopelessnessId[_hopelessnessCount - 1], me)); + + DoCastAOE(hopelessnessId[_hopelessnessCount], true); + ++_hopelessnessCount; + } + + if (!me->HasUnitState(UNIT_STATE_ROOT)) + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + Talk(SAY_DEATH); + } + + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(SAY_SLAY); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->SetControlled(false, UNIT_STATE_ROOT); + BossAI::EnterEvadeMode(why); + if (_startingFight) + Reset(); + } + +private: + uint8 _hopelessnessCount{}; + bool _startingFight{}; }; void AddSC_boss_falric() { - new boss_falric(); + RegisterHallsOfReflectionCreatureAI(boss_falric); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index 119dcef198..2f4b0784f6 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -16,160 +16,136 @@ */ #include "CreatureScript.h" -#include "SpellScriptLoader.h" -#include "halls_of_reflection.h" #include "ScriptedCreature.h" #include "SpellAuraEffects.h" #include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "halls_of_reflection.h" enum Yells { - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_DEATH = 2, - SAY_CORRUPTED_FLESH = 3, - SAY_CORRUPTED_WELL = 4, + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2, + SAY_CORRUPTED_FLESH = 3, + SAY_CORRUPTED_WELL = 4, }; enum Spells { - SPELL_OBLITERATE = 72360, - SPELL_WELL_OF_CORRUPTION = 72362, - SPELL_CORRUPTED_FLESH = 72363, - SPELL_SHARED_SUFFERING = 72368, + SPELL_OBLITERATE = 72360, + SPELL_WELL_OF_CORRUPTION = 72362, + SPELL_CORRUPTED_FLESH = 72363, + SPELL_SHARED_SUFFERING = 72368, }; enum Events { - EVENT_NONE, - EVENT_OBLITERATE, + EVENT_OBLITERATE = 1, EVENT_WELL_OF_CORRUPTION, EVENT_CORRUPTED_FLESH, EVENT_SHARED_SUFFERING, }; -class boss_marwyn : public CreatureScript +struct boss_marwyn : public BossAI { -public: - boss_marwyn() : CreatureScript("boss_marwyn") { } + boss_marwyn(Creature* creature) : BossAI(creature, DATA_MARWYN) { } - struct boss_marwynAI : public ScriptedAI + void Reset() override { - boss_marwynAI(Creature* creature) : ScriptedAI(creature) + BossAI::Reset(); + _startingFight = false; + me->SetImmuneToAll(true); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + me->SetImmuneToAll(false); + + events.ScheduleEvent(EVENT_OBLITERATE, 15s); + events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13s); + events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20s); + events.ScheduleEvent(EVENT_SHARED_SUFFERING, 5s); + } + + void DoAction(int32 action) override + { + if (action == 1) { - pInstance = creature->GetInstanceScript(); - } - - InstanceScript* pInstance; - EventMap events; - uint16 startFightTimer; - - void Reset() override - { - startFightTimer = 0; - me->SetImmuneToAll(true); - events.Reset(); - if (pInstance) - pInstance->SetData(DATA_MARWYN, NOT_STARTED); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SetImmuneToAll(false); - - events.ScheduleEvent(EVENT_OBLITERATE, 15s); - events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13s); - events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20s); - events.ScheduleEvent(EVENT_SHARED_SUFFERING, 5s); - } - - void DoAction(int32 a) override - { - if (a == 1) + Talk(SAY_AGGRO); + _startingFight = true; + me->m_Events.AddEventAtOffset([this]() { - Talk(SAY_AGGRO); - startFightTimer = 8000; - } + _startingFight = false; + me->SetInCombatWithZone(); + }, 8s); } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - if (startFightTimer) - { - if (startFightTimer <= diff) + case EVENT_OBLITERATE: + if (me->IsWithinMeleeRange(me->GetVictim())) { - startFightTimer = 0; - me->SetInCombatWithZone(); + DoCastVictim(SPELL_OBLITERATE); + events.Repeat(15s); } else - startFightTimer -= diff; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_OBLITERATE: - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->CastSpell(me->GetVictim(), SPELL_OBLITERATE, false); - events.ScheduleEvent(EVENT_OBLITERATE, 15s); - } - else - events.ScheduleEvent(EVENT_OBLITERATE, 3s); - break; - case EVENT_WELL_OF_CORRUPTION: - Talk(SAY_CORRUPTED_WELL); - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_WELL_OF_CORRUPTION, false); - events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13s); - break; - case EVENT_CORRUPTED_FLESH: - Talk(SAY_CORRUPTED_FLESH); - me->CastSpell((Unit*)nullptr, SPELL_CORRUPTED_FLESH, false); - events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20s); - break; - case EVENT_SHARED_SUFFERING: - if (Unit* target = SelectTargetFromPlayerList(200.0f, 0, true)) - me->CastSpell(target, SPELL_SHARED_SUFFERING, true); - events.ScheduleEvent(EVENT_SHARED_SUFFERING, 15s); - break; - } - - DoMeleeAttackIfReady(); + events.Repeat(3s); + break; + case EVENT_WELL_OF_CORRUPTION: + Talk(SAY_CORRUPTED_WELL); + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_WELL_OF_CORRUPTION); + events.Repeat(13s); + break; + case EVENT_CORRUPTED_FLESH: + Talk(SAY_CORRUPTED_FLESH); + DoCastAOE(SPELL_CORRUPTED_FLESH); + events.Repeat(20s); + break; + case EVENT_SHARED_SUFFERING: + if (Unit* target = SelectTargetFromPlayerList(200.0f, 0, true)) + DoCast(target, SPELL_SHARED_SUFFERING, true); + events.Repeat(15s); + break; } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - if (pInstance) - pInstance->SetData(DATA_MARWYN, DONE); - } - - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - Talk(SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (startFightTimer) - Reset(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); + DoMeleeAttackIfReady(); } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + Talk(SAY_DEATH); + } + + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(SAY_SLAY); + } + + void EnterEvadeMode(EvadeReason why) override + { + BossAI::EnterEvadeMode(why); + if (_startingFight) + Reset(); + } + +private: + bool _startingFight{}; }; enum SharedSufferingAura @@ -186,25 +162,37 @@ class spell_hor_shared_suffering_aura : public AuraScript return ValidateSpellInfo({ SPELL_SHARED_SUFFERING_DAMAGE }); } - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL) // dispelled - if (Unit* caster = GetCaster()) - if (Map* map = caster->FindMap()) - if (Aura* a = aurEff->GetBase()) - { - uint32 count = 0; - uint32 ticks = 0; - uint32 dmgPerTick = a->GetSpellInfo()->Effects[0].BasePoints; - Map::PlayerList const& pl = map->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - if (p->IsAlive()) - ++count; - ticks = (a->GetDuration() / int32(a->GetSpellInfo()->Effects[0].Amplitude)) + 1; - int32 dmg = (ticks * dmgPerTick) / count; - caster->CastCustomSpell(GetTarget(), SPELL_SHARED_SUFFERING_DAMAGE, nullptr, &dmg, nullptr, true); - } + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL) + return; + + Unit* caster = GetCaster(); + if (!caster) + return; + + Map* map = caster->FindMap(); + if (!map) + return; + + Aura* aura = aurEff->GetBase(); + if (!aura) + return; + + uint32 count = 0; + uint32 dmgPerTick = aura->GetSpellInfo()->Effects[0].BasePoints; + Map::PlayerList const& pl = map->GetPlayers(); + for (auto itr = pl.begin(); itr != pl.end(); ++itr) + if (Player* p = itr->GetSource()) + if (p->IsAlive()) + ++count; + + if (!count) + return; + + uint32 ticks = (aura->GetDuration() / int32(aura->GetSpellInfo()->Effects[0].Amplitude)) + 1; + int32 dmg = (ticks * dmgPerTick) / count; + caster->CastCustomSpell(GetTarget(), SPELL_SHARED_SUFFERING_DAMAGE, nullptr, &dmg, nullptr, true); } void Register() override @@ -215,6 +203,6 @@ class spell_hor_shared_suffering_aura : public AuraScript void AddSC_boss_marwyn() { - new boss_marwyn(); + RegisterHallsOfReflectionCreatureAI(boss_marwyn); RegisterSpellScript(spell_hor_shared_suffering_aura); } 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 bf20e8d990..266550e9fe 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -155,16 +155,12 @@ public: { QuestStatus status = player->GetQuestStatus(creature->GetEntry() == NPC_SYLVANAS_PART1 ? QUEST_DELIVRANCE_FROM_THE_PIT_H2 : QUEST_DELIVRANCE_FROM_THE_PIT_A2); if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - { - AddGossipItemFor(player, creature->GetEntry() == NPC_SYLVANAS_PART1 ? GOSSIP_MENU_SYLVANAS : GOSISP_MENU_JAINA, GOSSIP_OPTION_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - } + AddGossipItemFor(player, creature->GetEntry() == NPC_SYLVANAS_PART1 ? GOSSIP_MENU_SYLVANAS : GOSISP_MENU_JAINA, GOSSIP_OPTION_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); // once last quest is completed, she offers this shortcut of the starting event status = player->GetQuestStatus(creature->GetEntry() == NPC_SYLVANAS_PART1 ? QUEST_WRATH_OF_THE_LICH_KING_H2 : QUEST_WRATH_OF_THE_LICH_KING_A2); if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - { AddGossipItemFor(player, creature->GetEntry() == NPC_SYLVANAS_PART1 ? GOSSIP_MENU_SYLVANAS : GOSISP_MENU_JAINA, GOSSIP_OPTION_START_SKIP, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - } } SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); @@ -190,13 +186,13 @@ public: ClearGossipMenuFor(player); switch (uiAction) { - case GOSSIP_ACTION_INFO_DEF+1: + case GOSSIP_ACTION_INFO_DEF + 1: CloseGossipMenuFor(player); if (creature->AI()) creature->AI()->DoAction(ACTION_START_INTRO); creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); break; - case GOSSIP_ACTION_INFO_DEF+2: + case GOSSIP_ACTION_INFO_DEF + 2: CloseGossipMenuFor(player); if (creature->AI()) creature->AI()->DoAction(ACTION_SKIP_INTRO); @@ -216,13 +212,13 @@ public: { npc_hor_leaderAI(Creature* creature) : NullCreatureAI(creature) { - pInstance = me->GetInstanceScript(); - if (!pInstance) + instance = me->GetInstanceScript(); + if (!instance) me->IsAIEnabled = false; - first = (pInstance && !pInstance->GetData(DATA_INTRO)); + first = (instance && !instance->GetPersistentData(PERSISTENT_DATA_INTRO)); } - InstanceScript* pInstance; + InstanceScript* instance; EventMap events; bool first; bool shortver; @@ -262,7 +258,7 @@ public: switch (events.ExecuteEvent()) { case EVENT_PRE_INTRO_1: - if (pInstance) + if (instance) { me->SetSheath(SHEATH_STATE_MELEE); @@ -272,10 +268,8 @@ public: break; case EVENT_PRE_INTRO_2: if (me->GetEntry() == NPC_JAINA_PART1) - { Talk(SAY_JAINA_INTRO_1); - } - me->GetMotionMaster()->MovePoint(0, SpawnPos); + me->GetMotionMaster()->MovePoint(0, SpawnPos); break; case EVENT_TALK_LEADER_1: me->SetSheath(SHEATH_STATE_UNARMED); @@ -292,19 +286,16 @@ public: shortver = false; me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); me->GetMotionMaster()->MovePoint(0, MoveThronePos); - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) { - pLoralen->LoadEquipment(true); - pLoralen->SetVisible(true); - pLoralen->SetWalk(true); - pLoralen->GetMotionMaster()->MovePoint(0, LoralenMidleFollowPos); - + loralen->LoadEquipment(true); + loralen->SetVisible(true); + loralen->SetWalk(true); + loralen->GetMotionMaster()->MovePoint(0, LoralenMidleFollowPos); } // Begining of intro is differents between factions as the speech sequence and timers are differents. if (me->GetEntry() == NPC_JAINA_PART1) - { events.ScheduleEvent(EVENT_INTRO_A2_1, 10s); - } else { events.ScheduleEvent(EVENT_INTRO_H2_2, 9s); @@ -317,10 +308,8 @@ public: shortver = true; me->SetUInt32Value(UNIT_NPC_EMOTESTATE, (me->GetEntry() == NPC_JAINA_PART1 ? EMOTE_STATE_READY2H : EMOTE_STATE_READY1H)); me->GetMotionMaster()->MovePoint(0, MoveThronePos); - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowPos); - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowPos); events.ScheduleEvent(EVENT_INTRO_LK_1, 0ms); break; @@ -334,25 +323,25 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_3, 10s); break; case EVENT_INTRO_A2_3: - pInstance->HandleGameObject(pInstance->GetGuidData(GO_FROSTMOURNE), true); - me->CastSpell(me, SPELL_FROSTMOURNE_SPAWN_SOUND, true); - //me->CastSpell(me, SPELL_ARCANE_CAST_VISUAL, false);// the sniff is missing from the alliance + instance->HandleGameObject(GO_FROSTMOURNE, true); + DoCastSelf(SPELL_FROSTMOURNE_SPAWN_SOUND, true); + //DoCastSelf(SPELL_ARCANE_CAST_VISUAL);// the sniff is missing from the alliance events.ScheduleEvent(EVENT_INTRO_A2_4, 10s); break; case EVENT_INTRO_A2_4: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - pUther->SetVisible(true); - if (Aura* a = pUther->AddAura(SPELL_SHADOWMOURNE_VISUAL, pUther)) + uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + uther->SetVisible(true); + if (Aura* a = uther->AddAura(SPELL_SHADOWMOURNE_VISUAL, uther)) a->SetDuration(8000); } events.ScheduleEvent(EVENT_INTRO_A2_5, 2s); break; case EVENT_INTRO_A2_5: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_1); + uther->AI()->Talk(SAY_UTHER_INTRO_A2_1); events.ScheduleEvent(EVENT_INTRO_A2_6, 3s); } break; @@ -361,10 +350,8 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_7, 6s); break; case EVENT_INTRO_A2_7: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_2); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_2); events.ScheduleEvent(EVENT_INTRO_A2_8, 6500ms); break; case EVENT_INTRO_A2_8: @@ -372,10 +359,8 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_9, 2s); break; case EVENT_INTRO_A2_9: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_3); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_3); events.ScheduleEvent(EVENT_INTRO_A2_10, 9s); break; case EVENT_INTRO_A2_10: @@ -383,10 +368,8 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_11, 5s); break; case EVENT_INTRO_A2_11: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_4); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_4); events.ScheduleEvent(EVENT_INTRO_A2_12, 11s); break; case EVENT_INTRO_A2_12: @@ -394,10 +377,8 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_13, 4s); break; case EVENT_INTRO_A2_13: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_5); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_5); events.ScheduleEvent(EVENT_INTRO_A2_14, 12s + 500ms); break; case EVENT_INTRO_A2_14: @@ -405,15 +386,13 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_15, 10s); break; case EVENT_INTRO_A2_15: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_6); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_6); events.ScheduleEvent(EVENT_INTRO_A2_16, 24s); break; case EVENT_INTRO_A2_16: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_7); + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->AI()->Talk(SAY_UTHER_INTRO_A2_7); events.ScheduleEvent(EVENT_INTRO_A2_17, 4s); break; case EVENT_INTRO_A2_17: @@ -421,10 +400,10 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_18, 2s); break; case EVENT_INTRO_A2_18: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_8); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_A2_8); } events.ScheduleEvent(EVENT_INTRO_A2_19, 11s); break; @@ -435,17 +414,13 @@ public: // H2 Intro Events case EVENT_LORALEN_MOVE_1: - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowPos); - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowPos); break; case EVENT_LORALEN_MOVE_2: - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); break; case EVENT_INTRO_H2_2: @@ -462,13 +437,13 @@ public: break; case EVENT_INTRO_H2_3: - me->CastSpell(me, SPELL_SUMMON_SOULS, false); + DoCastSelf(SPELL_SUMMON_SOULS); events.ScheduleEvent(EVENT_INTRO_H2_3_1, 5s); break; case EVENT_INTRO_H2_3_1: - me->CastSpell(me, SPELL_FROSTMOURNE_SPAWN_SOUND, false); - pInstance->HandleGameObject(pInstance->GetGuidData(GO_FROSTMOURNE), true); + DoCastSelf(SPELL_FROSTMOURNE_SPAWN_SOUND); + instance->HandleGameObject(GO_FROSTMOURNE, true); events.ScheduleEvent(EVENT_INTRO_H2_3_2, 3s); break; @@ -477,22 +452,20 @@ public: events.ScheduleEvent(EVENT_INTRO_H2_4, 2s); break; case EVENT_INTRO_H2_4: - if (Creature* pUther = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->SetVisible(true); - if (Aura* a = pUther->AddAura(SPELL_SHADOWMOURNE_VISUAL, pUther)) - { + uther->SetVisible(true); + if (Aura* a = uther->AddAura(SPELL_SHADOWMOURNE_VISUAL, uther)) a->SetDuration(8000); - } } events.ScheduleEvent(EVENT_INTRO_H2_5, 7s); break; case EVENT_INTRO_H2_5: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_1); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_1); } events.ScheduleEvent(EVENT_INTRO_H2_6, 11s); break; @@ -502,10 +475,10 @@ public: events.ScheduleEvent(EVENT_INTRO_H2_7, 2s + 500ms); break; case EVENT_INTRO_H2_7: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_2); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_2); } events.ScheduleEvent(EVENT_INTRO_H2_8, 9s);// break; @@ -515,10 +488,10 @@ public: events.ScheduleEvent(EVENT_INTRO_H2_9, 5s); break; case EVENT_INTRO_H2_9: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_3); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_3); } events.ScheduleEvent(EVENT_INTRO_H2_10, 20s); break; @@ -528,10 +501,10 @@ public: events.ScheduleEvent(EVENT_INTRO_H2_11, 3s); break; case EVENT_INTRO_H2_11: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_4); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_4); } events.ScheduleEvent(EVENT_INTRO_H2_12, 21s + 500ms); break; @@ -541,19 +514,18 @@ public: events.ScheduleEvent(EVENT_INTRO_H2_13, 3s + 500ms); break; case EVENT_INTRO_H2_13: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_5); - + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_5); } events.ScheduleEvent(EVENT_INTRO_H2_14, 12s + 500ms); break; case EVENT_INTRO_H2_14: - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_6); + uther->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_6); } events.ScheduleEvent(EVENT_INTRO_H2_15, 8s); break; @@ -565,25 +537,25 @@ public: // Remaining Intro Events common for both faction case EVENT_INTRO_LK_1: - if (Creature* pLichKing = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pInstance->HandleGameObject(pInstance->GetGuidData(GO_ARTHAS_DOOR), true); - pLichKing->SetVisible(true); + instance->HandleGameObject(GO_ARTHAS_DOOR, true); + lichKing->SetVisible(true); - pLichKing->GetMotionMaster()->MovePoint(0, LichKingMoveMidlelThronePos, FORCED_MOVEMENT_NONE, 0.f, false); + lichKing->GetMotionMaster()->MovePoint(0, LichKingMoveMidlelThronePos, FORCED_MOVEMENT_NONE, 0.f, false); } if (!shortver) - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + uther->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); if (me->GetEntry() == NPC_JAINA_PART1) - pUther->AI()->Talk(SAY_UTHER_INTRO_A2_9); + uther->AI()->Talk(SAY_UTHER_INTRO_A2_9); else - pUther->AI()->Talk(SAY_UTHER_INTRO_H2_7); + uther->AI()->Talk(SAY_UTHER_INTRO_H2_7); } events.ScheduleEvent(EVENT_INTRO_LK_1_1, 9s); @@ -593,102 +565,100 @@ public: break; case EVENT_INTRO_LK_1_1: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pLichKing->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); - pLichKing->AI()->Talk(SAY_LK_INTRO_1); + lichKing->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + lichKing->AI()->Talk(SAY_LK_INTRO_1); } break; case EVENT_INTRO_LK_1_2: if (!shortver) - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); - pUther->SetFacingTo(0.89f); + uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); + uther->SetFacingTo(0.89f); } break; case EVENT_INTRO_LK_1_3: - pInstance->HandleGameObject(pInstance->GetGuidData(GO_ARTHAS_DOOR), false); + instance->HandleGameObject(GO_ARTHAS_DOOR, false); break; case EVENT_INTRO_LK_2: if (!shortver) - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pLichKing->SetVisible(true); - pLichKing->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos, FORCED_MOVEMENT_NONE, 0.f, false); + lichKing->SetVisible(true); + lichKing->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos, FORCED_MOVEMENT_NONE, 0.f, false); } events.ScheduleEvent(EVENT_INTRO_LK_2_1, 1s); break; case EVENT_INTRO_LK_2_1: if (!shortver) - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) + if (Creature* uther = instance->GetCreature(NPC_UTHER)) { - pUther->SendPlaySpellVisual(SPELL_UTHER_DESPAWN); - pUther->CastSpell(pUther, SPELL_UTHER_DESPAWN, true); + uther->SendPlaySpellVisual(SPELL_UTHER_DESPAWN); + uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true); } events.ScheduleEvent(EVENT_INTRO_LK_3, 2s); break; case EVENT_INTRO_LK_3: if (!shortver) - if (Creature* pUther = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_UTHER))) - { - pUther->SetVisible(false); - } + if (Creature* uther = instance->GetCreature(NPC_UTHER)) + uther->SetVisible(false); events.ScheduleEvent(EVENT_INTRO_LK_4, 6s); break; case EVENT_INTRO_LK_4: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pLichKing->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); - pLichKing->AI()->Talk(SAY_LK_INTRO_2); + lichKing->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); + lichKing->AI()->Talk(SAY_LK_INTRO_2); } events.ScheduleEvent(EVENT_INTRO_LK_4_2, 10s); break; case EVENT_INTRO_LK_4_2: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pLichKing->LoadEquipment(1, true); - pLichKing->SendMovementFlagUpdate(); - pLichKing->CastSpell(pLichKing, SPELL_FROSTMOURNE_EQUIP, false); - pInstance->HandleGameObject(pInstance->GetGuidData(GO_FROSTMOURNE), false); + lichKing->LoadEquipment(1, true); + lichKing->SendMovementFlagUpdate(); + lichKing->CastSpell(lichKing, SPELL_FROSTMOURNE_EQUIP); + instance->HandleGameObject(GO_FROSTMOURNE, false); events.ScheduleEvent(EVENT_INTRO_LK_4_3, 1750ms); } events.ScheduleEvent(EVENT_INTRO_LK_5, 6s); break; case EVENT_INTRO_LK_4_3: - if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_FROSTMOURNE))) + if (GameObject* go = instance->GetGameObject(GO_FROSTMOURNE)) go->SetPhaseMask(2, true); break; case EVENT_INTRO_LK_5: - if (Creature* pFalric = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_FALRIC))) + if (Creature* falric = instance->GetCreature(DATA_FALRIC)) { - pFalric->UpdatePosition(5274.9f, 2039.2f, 709.319f, 5.4619f, true); - pFalric->StopMovingOnCurrentPos(); - pFalric->SetVisible(true); - if (pFalric->IsAlive()) + falric->UpdatePosition(5274.9f, 2039.2f, 709.319f, 5.4619f, true); + falric->StopMovingOnCurrentPos(); + falric->SetVisible(true); + if (falric->IsAlive()) { - pFalric->GetMotionMaster()->MovePoint(0, FalricMovePos); - if (Aura* a = pFalric->AddAura(SPELL_SHADOWMOURNE_VISUAL, pFalric)) + falric->GetMotionMaster()->MovePoint(0, FalricMovePos); + if (Aura* a = falric->AddAura(SPELL_SHADOWMOURNE_VISUAL, falric)) a->SetDuration(8000); } } - if (Creature* pMarwyn = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MARWYN))) + if (Creature* marwyn = instance->GetCreature(DATA_MARWYN)) { - pMarwyn->UpdatePosition(5343.77f, 1973.86f, 709.319f, 2.35173f, true); - pMarwyn->StopMovingOnCurrentPos(); - pMarwyn->SetVisible(true); - if (pMarwyn->IsAlive()) + marwyn->UpdatePosition(5343.77f, 1973.86f, 709.319f, 2.35173f, true); + marwyn->StopMovingOnCurrentPos(); + marwyn->SetVisible(true); + if (marwyn->IsAlive()) { - pMarwyn->GetMotionMaster()->MovePoint(0, MarwynMovePos); - if (Aura* a = pMarwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, pMarwyn)) + marwyn->GetMotionMaster()->MovePoint(0, MarwynMovePos); + if (Aura* a = marwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, marwyn)) a->SetDuration(8000); } } @@ -699,57 +669,55 @@ public: break; case EVENT_INTRO_LK_5_1: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) { - pLichKing->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - pLichKing->AI()->Talk(SAY_LK_INTRO_3); + lichKing->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + lichKing->AI()->Talk(SAY_LK_INTRO_3); } break; case EVENT_INTRO_LK_5_2: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) - { - pLichKing->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos, FORCED_MOVEMENT_NONE, 0.f, false); - } + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) + lichKing->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos, FORCED_MOVEMENT_NONE, 0.f, false); break; case EVENT_INTRO_LK_5_3: me->SetSpeed(MOVE_RUN, 1.6); me->SetSheath(SHEATH_STATE_MELEE); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H); - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) { - pLoralen->SetSheath(SHEATH_STATE_MELEE); - pLoralen->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H); - pLoralen->SetWalk(false); - pLoralen->LoadEquipment(true); + loralen->SetSheath(SHEATH_STATE_MELEE); + loralen->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H); + loralen->SetWalk(false); + loralen->LoadEquipment(true); } break; case EVENT_INTRO_LK_6: - if (Creature* pFalric = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_FALRIC))) + if (Creature* falric = instance->GetCreature(DATA_FALRIC)) { - pFalric->HandleEmoteCommand(EMOTE_ONESHOT_BOW); - pFalric->AI()->Talk(SAY_FALRIC_INTRO_1); + falric->HandleEmoteCommand(EMOTE_ONESHOT_BOW); + falric->AI()->Talk(SAY_FALRIC_INTRO_1); } events.ScheduleEvent(EVENT_INTRO_LK_7, 2s); break; case EVENT_INTRO_LK_7: - if (Creature* pMarwyn = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MARWYN))) + if (Creature* marwyn = instance->GetCreature(DATA_MARWYN)) { - pMarwyn->HandleEmoteCommand(EMOTE_ONESHOT_BOW); - pMarwyn->AI()->Talk(SAY_MARWYN_INTRO_1); + marwyn->HandleEmoteCommand(EMOTE_ONESHOT_BOW); + marwyn->AI()->Talk(SAY_MARWYN_INTRO_1); } events.ScheduleEvent(EVENT_INTRO_LK_8, 3s); break; case EVENT_INTRO_LK_8: - if (Creature* pFalric = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_FALRIC))) + if (Creature* falric = instance->GetCreature(DATA_FALRIC)) { - pFalric->AI()->Talk(SAY_FALRIC_INTRO_2); - pInstance->SetData(ACTION_SHOW_TRASH, 1); - pInstance->HandleGameObject(pInstance->GetGuidData(GO_ARTHAS_DOOR), true); + falric->AI()->Talk(SAY_FALRIC_INTRO_2); + instance->SetData(ACTION_SHOW_TRASH, 1); + instance->HandleGameObject(GO_ARTHAS_DOOR, true); } events.ScheduleEvent(EVENT_INTRO_LK_9, 6s); break; @@ -765,39 +733,28 @@ public: me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); me->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos, FORCED_MOVEMENT_NONE, 0.f, false); } - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk1, FORCED_MOVEMENT_NONE, 0.f, false); - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk1, FORCED_MOVEMENT_NONE, 0.f, false); events.ScheduleEvent(EVENT_INTRO_LK_10, 1s + 500ms); break; case EVENT_INTRO_LK_10: - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk2, FORCED_MOVEMENT_NONE, 0.f, false); - - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk2, FORCED_MOVEMENT_NONE, 0.f, false); events.ScheduleEvent(EVENT_INTRO_LK_11, 2s); break; case EVENT_INTRO_LK_11: - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk3, FORCED_MOVEMENT_NONE, 0.f, false); - } + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowLk3, FORCED_MOVEMENT_NONE, 0.f, false); events.ScheduleEvent(EVENT_INTRO_LK_12, 5s + 500ms); break; case EVENT_INTRO_LK_12: - if (Creature* pLichKing = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(NPC_LICH_KING_EVENT))) - { - pLichKing->SetVisible(false); - } - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) - { - pLoralen->GetMotionMaster()->MovePoint(0, LoralenFollowLkFinal, FORCED_MOVEMENT_NONE, 0.f, false); - } + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_EVENT)) + lichKing->SetVisible(false); + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) + loralen->GetMotionMaster()->MovePoint(0, LoralenFollowLkFinal, FORCED_MOVEMENT_NONE, 0.f, false); events.ScheduleEvent(EVENT_INTRO_LK_13, 2s); break; case EVENT_INTRO_LK_13: @@ -806,19 +763,19 @@ public: break; case EVENT_INTRO_END: - pInstance->HandleGameObject(pInstance->GetGuidData(GO_ARTHAS_DOOR), false); - pInstance->HandleGameObject(pInstance->GetGuidData(GO_FRONT_DOOR), false); + instance->HandleGameObject(GO_ARTHAS_DOOR, false); + instance->HandleGameObject(GO_FRONT_DOOR, false); events.ScheduleEvent(EVENT_INTRO_END_SET, 3s); break; case EVENT_INTRO_END_SET: - if (Creature* pLoralen = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_DARK_RANGER_LORALEN))) + if (Creature* loralen = instance->GetCreature(NPC_DARK_RANGER_LORALEN)) { - pLoralen->UpdatePosition(5369.71289f, 2083.6330f, 707.695129f, 0.188739f, true); - pLoralen->StopMovingOnCurrentPos(); - pLoralen->SetVisible(true); - pLoralen->KillSelf(pLoralen); + loralen->UpdatePosition(5369.71289f, 2083.6330f, 707.695129f, 0.188739f, true); + loralen->StopMovingOnCurrentPos(); + loralen->SetVisible(true); + loralen->KillSelf(loralen); } - pInstance->SetData(DATA_INTRO, DONE); + instance->SetData(DATA_INTRO, DONE); break; } } @@ -859,6 +816,21 @@ enum TrashSpells SPELL_CURSED_ARROW = 72222, SPELL_FROST_TRAP = 72215, SPELL_ICE_SHOT = 72268, + + // Phantom Mage (clone visual) + SPELL_HALLUCINATION_CLONE = 72343, + + // Raging Ghoul + SPELL_LEAP = 70150, + + // Risen Witch Doctor + SPELL_CURSE_OF_DOOM = 70144, + SPELL_SHADOW_BOLT_WD = 70080, + SPELL_SHADOW_BOLT_VOLLEY = 70145, + + // Lumbering Abomination + SPELL_VOMIT_SPRAY = 70176, + SPELL_CLEAVE = 40505, }; enum TrashEvents @@ -896,704 +868,591 @@ enum TrashEvents EVENT_ICE_SHOT, }; -class npc_ghostly_priest : public CreatureScript +struct npc_ghostly_priest: public ScriptedAI { -public: - npc_ghostly_priest() : CreatureScript("npc_ghostly_priest") { } + npc_ghostly_priest(Creature* creature) : ScriptedAI(creature) {} - CreatureAI* GetAI(Creature* creature) const override + void DoAction(int32 action) override { - return GetHallsOfReflectionAI(creature); + if (action == 1) + { + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + AttackStart(target); + } } - struct npc_ghostly_priestAI: public ScriptedAI + void Reset() override { - npc_ghostly_priestAI(Creature* c) : ScriptedAI(c) {} + events.Reset(); + } - EventMap events; + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5s); + events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 8s); + events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10s); + events.ScheduleEvent(EVENT_DARK_MENDING, 8s); + } - void DoAction(int32 a) override + void JustDied(Unit* /*killer*/) override + { + if (!urand(0,9)) + Talk(SAY_WAVE_DEATH); + } + + void AttackStart(Unit* who) override + { + if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return; + ScriptedAI::AttackStart(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) { - if (a == 1) - { - me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) - AttackStart(target); - } - } - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5s); - events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 8s); - events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10s); - events.ScheduleEvent(EVENT_DARK_MENDING, 8s); - } - - void JustDied(Unit* /*killer*/) override - { - if (!urand(0,9)) + case EVENT_SHADOW_WORD_PAIN: + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_SHADOW_WORD_PAIN); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5s); + break; + case EVENT_CIRCLE_OF_DESTRUCTION: + if (Unit* target = SelectTargetFromPlayerList(10.0f, 0, true)) + DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); + events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12s); + break; + case EVENT_COWER_IN_FEAR: + if (Unit* target = SelectTargetFromPlayerList(20.0f, 0, true)) + DoCast(target, SPELL_COWER_IN_FEAR); + events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10s); + break; + case EVENT_DARK_MENDING: + if (Unit* target = DoSelectLowestHpFriendly(35.0f, DUNGEON_MODE(20000, 35000))) { - Talk(SAY_WAVE_DEATH); + DoCast(target, SPELL_DARK_MENDING); + events.ScheduleEvent(EVENT_DARK_MENDING, 6s); } + else + events.ScheduleEvent(EVENT_DARK_MENDING, 3s); + break; } - void AttackStart(Unit* who) override - { - if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return; - ScriptedAI::AttackStart(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SHADOW_WORD_PAIN: - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_SHADOW_WORD_PAIN, false); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5s); - break; - case EVENT_CIRCLE_OF_DESTRUCTION: - if (Unit* target = SelectTargetFromPlayerList(10.0f, 0, true)) - me->CastSpell(target, SPELL_CIRCLE_OF_DESTRUCTION, false); - events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12s); - break; - case EVENT_COWER_IN_FEAR: - if (Unit* target = SelectTargetFromPlayerList(20.0f, 0, true)) - me->CastSpell(target, SPELL_COWER_IN_FEAR, false); - events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10s); - break; - case EVENT_DARK_MENDING: - if (Unit* target = DoSelectLowestHpFriendly(35.0f, DUNGEON_MODE(20000, 35000))) - { - me->CastSpell(target, SPELL_DARK_MENDING, false); - events.ScheduleEvent(EVENT_DARK_MENDING, 6s); - } - else - events.ScheduleEvent(EVENT_DARK_MENDING, 3s); - break; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - } - } - }; -}; - -class npc_phantom_mage : public CreatureScript -{ -public: - npc_phantom_mage() : CreatureScript("npc_phantom_mage") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); + DoMeleeAttackIfReady(); } - struct npc_phantom_mageAI: public ScriptedAI + void EnterEvadeMode(EvadeReason why) override { - npc_phantom_mageAI(Creature* c) : ScriptedAI(c) {} - - EventMap events; - - void DoAction(int32 a) override + ScriptedAI::EnterEvadeMode(why); + if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) { - if (a == 1) - { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + } + } +}; + +struct npc_phantom_mage: public ScriptedAI +{ + npc_phantom_mage(Creature* creature) : ScriptedAI(creature) {} + + void DoAction(int32 action) override + { + if (action == 1) + { + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + AttackStart(target); + } + } + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_FIREBALL, 3s); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s); + events.ScheduleEvent(EVENT_FROSTBOLT, 9s); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12s); + events.ScheduleEvent(EVENT_HALLUCINATION, 40s); + } + + void JustDied(Unit* /*killer*/) override + { + if (!urand(0,9)) + Talk(SAY_WAVE_DEATH); + } + + void AttackStart(Unit* who) override + { + if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return; + ScriptedAI::AttackStart(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_FIREBALL: + DoCastVictim(SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 6s); + break; + case EVENT_FLAMESTRIKE: + DoCastVictim(SPELL_FLAMESTRIKE); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 15s); + break; + case EVENT_FROSTBOLT: + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_FROSTBOLT); + events.ScheduleEvent(EVENT_FROSTBOLT, 9s); + break; + case EVENT_CHAINS_OF_ICE: + if (Unit* target = SelectTargetFromPlayerList(100.0f, 0, true)) + DoCast(target, SPELL_CHAINS_OF_ICE); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12s); + break; + case EVENT_HALLUCINATION: + //DoCastSelf(SPELL_HALLUCINATION); + me->SummonCreature(NPC_PHANTOM_HALLUCINATION, *me, TEMPSUMMON_TIMED_DESPAWN, 30000); + DoCastSelf(SPELL_HALLUCINATION_CLONE, true); + break; + } + + DoMeleeAttackIfReady(); + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) + { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + } + } +}; + +struct npc_phantom_hallucination : public npc_phantom_mage +{ + npc_phantom_hallucination(Creature* creature) : npc_phantom_mage(creature) + { + numOfUpd = 2; + } + + uint8 numOfUpd; + + void JustDied(Unit* /*who*/) override + { + DoCastAOE(SPELL_HALLUCINATION_2); + } + + void UpdateAI(uint32 diff) override + { + if (numOfUpd) + { + if (--numOfUpd == 0) me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) - AttackStart(target); - } + return; } - void Reset() override - { - events.Reset(); - } + npc_phantom_mage::UpdateAI(diff); + } - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_FIREBALL, 3s); - events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s); - events.ScheduleEvent(EVENT_FROSTBOLT, 9s); - events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12s); - events.ScheduleEvent(EVENT_HALLUCINATION, 40s); - } + void EnterEvadeMode(EvadeReason why) override + { + if (numOfUpd) + return; - void JustDied(Unit* /*killer*/) override + ScriptedAI::EnterEvadeMode(why); + if (me->IsSummon()) + me->ToTempSummon()->DespawnOrUnsummon(1ms); + } +}; + +struct npc_shadowy_mercenary: public ScriptedAI +{ + npc_shadowy_mercenary(Creature* creature) : ScriptedAI(creature) {} + + void DoAction(int32 action) override + { + if (action == 1) { - if (!urand(0,9)) + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + AttackStart(target); + } + } + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_SHADOW_STEP, 4s); + events.ScheduleEvent(EVENT_DEADLY_POISON, 6s); + events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10s); + events.ScheduleEvent(EVENT_KIDNEY_SHOT, 5s); + } + + void JustDied(Unit* /*killer*/) override + { + if (!urand(0,9)) + Talk(SAY_WAVE_DEATH); + } + + void AttackStart(Unit* who) override + { + if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return; + ScriptedAI::AttackStart(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SHADOW_STEP: + if (Unit* target = SelectTargetFromPlayerList(100.0f, 0, true)) { - Talk(SAY_WAVE_DEATH); - } - } - - void AttackStart(Unit* who) override - { - if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return; - ScriptedAI::AttackStart(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_FIREBALL: - me->CastSpell(me->GetVictim(), SPELL_FIREBALL, false); - events.ScheduleEvent(EVENT_FIREBALL, 6s); - break; - case EVENT_FLAMESTRIKE: - me->CastSpell(me->GetVictim(), SPELL_FLAMESTRIKE, false); - events.ScheduleEvent(EVENT_FLAMESTRIKE, 15s); - break; - case EVENT_FROSTBOLT: - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_FROSTBOLT, false); - events.ScheduleEvent(EVENT_FROSTBOLT, 9s); - break; - case EVENT_CHAINS_OF_ICE: - if (Unit* target = SelectTargetFromPlayerList(100.0f, 0, true)) - me->CastSpell(target, SPELL_CHAINS_OF_ICE, false); - events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12s); - break; - case EVENT_HALLUCINATION: - //me->CastSpell(me, SPELL_HALLUCINATION, false); - me->SummonCreature(NPC_PHANTOM_HALLUCINATION, *me, TEMPSUMMON_TIMED_DESPAWN, 30000); - me->CastSpell(me, SPELL_HALLUCINATION + 1, true); - break; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - } - } - }; -}; - -class npc_phantom_hallucination : public CreatureScript -{ -public: - npc_phantom_hallucination() : CreatureScript("npc_phantom_hallucination") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); - } - - struct npc_phantom_hallucinationAI : public npc_phantom_mage::npc_phantom_mageAI - { - npc_phantom_hallucinationAI(Creature* c) : npc_phantom_mage::npc_phantom_mageAI(c) - { - numOfUpd = 2; - } - - uint8 numOfUpd; - - void JustDied(Unit* /*who*/) override - { - me->CastSpell((Unit*)nullptr, SPELL_HALLUCINATION_2, false); - } - - void UpdateAI(uint32 diff) override - { - if (numOfUpd) - { - if (--numOfUpd == 0) - me->SetInCombatWithZone(); - return; - } - - npc_phantom_mageAI::UpdateAI(diff); - } - - void EnterEvadeMode(EvadeReason why) override - { - if (numOfUpd) - return; - - ScriptedAI::EnterEvadeMode(why); - if (me->IsSummon()) - me->ToTempSummon()->DespawnOrUnsummon(1ms); - } - }; -}; - -class npc_shadowy_mercenary : public CreatureScript -{ -public: - npc_shadowy_mercenary() : CreatureScript("npc_shadowy_mercenary") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); - } - - struct npc_shadowy_mercenaryAI: public ScriptedAI - { - npc_shadowy_mercenaryAI(Creature* c) : ScriptedAI(c) {} - - EventMap events; - - void DoAction(int32 a) override - { - if (a == 1) - { - me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + DoResetThreatList(); + me->AddThreat(target, 5000.0f); AttackStart(target); - } - } - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_SHADOW_STEP, 4s); - events.ScheduleEvent(EVENT_DEADLY_POISON, 6s); - events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10s); - events.ScheduleEvent(EVENT_KIDNEY_SHOT, 5s); - } - - void JustDied(Unit* /*killer*/) override - { - if (!urand(0,9)) - { - Talk(SAY_WAVE_DEATH); + DoCast(target, SPELL_SHADOW_STEP); } + events.ScheduleEvent(EVENT_SHADOW_STEP, 20s); + break; + case EVENT_DEADLY_POISON: + DoCastVictim(SPELL_DEADLY_POISON); + events.ScheduleEvent(EVENT_DEADLY_POISON, 4s); + break; + case EVENT_ENVENOMED_DAGGER_THROW: + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); + events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10s); + break; + case EVENT_KIDNEY_SHOT: + DoCastVictim(SPELL_KIDNEY_SHOT); + events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10s); + break; } - void AttackStart(Unit* who) override - { - if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return; - ScriptedAI::AttackStart(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SHADOW_STEP: - if (Unit* target = SelectTargetFromPlayerList(100.0f, 0, true)) - { - DoResetThreatList(); - me->AddThreat(target, 5000.0f); - AttackStart(target); - me->CastSpell(target, SPELL_SHADOW_STEP, false); - } - events.ScheduleEvent(EVENT_SHADOW_STEP, 20s); - break; - case EVENT_DEADLY_POISON: - me->CastSpell(me->GetVictim(), SPELL_DEADLY_POISON, false); - events.ScheduleEvent(EVENT_DEADLY_POISON, 4s); - break; - case EVENT_ENVENOMED_DAGGER_THROW: - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_ENVENOMED_DAGGER_THROW, false); - events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10s); - break; - case EVENT_KIDNEY_SHOT: - me->CastSpell(me->GetVictim(), SPELL_KIDNEY_SHOT, false); - events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10s); - break; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - } - } - }; -}; - -class npc_spectral_footman : public CreatureScript -{ -public: - npc_spectral_footman() : CreatureScript("npc_spectral_footman") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); + DoMeleeAttackIfReady(); } - struct npc_spectral_footmanAI: public ScriptedAI + void EnterEvadeMode(EvadeReason why) override { - npc_spectral_footmanAI(Creature* c) : ScriptedAI(c) {} - - EventMap events; - - void DoAction(int32 a) override + ScriptedAI::EnterEvadeMode(why); + if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) { - if (a == 1) - { - me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) - AttackStart(target); - } + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); } - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5s); - events.ScheduleEvent(EVENT_SHIELD_BASH, 6s); - events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15s); - } - - void JustDied(Unit* /*killer*/) override - { - if (!urand(0,9)) - { - Talk(SAY_WAVE_DEATH); - } - } - - void AttackStart(Unit* who) override - { - if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return; - ScriptedAI::AttackStart(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPECTRAL_STRIKE: - me->CastSpell(me->GetVictim(), SPELL_SPECTRAL_STRIKE, false); - events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5s); - break; - case EVENT_SHIELD_BASH: - me->CastSpell(me->GetVictim(), SPELL_SHIELD_BASH, false); - events.ScheduleEvent(EVENT_SHIELD_BASH, 6s); - break; - case EVENT_TORTURED_ENRAGE: - me->CastSpell(me, SPELL_TORTURED_ENRAGE, false); - events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15s); - break; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - } - } - }; -}; - -class npc_tortured_rifleman : public CreatureScript -{ -public: - npc_tortured_rifleman() : CreatureScript("npc_tortured_rifleman") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); - } - - struct npc_tortured_riflemanAI : public ScriptedAI - { - npc_tortured_riflemanAI(Creature* c) : ScriptedAI(c) {} - - EventMap events; - - void DoAction(int32 a) override - { - if (a == 1) - { - me->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) - AttackStart(target); - } - } - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_CURSED_ARROW, 10s); - events.ScheduleEvent(EVENT_FROST_TRAP, 15s); - events.ScheduleEvent(EVENT_ICE_SHOT, 15s); - } - - void JustDied(Unit* /*killer*/) override - { - if (!urand(0,9)) - { - Talk(SAY_WAVE_DEATH); - } - } - - void AttackStart(Unit* who) override - { - if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - return; - ScriptedAI::AttackStart(who); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_CURSED_ARROW: - me->CastSpell(me->GetVictim(), SPELL_CURSED_ARROW, false); - events.ScheduleEvent(EVENT_CURSED_ARROW, 10s); - break; - case EVENT_FROST_TRAP: - me->CastSpell((Unit*)nullptr, SPELL_FROST_TRAP, false); - events.ScheduleEvent(EVENT_FROST_TRAP, 30s); - break; - case EVENT_ICE_SHOT: - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_ICE_SHOT, false); - events.ScheduleEvent(EVENT_ICE_SHOT, 8s); - break; - } - - DoSpellAttackIfReady(SPELL_SHOOT); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - } - } - }; -}; - -class boss_frostsworn_general : public CreatureScript -{ -public: - boss_frostsworn_general() : CreatureScript("boss_frostsworn_general") { } - - struct boss_frostsworn_generalAI : public ScriptedAI - { - boss_frostsworn_generalAI(Creature* creature) : ScriptedAI(creature) - { - pInstance = creature->GetInstanceScript(); - } - - InstanceScript* pInstance; - EventMap events; - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_FROSTSWORN_GENERAL_AGGRO); - events.ScheduleEvent(EVENT_ACTIVATE_REFLECTIONS, 8s); - events.ScheduleEvent(EVENT_THROW_SHIELD, 6s); - pInstance->SetData(ACTION_SPIRITUAL_REFLECTIONS_COPY, 1); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - Position p = me->GetHomePosition(); - if (me->GetExactDist(&p) > 30.0f) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ACTIVATE_REFLECTIONS: - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_REFLECTIONS_DUMMY, false); - pInstance->SetData(ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE, 1); - break; - case EVENT_THROW_SHIELD: - if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) - me->CastSpell(target, SPELL_THROW_SHIELD, false); - events.ScheduleEvent(EVENT_THROW_SHIELD, 10s); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_FROSTSWORN_GENERAL_DEATH); - if (pInstance) - pInstance->SetData(DATA_FROSTSWORN_GENERAL, DONE); - } - - void EnterEvadeMode(EvadeReason why) override - { - pInstance->SetData(ACTION_SPIRITUAL_REFLECTIONS_HIDE, 1); - ScriptedAI::EnterEvadeMode(why); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHallsOfReflectionAI(creature); } }; -class npc_hor_spiritual_reflection : public CreatureScript +struct npc_spectral_footman: public ScriptedAI { -public: - npc_hor_spiritual_reflection() : CreatureScript("npc_hor_spiritual_reflection") { } + npc_spectral_footman(Creature* creature) : ScriptedAI(creature) {} - struct npc_hor_spiritual_reflectionAI : public ScriptedAI + void DoAction(int32 action) override { - npc_hor_spiritual_reflectionAI(Creature* creature) : ScriptedAI(creature) + if (action == 1) { + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + AttackStart(target); } + } - EventMap events; - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 4s, 7s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_BALEFUL_STRIKE: - me->CastSpell(me->GetVictim(), SPELL_BALEFUL_STRIKE, false); - events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 4s, 7s); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - me->CastSpell((Unit*)nullptr, SPELL_SPIRIT_BURST, false); - } - - void EnterEvadeMode(EvadeReason why) override - { - me->UpdatePosition(me->GetHomePosition(), true); - ScriptedAI::EnterEvadeMode(why); - me->SetVisible(false); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetHallsOfReflectionAI(creature); + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5s); + events.ScheduleEvent(EVENT_SHIELD_BASH, 6s); + events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15s); + } + + void JustDied(Unit* /*killer*/) override + { + if (!urand(0,9)) + Talk(SAY_WAVE_DEATH); + } + + void AttackStart(Unit* who) override + { + if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return; + ScriptedAI::AttackStart(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SPECTRAL_STRIKE: + DoCastVictim(SPELL_SPECTRAL_STRIKE); + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5s); + break; + case EVENT_SHIELD_BASH: + DoCastVictim(SPELL_SHIELD_BASH); + events.ScheduleEvent(EVENT_SHIELD_BASH, 6s); + break; + case EVENT_TORTURED_ENRAGE: + DoCastSelf(SPELL_TORTURED_ENRAGE); + events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15s); + break; + } + + DoMeleeAttackIfReady(); + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) + { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + } + } +}; + +struct npc_tortured_rifleman : public ScriptedAI +{ + npc_tortured_rifleman(Creature* creature) : ScriptedAI(creature) {} + + void DoAction(int32 action) override + { + if (action == 1) + { + me->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0f, true)) + AttackStart(target); + } + } + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_CURSED_ARROW, 10s); + events.ScheduleEvent(EVENT_FROST_TRAP, 15s); + events.ScheduleEvent(EVENT_ICE_SHOT, 15s); + } + + void JustDied(Unit* /*killer*/) override + { + if (!urand(0,9)) + Talk(SAY_WAVE_DEATH); + } + + void AttackStart(Unit* who) override + { + if (!me->IsVisible() || me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + return; + ScriptedAI::AttackStart(who); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_CURSED_ARROW: + DoCastVictim(SPELL_CURSED_ARROW); + events.ScheduleEvent(EVENT_CURSED_ARROW, 10s); + break; + case EVENT_FROST_TRAP: + DoCastAOE(SPELL_FROST_TRAP); + events.ScheduleEvent(EVENT_FROST_TRAP, 30s); + break; + case EVENT_ICE_SHOT: + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_ICE_SHOT); + events.ScheduleEvent(EVENT_ICE_SHOT, 8s); + break; + } + + DoSpellAttackIfReady(SPELL_SHOOT); + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (me->GetInstanceScript()->GetData(DATA_WAVE_NUMBER)) + { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + } + } +}; + +struct boss_frostsworn_general : public ScriptedAI +{ + boss_frostsworn_general(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_FROSTSWORN_GENERAL_AGGRO); + events.ScheduleEvent(EVENT_ACTIVATE_REFLECTIONS, 8s); + events.ScheduleEvent(EVENT_THROW_SHIELD, 6s); + instance->SetData(ACTION_SPIRITUAL_REFLECTIONS_COPY, 1); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + Position p = me->GetHomePosition(); + if (me->GetExactDist(&p) > 30.0f) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_ACTIVATE_REFLECTIONS: + DoCastAOE(SPELL_SUMMON_REFLECTIONS_DUMMY); + instance->SetData(ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE, 1); + break; + case EVENT_THROW_SHIELD: + if (Unit* target = SelectTargetFromPlayerList(40.0f, 0, true)) + DoCast(target, SPELL_THROW_SHIELD); + events.ScheduleEvent(EVENT_THROW_SHIELD, 10s); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_FROSTSWORN_GENERAL_DEATH); + if (instance) + instance->SetData(DATA_FROSTSWORN_GENERAL, DONE); + } + + void EnterEvadeMode(EvadeReason why) override + { + instance->SetData(ACTION_SPIRITUAL_REFLECTIONS_HIDE, 1); + ScriptedAI::EnterEvadeMode(why); + } +}; + +struct npc_hor_spiritual_reflection : public ScriptedAI +{ + npc_hor_spiritual_reflection(Creature* creature) : ScriptedAI(creature) {} + + void Reset() override + { + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 4s, 7s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_BALEFUL_STRIKE: + DoCastVictim(SPELL_BALEFUL_STRIKE); + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 4s, 7s); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + DoCastAOE(SPELL_SPIRIT_BURST); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->UpdatePosition(me->GetHomePosition(), true); + ScriptedAI::EnterEvadeMode(why); + me->SetVisible(false); } }; @@ -1611,7 +1470,7 @@ public: if (!inst) return false; - if (inst->GetData(DATA_FROSTSWORN_GENERAL) && !inst->GetData(DATA_LK_INTRO)) + if (inst->GetPersistentData(PERSISTENT_DATA_FROSTSWORN_GENERAL) && !inst->GetPersistentData(PERSISTENT_DATA_LK_INTRO)) inst->SetData(DATA_LK_INTRO, DONE); return false; @@ -1646,261 +1505,250 @@ enum eFightEvents EVENT_DECREASE_REQ_COUNT_BY_100, }; -class npc_hor_lich_king : public CreatureScript +struct npc_hor_lich_king : public NullCreatureAI { -public: - npc_hor_lich_king() : CreatureScript("npc_hor_lich_king") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_hor_lich_king(Creature* creature) : NullCreatureAI(creature), summons(me) { - return GetHallsOfReflectionAI(creature); + instance = me->GetInstanceScript(); + if (!instance) + me->IsAIEnabled = false; } - struct npc_hor_lich_kingAI : public NullCreatureAI + InstanceScript* instance; + EventMap events; + SummonList summons; + uint8 currentWall; + uint8 reqKillCount; + uint8 div2; + + void Reset() override { - npc_hor_lich_kingAI(Creature* creature) : NullCreatureAI(creature), summons(me) + currentWall = 0; + reqKillCount = 0; + events.Reset(); + events.RescheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); + } + void DoAction(int32 action) override + { + if (action == ACTION_START_LK_FIGHT_REAL) + events.ScheduleEvent(EVENT_LK_START_FOLLOWING, 1500ms); + else if ((action == ACTION_INFORM_TRASH_DIED && reqKillCount) || action == ACTION_CHECK_TRASH_DIED) { - pInstance = me->GetInstanceScript(); - if (!pInstance) - me->IsAIEnabled = false; - } - - InstanceScript* pInstance; - EventMap events; - SummonList summons; - uint8 currentWall; - uint8 reqKillCount; - uint8 div2; - - void Reset() override - { - currentWall = 0; - reqKillCount = 0; - events.Reset(); - events.RescheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); - } - void DoAction(int32 a) override - { - if (a == ACTION_START_LK_FIGHT_REAL) - events.ScheduleEvent(EVENT_LK_START_FOLLOWING, 1500ms); - else if ((a == ACTION_INFORM_TRASH_DIED && reqKillCount) || a == ACTION_CHECK_TRASH_DIED) + if ((action == ACTION_CHECK_TRASH_DIED && reqKillCount == 0) || (action == ACTION_INFORM_TRASH_DIED && (--reqKillCount) == 0)) { - if ((a == ACTION_CHECK_TRASH_DIED && reqKillCount == 0) || (a == ACTION_INFORM_TRASH_DIED && (--reqKillCount) == 0)) + events.CancelEvent(EVENT_DECREASE_REQ_COUNT_BY_100); // just in case, magic happens sometimes + ++currentWall; + instance->SetData(ACTION_DELETE_ICE_WALL, 1); + if (currentWall <= 3) { - events.CancelEvent(EVENT_DECREASE_REQ_COUNT_BY_100); // just in case, magic happens sometimes - ++currentWall; - pInstance->SetData(ACTION_DELETE_ICE_WALL, 1); - if (currentWall <= 3) + events.ScheduleEvent(EVENT_LK_SUMMON_NEXT_ICE_WALL, 1s); + events.ScheduleEvent(EVENT_LK_SUMMON, currentWall == 3 ? 11s : 7500ms); + } + else + me->RemoveAura(SPELL_REMORSELESS_WINTER); + if (Creature* c = instance->GetCreature(NPC_SYLVANAS_PART2)) + c->AI()->DoAction(ACTION_INFORM_WALL_DESTROYED); + } + } + } + + void MovementInform(uint32 type, uint32 /*id*/) override + { + // Xinef: dont use 0, it is no longer the last point + // Xinef: if type is escort and spline is finalized, it means that we reached last point from the path + if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized()) + { + if (currentWall == 0) + { + Talk(SAY_LK_IW_1); + me->SetOrientation(4.15f); + if (Creature* icewall = instance->instance->GetCreature(instance->GetGuidData(NPC_ICE_WALL_TARGET))) + { + me->SetFacingToObject(icewall); + me->CastSpell(icewall, SPELL_SUMMON_ICE_WALL); + events.ScheduleEvent(EVENT_LK_REMORSELESS_WINTER, 4s); + } + } + else if (currentWall == 4) + { + Talk(SAY_LK_NOWHERE_TO_RUN); + instance->SetData(DATA_LICH_KING, DONE); + } + } + } + + void JustSummoned(Creature* s) override + { + + ++reqKillCount; + if (events.HasTimeUntilEvent(EVENT_DECREASE_REQ_COUNT_BY_100)) + events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s); + summons.Summon(s); + s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]); + s->GetMotionMaster()->MovePoint(0, PathWaypoints[WP_STOP[currentWall + 1]]); + s->SetInCombatWithZone(); + if (Unit* target = s->SelectNearestPlayer(350.0f)) + { + s->AddThreat(target, 1000.0f); + s->AI()->AttackStart(target); + } + s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]); + } + + void SummonedCreatureDespawn(Creature* s) override + { + summons.Despawn(s); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && target->IsAlive() && spell->Id == SPELL_LICH_KING_ZAP_PLAYER) + Unit::DealDamage(me, target, 10000); + } + + void UpdateAI(uint32 diff) override + { + if (me->HealthBelowPct(70)) + me->SetHealth(me->GetMaxHealth() * 3 / 4); + + events.Update(diff); + + if (me->IsNonMeleeSpellCast(false, true, true)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_LK_CHECK_COMBAT: + if (me->isActiveObject()) // during fight + { + if (Creature* leader = instance->GetCreature(NPC_SYLVANAS_PART2)) + if (leader->IsAlive() && leader->GetPositionX() < 5575.0f && me->GetExactDist2d(leader) <= 12.5f && !leader->HasAura(SPELL_HARVEST_SOUL) && me->HasAura(SPELL_REMORSELESS_WINTER)) + { + me->GetMotionMaster()->MovementExpired(); + me->StopMoving(); + reqKillCount = 255; + leader->InterruptNonMeleeSpells(true); + me->CastSpell(leader, SPELL_HARVEST_SOUL); + events.ScheduleEvent(EVENT_LK_KILL_LEADER, 3s); + events.ScheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); + break; + } + if (instance->instance->HavePlayers()) { - events.ScheduleEvent(EVENT_LK_SUMMON_NEXT_ICE_WALL, 1s); - events.ScheduleEvent(EVENT_LK_SUMMON, currentWall == 3 ? 11s : 7500ms); + me->SetInCombatWithZone(); + ++div2; + if (div2 > 1) + { + div2 = 0; + if (me->HasAura(SPELL_REMORSELESS_WINTER)) // prevent going behind him during fight + { + Map::PlayerList const& pl = instance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + if (Player* p = itr->GetSource()) + if (!p->IsGameMaster() && p->IsAlive() && (p->GetPositionX() - me->GetPositionX() + p->GetPositionY() - me->GetPositionY()) > 20.0f) + me->CastSpell(p, SPELL_LICH_KING_ZAP_PLAYER, true); + } + } } else - me->RemoveAura(SPELL_REMORSELESS_WINTER); - if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_SYLVANAS_PART2))) - c->AI()->DoAction(ACTION_INFORM_WALL_DESTROYED); + { + summons.DespawnAll(); + instance->SetData(ACTION_STOP_LK_FIGHT, 1); + } } - } - } - - void MovementInform(uint32 type, uint32 /*id*/) override - { - // Xinef: dont use 0, it is no longer the last point - // Xinef: if type is escort and spline is finalized, it means that we reached last point from the path - if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized()) - { - if (currentWall == 0) + events.ScheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); + break; + case EVENT_LK_KILL_LEADER: + if (Creature* leader = instance->GetCreature(NPC_SYLVANAS_PART2)) { - Talk(SAY_LK_IW_1); - me->SetOrientation(4.15f); - if (Creature* icewall = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_ICE_WALL_TARGET))) - { - me->SetFacingToObject(icewall); - me->CastSpell(icewall, SPELL_SUMMON_ICE_WALL, false); - events.ScheduleEvent(EVENT_LK_REMORSELESS_WINTER, 4s); - } + leader->CastSpell(leader, SPELL_HOR_SUICIDE, true); + Unit::Kill(me, leader); + me->InterruptNonMeleeSpells(true); + DoCastAOE(SPELL_FURY_OF_FROSTMOURNE); } - else if (currentWall == 4) + break; + case EVENT_LK_START_FOLLOWING: { - Talk(SAY_LK_NOWHERE_TO_RUN); - pInstance->SetData(DATA_LICH_KING, DONE); + me->SetSpeed(MOVE_RUN, 9.0f / 7.0f); + Movement::PointsArray path; + path.emplace_back(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + for (uint8 i = 0; i <= 2; ++i) + path.emplace_back(PathWaypoints[i].GetPositionX(), PathWaypoints[i].GetPositionY(), PathWaypoints[i].GetPositionZ()); + me->GetMotionMaster()->MoveSplinePath(&path); } - } + break; + case EVENT_LK_REMORSELESS_WINTER: + { + me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run); + Talk(SAY_LK_WINTER); + DoCastSelf(SPELL_REMORSELESS_WINTER, true); + Movement::PointsArray path; + path.emplace_back(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + for (uint8 i = 3; i < PATH_WP_COUNT - 1; ++i) + path.emplace_back(PathWaypoints[i].GetPositionX(), PathWaypoints[i].GetPositionY(), PathWaypoints[i].GetPositionZ()); + me->GetMotionMaster()->MoveSplinePath(&path); + me->GetMotionMaster()->propagateSpeedChange(); + events.ScheduleEvent(EVENT_LK_SUMMON, 1s); + } + break; + case EVENT_LK_SUMMON: + switch (currentWall) + { + case 0: + events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 0ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4s); + break; + case 1: + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); + events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 100ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4s); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5100ms); + break; + case 2: + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); + events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 100ms); + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 4s); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4100ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5200ms); + break; + case 3: + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 100ms); + events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 1200ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5300ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 6400ms); + events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 12s + 500ms); + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 16s + 500ms); + events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 16s + 600ms); + events.ScheduleEvent(EVENT_LK_SUMMON_LA, 17s + 700ms); + break; + } + if (currentWall <= 3) + { + reqKillCount = 100; + events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s); + } + break; + case EVENT_DECREASE_REQ_COUNT_BY_100: + reqKillCount = (reqKillCount <= 100 ? 0 : reqKillCount - 100); + DoAction(ACTION_CHECK_TRASH_DIED); + break; + case EVENT_LK_SUMMON_GHOULS: + DoCastAOE(SPELL_SUMMON_RAGING_GHOULS); + break; + case EVENT_LK_SUMMON_RWD: + DoCastAOE(SPELL_SUMMON_RISEN_WITCH_DOCTOR); + break; + case EVENT_LK_SUMMON_LA: + DoCastAOE(SPELL_SUMMON_LUMBERING_ABOMINATION); + break; + case EVENT_LK_SUMMON_NEXT_ICE_WALL: + Talk(SAY_LK_IW_1 + currentWall); + if (Creature* c = instance->instance->GetCreature(instance->GetGuidData(NPC_ICE_WALL_TARGET + currentWall))) + me->CastSpell(c, SPELL_SUMMON_ICE_WALL); + break; } - - void JustSummoned(Creature* s) override - { - - ++reqKillCount; - if (events.HasTimeUntilEvent(EVENT_DECREASE_REQ_COUNT_BY_100)) - events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s); - summons.Summon(s); - s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]); - s->GetMotionMaster()->MovePoint(0, PathWaypoints[WP_STOP[currentWall + 1]]); - s->SetInCombatWithZone(); - if (Unit* target = s->SelectNearestPlayer(350.0f)) - { - s->AddThreat(target, 1000.0f); - s->AI()->AttackStart(target); - } - s->SetHomePosition(PathWaypoints[WP_STOP[currentWall + 1]]); - } - - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (target && target->IsAlive() && spell->Id == SPELL_LICH_KING_ZAP_PLAYER) - Unit::DealDamage(me, target, 10000); - } - - void UpdateAI(uint32 diff) override - { - if (me->HealthBelowPct(70)) - me->SetHealth(me->GetMaxHealth() * 3 / 4); - - events.Update(diff); - - if (me->IsNonMeleeSpellCast(false, true, true)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_LK_CHECK_COMBAT: - if (me->isActiveObject()) // during fight - { - if (Creature* leader = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_SYLVANAS_PART2))) - if (leader->IsAlive() && leader->GetPositionX() < 5575.0f && me->GetExactDist2d(leader) <= 12.5f && !leader->HasAura(SPELL_HARVEST_SOUL) && me->HasAura(SPELL_REMORSELESS_WINTER)) - { - me->GetMotionMaster()->MovementExpired(); - me->StopMoving(); - reqKillCount = 255; - leader->InterruptNonMeleeSpells(true); - me->CastSpell(leader, SPELL_HARVEST_SOUL, false); - events.ScheduleEvent(EVENT_LK_KILL_LEADER, 3s); - events.ScheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); - break; - } - if (pInstance->instance->HavePlayers()) - { - me->SetInCombatWithZone(); - ++div2; - if (div2 > 1) - { - div2 = 0; - if (me->HasAura(SPELL_REMORSELESS_WINTER)) // prevent going behind him during fight - { - Map::PlayerList const& pl = pInstance->instance->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - if (!p->IsGameMaster() && p->IsAlive() && (p->GetPositionX() - me->GetPositionX() + p->GetPositionY() - me->GetPositionY()) > 20.0f) - me->CastSpell(p, SPELL_LICH_KING_ZAP_PLAYER, true); - } - } - } - else - { - summons.DespawnAll(); - pInstance->SetData(ACTION_STOP_LK_FIGHT, 1); - } - } - events.ScheduleEvent(EVENT_LK_CHECK_COMBAT, 1s); - break; - case EVENT_LK_KILL_LEADER: - if (Creature* leader = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_SYLVANAS_PART2))) - { - leader->CastSpell(leader, SPELL_HOR_SUICIDE, true); - Unit::Kill(me, leader); - me->InterruptNonMeleeSpells(true); - me->CastSpell((Unit*)nullptr, SPELL_FURY_OF_FROSTMOURNE, false); - } - break; - case EVENT_LK_START_FOLLOWING: - { - me->SetSpeed(MOVE_RUN, 9.0f / 7.0f); - Movement::PointsArray path; - path.emplace_back(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - for (uint8 i = 0; i <= 2; ++i) - path.emplace_back(PathWaypoints[i].GetPositionX(), PathWaypoints[i].GetPositionY(), PathWaypoints[i].GetPositionZ()); - me->GetMotionMaster()->MoveSplinePath(&path); - } - break; - case EVENT_LK_REMORSELESS_WINTER: - { - me->SetSpeed(MOVE_RUN, me->GetCreatureTemplate()->speed_run); - Talk(SAY_LK_WINTER); - me->CastSpell(me, SPELL_REMORSELESS_WINTER, true); - Movement::PointsArray path; - path.emplace_back(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - for (uint8 i = 3; i < PATH_WP_COUNT - 1; ++i) - path.emplace_back(PathWaypoints[i].GetPositionX(), PathWaypoints[i].GetPositionY(), PathWaypoints[i].GetPositionZ()); - me->GetMotionMaster()->MoveSplinePath(&path); - me->GetMotionMaster()->propagateSpeedChange(); - events.ScheduleEvent(EVENT_LK_SUMMON, 1s); - } - break; - case EVENT_LK_SUMMON: - switch (currentWall) - { - case 0: - events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 0ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4s); - break; - case 1: - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); - events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 100ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4s); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5100ms); - break; - case 2: - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); - events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 100ms); - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 4s); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 4100ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5200ms); - break; - case 3: - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 0ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 100ms); - events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 1200ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 5300ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 6400ms); - events.ScheduleEvent(EVENT_LK_SUMMON_GHOULS, 12s + 500ms); - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 16s + 500ms); - events.ScheduleEvent(EVENT_LK_SUMMON_RWD, 16s + 600ms); - events.ScheduleEvent(EVENT_LK_SUMMON_LA, 17s + 700ms); - break; - } - if (currentWall <= 3) - { - reqKillCount = 100; - events.RescheduleEvent(EVENT_DECREASE_REQ_COUNT_BY_100, 10s); - } - break; - case EVENT_DECREASE_REQ_COUNT_BY_100: - reqKillCount = (reqKillCount <= 100 ? 0 : reqKillCount - 100); - DoAction(ACTION_CHECK_TRASH_DIED); - break; - case EVENT_LK_SUMMON_GHOULS: - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_RAGING_GHOULS, false); - break; - case EVENT_LK_SUMMON_RWD: - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_RISEN_WITCH_DOCTOR, false); - break; - case EVENT_LK_SUMMON_LA: - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_LUMBERING_ABOMINATION, false); - break; - case EVENT_LK_SUMMON_NEXT_ICE_WALL: - Talk(SAY_LK_IW_1 + currentWall); - if (Creature* c = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_ICE_WALL_TARGET + currentWall))) - me->CastSpell(c, SPELL_SUMMON_ICE_WALL, false); - break; - } - } - }; + } }; class npc_hor_leader_second : public CreatureScript @@ -1915,8 +1763,8 @@ public: ClearGossipMenuFor(player); - if (InstanceScript* pInstance = creature->GetInstanceScript()) - if (!pInstance->GetData(DATA_LICH_KING)) + if (InstanceScript* instance = creature->GetInstanceScript()) + if (instance->GetBossState(DATA_LICH_KING) != DONE) { creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); creature->AI()->DoAction(ACTION_START_LK_FIGHT_REAL); @@ -1935,13 +1783,13 @@ public: { npc_hor_leader_secondAI(Creature* creature) : NullCreatureAI(creature) { - pInstance = me->GetInstanceScript(); - if (!pInstance) + instance = me->GetInstanceScript(); + if (!instance) me->IsAIEnabled = false; } - InstanceScript* pInstance; + InstanceScript* instance; EventMap events; uint8 currentStopPoint; @@ -2004,63 +1852,57 @@ public: switch (events.ExecuteEvent()) { case EVENT_LK_SAY_AGGRO: - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) { - me->Attack(lkboss, true), - lkboss->AI()->Talk(me->GetEntry() == NPC_JAINA_PART2 ? SAY_LK_AGGRO_ALLY : SAY_LK_AGGRO_HORDE); + me->Attack(lichKing, true), + lichKing->AI()->Talk(me->GetEntry() == NPC_JAINA_PART2 ? SAY_LK_AGGRO_ALLY : SAY_LK_AGGRO_HORDE); } break; case EVENT_LK_BATTLE_1: - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) - { - lkboss->CastSpell(lkboss, SPELL_SOUL_REAPER, false); - } + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + lichKing->CastSpell(lichKing, SPELL_SOUL_REAPER); break; case EVENT_LK_BATTLE_2: //horda - if (Creature* leader = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_SYLVANAS_PART2))) - { + if (Creature* leader = instance->GetCreature(NPC_SYLVANAS_PART2)) leader->CastSpell(leader, SPELL_EVASION, true); - } - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + lichKing->SetFacingToObject(me); + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) { - lkboss->SetFacingToObject(me); - } - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) - { - lkboss->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); - me->SetFacingToObject(lkboss); + lichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); + me->SetFacingToObject(lichKing); } break; case EVENT_JAINA_IMMOBILIZE_LK: - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) { - lkboss->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY_SPELL_OMNI); + lichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY_SPELL_OMNI); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - me->CastSpell(lkboss, SPELL_JAINA_ICE_PRISON, false); + me->CastSpell(lichKing, SPELL_JAINA_ICE_PRISON); events.ScheduleEvent(EVENT_SAY_LEAVE, 5s); } break; case EVENT_SYLVANAS_IMMOBILIZE_JUMP: - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) { me->AttackStop(); me->SetSheath(SHEATH_STATE_MELEE); - lkboss->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY_SPELL_OMNI); - lkboss->CastSpell(me, SPELL_BLIDING_RETREAT, false); + lichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY_SPELL_OMNI); + lichKing->CastSpell(me, SPELL_BLIDING_RETREAT); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - me->KnockbackFrom(lkboss->GetPositionX(), lkboss->GetPositionY(), 34.3f, 4.0f); + me->KnockbackFrom(lichKing->GetPositionX(), lichKing->GetPositionY(), 34.3f, 4.0f); events.ScheduleEvent(EVENT_SYLVANAS_DARK_BINDING, 2s +500ms); } break; case EVENT_SYLVANAS_DARK_BINDING: - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) - me->CastSpell(lkboss, SPELL_SYLVANAS_DARK_BINDING, false); + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + me->CastSpell(lichKing, SPELL_SYLVANAS_DARK_BINDING); events.ScheduleEvent(EVENT_SAY_LEAVE, 2s); break; case EVENT_SAY_LEAVE: { - Map::PlayerList const& pl = pInstance->instance->GetPlayers(); + Map::PlayerList const& pl = instance->instance->GetPlayers(); for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) if (Player* p = itr->GetSource()) p->KilledMonsterCredit(me->GetEntry()); //for quest @@ -2079,15 +1921,15 @@ public: break; case EVENT_START_RUN: { - pInstance->SetData(ACTION_START_LK_FIGHT, 1); + instance->SetData(ACTION_START_LK_FIGHT, 1); me->setActive(true); MoveToNextStopPoint(); - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) { - lkboss->setActive(true); - lkboss->SetInCombatWithZone(); - lkboss->RemoveAura(me->GetEntry() == NPC_JAINA_PART2 ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING); - lkboss->AI()->DoAction(ACTION_START_LK_FIGHT_REAL); + lichKing->setActive(true); + lichKing->SetInCombatWithZone(); + lichKing->RemoveAura(me->GetEntry() == NPC_JAINA_PART2 ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING); + lichKing->AI()->DoAction(ACTION_START_LK_FIGHT_REAL); } } break; @@ -2114,7 +1956,7 @@ public: } Talk(textId); if (currentStopPoint <= 4) - me->CastSpell((Unit*)nullptr, (me->GetEntry() == NPC_JAINA_PART2 ? SPELL_DESTROY_WALL_JAINA : SPELL_DESTROY_WALL_SYLVANAS), false); + DoCastAOE(me->GetEntry() == NPC_JAINA_PART2 ? SPELL_DESTROY_WALL_JAINA : SPELL_DESTROY_WALL_SYLVANAS); else { me->SetFacingTo(PathWaypoints[PATH_WP_COUNT - 1].GetOrientation()); @@ -2131,192 +1973,149 @@ public: }; }; -class npc_hor_raging_ghoul : public CreatureScript +struct npc_hor_raging_ghoul : public ScriptedAI { -public: - npc_hor_raging_ghoul() : CreatureScript("npc_hor_raging_ghoul") { } + npc_hor_raging_ghoul(Creature* creature) : ScriptedAI(creature) {} - struct npc_hor_raging_ghoulAI : public ScriptedAI + bool leaped; + + void Reset() override { - npc_hor_raging_ghoulAI(Creature* creature) : ScriptedAI(creature) {} + leaped = false; + } - bool leaped; - - void Reset() override - { - leaped = false; - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - if (!leaped) - if (Unit* target = me->SelectNearestPlayer(30.0f)) - { - AttackStart(target); - me->CastSpell(target, 70150, false); - leaped = true; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - me->SetCorpseDelay(10); - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) - lkboss->AI()->DoAction(ACTION_INFORM_TRASH_DIED); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void UpdateAI(uint32 /*diff*/) override { - return GetHallsOfReflectionAI(creature); + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + if (!leaped) + if (Unit* target = me->SelectNearestPlayer(30.0f)) + { + AttackStart(target); + DoCast(target, SPELL_LEAP); + leaped = true; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + me->SetCorpseDelay(10); + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED); } }; -class npc_hor_risen_witch_doctor : public CreatureScript +struct npc_hor_risen_witch_doctor : public ScriptedAI { -public: - npc_hor_risen_witch_doctor() : CreatureScript("npc_hor_risen_witch_doctor") { } + npc_hor_risen_witch_doctor(Creature* creature) : ScriptedAI(creature) {} - struct npc_hor_risen_witch_doctorAI : public ScriptedAI + void Reset() override { - npc_hor_risen_witch_doctorAI(Creature* creature) : ScriptedAI(creature) {} + events.Reset(); + } - EventMap events; - - void Reset() override - { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(1, 10s); - events.ScheduleEvent(2, 4500ms); - events.ScheduleEvent(3, 9s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case 1: - if (Unit* target = SelectTargetFromPlayerList(30.0f, 0, true)) - me->CastSpell(target, 70144, false); - events.ScheduleEvent(1, 12s); - break; - case 2: - me->CastSpell(me->GetVictim(), 70080, false); - events.ScheduleEvent(2, 4500ms); - break; - case 3: - if (SelectTargetFromPlayerList(30.0f, 0, true)) - me->CastSpell(me->GetVictim(), 70145, false); - events.ScheduleEvent(3, 9s); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - me->SetCorpseDelay(10); - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) - { - lkboss->AI()->DoAction(ACTION_INFORM_TRASH_DIED); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetHallsOfReflectionAI(creature); + events.ScheduleEvent(1, 10s); + events.ScheduleEvent(2, 4500ms); + events.ScheduleEvent(3, 9s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) + { + case 1: + if (Unit* target = SelectTargetFromPlayerList(30.0f, 0, true)) + DoCast(target, SPELL_CURSE_OF_DOOM); + events.ScheduleEvent(1, 12s); + break; + case 2: + DoCastVictim(SPELL_SHADOW_BOLT_WD); + events.ScheduleEvent(2, 4500ms); + break; + case 3: + if (SelectTargetFromPlayerList(30.0f, 0, true)) + DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY); + events.ScheduleEvent(3, 9s); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + me->SetCorpseDelay(10); + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED); } }; -class npc_hor_lumbering_abomination : public CreatureScript +struct npc_hor_lumbering_abomination : public ScriptedAI { -public: - npc_hor_lumbering_abomination() : CreatureScript("npc_hor_lumbering_abomination") { } + npc_hor_lumbering_abomination(Creature* creature) : ScriptedAI(creature) {} - struct npc_hor_lumbering_abominationAI : public ScriptedAI + void Reset() override { - npc_hor_lumbering_abominationAI(Creature* creature) : ScriptedAI(creature) {} + events.Reset(); + } - EventMap events; + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(1, 5s); + } - void Reset() override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) + return; + + switch (events.ExecuteEvent()) { - events.Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(1, 5s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasFearAura() || me->IsCharmed() || me->isFrozen() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasUnitState(UNIT_STATE_CONFUSED)) - return; - - switch (events.ExecuteEvent()) - { - case 1: - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->CastSpell(me->GetVictim(), 70176, false); - events.ScheduleEvent(1, 18s); - } - else - events.ScheduleEvent(1, 3s); - break; - } - - if (me->GetVictim() && me->isAttackReady() && me->IsWithinMeleeRange(me->GetVictim()) && !me->HasUnitState(UNIT_STATE_CASTING)) - { - me->CastSpell(me->GetVictim(), 40505, false); - } - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - me->SetCorpseDelay(10); - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* lkboss = pInstance->instance->GetCreature(pInstance->GetGuidData(NPC_LICH_KING_BOSS))) + case 1: + if (me->IsWithinMeleeRange(me->GetVictim())) { - lkboss->AI()->DoAction(ACTION_INFORM_TRASH_DIED); + DoCastVictim(SPELL_VOMIT_SPRAY); + events.ScheduleEvent(1, 18s); } + else + events.ScheduleEvent(1, 3s); + break; } - }; - CreatureAI* GetAI(Creature* creature) const override + if (me->GetVictim() && me->isAttackReady() && me->IsWithinMeleeRange(me->GetVictim()) && !me->HasUnitState(UNIT_STATE_CASTING)) + DoCastVictim(SPELL_CLEAVE); + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override { - return GetHallsOfReflectionAI(creature); + me->SetCorpseDelay(10); + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* lichKing = instance->GetCreature(NPC_LICH_KING_BOSS)) + lichKing->AI()->DoAction(ACTION_INFORM_TRASH_DIED); } }; @@ -2339,9 +2138,7 @@ class spell_hor_gunship_cannon_fire_aura : public AuraScript PreventDefaultAction(); if (Unit* caster = GetCaster()) if (Creature* creature = caster->SummonCreature(WORLD_TRIGGER, CannonFirePos[caster->GetEntry() == NPC_JAINA_PART2 ? 0 : 1][urand(0, 2)], TEMPSUMMON_TIMED_DESPAWN, 1)) - { creature->CastSpell((Unit*)nullptr, SPELL_GUNSHIP_CANNON_FIRE, true); - } } void Register() override @@ -2359,7 +2156,7 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*areaTrigger*/) override { - if (player->HasAura(70013)) + if (player->HasAura(SPELL_QUELDELAR_COMPULSION)) if (InstanceScript* instance = player->GetInstanceScript()) instance->SetData(DATA_BATTERED_HILT, 2); return true; @@ -2373,13 +2170,13 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*areaTrigger*/) override { - if (player->HasAura(70013)) + if (player->HasAura(SPELL_QUELDELAR_COMPULSION)) if (InstanceScript* instance = player->GetInstanceScript()) { uint32 bhd = instance->GetData(DATA_BATTERED_HILT); if (bhd != BHSF_STARTED) return true; - player->CastSpell(player, 70698, true); + player->CastSpell(player, SPELL_QUELDELAR_WILL, true); player->DestroyItemCount(49766, 1, true); instance->SetData(DATA_BATTERED_HILT, 3); } @@ -2391,22 +2188,22 @@ void AddSC_halls_of_reflection() { new npc_hor_leader(); - new npc_ghostly_priest(); - new npc_phantom_mage(); - new npc_phantom_hallucination(); - new npc_shadowy_mercenary(); - new npc_spectral_footman(); - new npc_tortured_rifleman(); + RegisterHallsOfReflectionCreatureAI(npc_ghostly_priest); + RegisterHallsOfReflectionCreatureAI(npc_phantom_mage); + RegisterHallsOfReflectionCreatureAI(npc_phantom_hallucination); + RegisterHallsOfReflectionCreatureAI(npc_shadowy_mercenary); + RegisterHallsOfReflectionCreatureAI(npc_spectral_footman); + RegisterHallsOfReflectionCreatureAI(npc_tortured_rifleman); - new boss_frostsworn_general(); - new npc_hor_spiritual_reflection(); + RegisterHallsOfReflectionCreatureAI(boss_frostsworn_general); + RegisterHallsOfReflectionCreatureAI(npc_hor_spiritual_reflection); new at_hor_shadow_throne(); - new npc_hor_lich_king(); + RegisterHallsOfReflectionCreatureAI(npc_hor_lich_king); new npc_hor_leader_second(); - new npc_hor_raging_ghoul(); - new npc_hor_risen_witch_doctor(); - new npc_hor_lumbering_abomination(); + RegisterHallsOfReflectionCreatureAI(npc_hor_raging_ghoul); + RegisterHallsOfReflectionCreatureAI(npc_hor_risen_witch_doctor); + RegisterHallsOfReflectionCreatureAI(npc_hor_lumbering_abomination); RegisterSpellScript(spell_hor_gunship_cannon_fire_aura); new at_hor_battered_hilt_start(); 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 fb5a722c1e..dfd4c93c5d 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -44,6 +44,7 @@ enum Data ACTION_DELETE_ICE_WALL, DATA_WAVE_NUMBER, DATA_LK_BATTLE,// in progress + DATA_SHIP_CAPTAIN, }; enum Creatures @@ -108,6 +109,17 @@ enum BatteredHiltStatusFlags BHSF_FINISHED = 4, }; +enum HoRPersistentData +{ + PERSISTENT_DATA_INTRO, + PERSISTENT_DATA_FROSTSWORN_GENERAL, + PERSISTENT_DATA_LK_INTRO, + PERSISTENT_DATA_BATTERED_HILT, + PERSISTENT_DATA_COUNT +}; + +constexpr uint8 MAX_SPIRITUAL_REFLECTIONS = 5; +constexpr uint8 MAX_ICE_WALL_TARGETS = 4; #define NUM_OF_TRASH 34 #define MAX_DIST_FROM_CENTER_IN_COMBAT 70.5f #define MAX_DIST_FROM_CENTER_TO_START 40.0f @@ -291,6 +303,11 @@ enum hMisc // Battered Hilt - Summon Quel'Delar SPELL_SUMMON_EVIL_QUEL = 69966, + SPELL_QUEL_DELAR_HATRED = 70300, + SPELL_FROSTMOURNE_ALTAR_GLOW = 70720, + SPELL_UTHER_HOLY_LIGHT_VISUAL = 73036, + SPELL_QUELDELAR_COMPULSION = 70013, + SPELL_QUELDELAR_WILL = 70698, }; const uint32 allowedCompositions[8][5] = @@ -390,4 +407,7 @@ inline AI* GetHallsOfReflectionAI(T* obj) return GetInstanceAI(obj, HallsOfReflectionScriptName); } +#define RegisterHallsOfReflectionCreatureAI(ai_name) \ + RegisterCreatureAIWithFactory(ai_name, GetHallsOfReflectionAI) + #endif 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 261006135e..a1bd4554e3 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 @@ -46,12 +46,10 @@ public: case 3: _owner.CastSpell((Unit*)nullptr, SPELL_SUMMON_EVIL_QUEL, true); _owner.AI()->Talk(SAY_BATTERED_HILT_REALIZE); - if (InstanceScript* instance = _owner.GetInstanceScript()) - instance->SetData(DATA_BATTERED_HILT, 4); + if (InstanceScript* inst = _owner.GetInstanceScript()) + inst->SetData(DATA_BATTERED_HILT, 4); if (Creature* quel = _owner.FindNearestCreature(NPC_QUEL_DELAR, 50)) - { quel->AI()->Talk(EMOTE_QUEL_SPAWN); - } _owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, 4), 3500ms); break; case 4: @@ -64,26 +62,22 @@ public: _owner.SetStandState(UNIT_STAND_STATE_KNEEL); break; case 6: - if (InstanceScript* instance = _owner.GetInstanceScript()) - instance->SetData(DATA_BATTERED_HILT, 6); + if (InstanceScript* inst = _owner.GetInstanceScript()) + inst->SetData(DATA_BATTERED_HILT, 6); _owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, 7), 2s); break; case 7: - if (InstanceScript* instance = _owner.GetInstanceScript()) - { - instance->SetData(DATA_BATTERED_HILT, 7); - } + if (InstanceScript* inst = _owner.GetInstanceScript()) + inst->SetData(DATA_BATTERED_HILT, 7); if (Creature* quel = _owner.FindNearestCreature(NPC_QUEL_DELAR, 50)) - { quel->AI()->Talk(EMOTE_QUEL_PREPARE); - } _owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, 8), 4s); break; case 8: _owner.SetReactState(REACT_AGGRESSIVE); _owner.SetImmuneToAll(false); - if (InstanceScript* instance = _owner.GetInstanceScript()) - instance->SetData(DATA_BATTERED_HILT, 8); + if (InstanceScript* inst = _owner.GetInstanceScript()) + inst->SetData(DATA_BATTERED_HILT, 8); break; case 9: _owner.AI()->Talk(SAY_BATTERED_HILT_OUTRO1); @@ -102,22 +96,22 @@ public: _owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, _eventId + 1), 5s); break; case 13: - _owner.CastSpell((Unit*)nullptr, 73036, true); + _owner.CastSpell((Unit*)nullptr, SPELL_UTHER_HOLY_LIGHT_VISUAL, true); _owner.m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(_owner, _eventId + 1), 3s); break; case 14: - { - Position homePos = _owner.GetHomePosition(); - _owner.SetReactState(REACT_PASSIVE); - _owner.SetImmuneToAll(true); - _owner.SetVisible(false); - _owner.UpdatePosition(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation(), true); - _owner.StopMovingOnCurrentPos(); - _owner.GetMotionMaster()->Clear(); - if (InstanceScript* instance = _owner.GetInstanceScript()) - instance->SetData(DATA_BATTERED_HILT, 9); - } + { + Position homePos = _owner.GetHomePosition(); + _owner.SetReactState(REACT_PASSIVE); + _owner.SetImmuneToAll(true); + _owner.SetVisible(false); + _owner.UpdatePosition(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation(), true); + _owner.StopMovingOnCurrentPos(); + _owner.GetMotionMaster()->Clear(); + if (InstanceScript* inst = _owner.GetInstanceScript()) + inst->SetData(DATA_BATTERED_HILT, 9); break; + } } return true; } @@ -127,1073 +121,1012 @@ private: uint8 _eventId; }; -class instance_halls_of_reflection : public InstanceMapScript +ObjectData const creatureData[] = +{ + { NPC_FALRIC, DATA_FALRIC }, + { NPC_MARWYN, DATA_MARWYN }, + { NPC_SYLVANAS_PART1, NPC_SYLVANAS_PART1 }, + { NPC_DARK_RANGER_LORALEN, NPC_DARK_RANGER_LORALEN }, + { NPC_UTHER, NPC_UTHER }, + { NPC_LICH_KING_EVENT, NPC_LICH_KING_EVENT }, + { NPC_FROSTSWORN_GENERAL, NPC_FROSTSWORN_GENERAL }, + { NPC_LICH_KING_BOSS, NPC_LICH_KING_BOSS }, + { NPC_SYLVANAS_PART2, NPC_SYLVANAS_PART2 }, + { NPC_ALTAR_BUNNY, NPC_ALTAR_BUNNY }, + { NPC_QUEL_DELAR, NPC_QUEL_DELAR }, + { NPC_HIGH_CAPTAIN_JUSTIN_BARLETT, DATA_SHIP_CAPTAIN }, + { NPC_SKY_REAVER_KORM_BLACKSKAR, DATA_SHIP_CAPTAIN }, + { 0, 0 } +}; + +ObjectData const gameObjectData[] = +{ + { GO_FROSTMOURNE, GO_FROSTMOURNE }, + { GO_FROSTMOURNE_ALTAR, GO_FROSTMOURNE_ALTAR }, + { GO_FRONT_DOOR, GO_FRONT_DOOR }, + { GO_ARTHAS_DOOR, GO_ARTHAS_DOOR }, + { GO_CAVE_IN, GO_CAVE_IN }, + { GO_DOOR_BEFORE_THRONE, GO_DOOR_BEFORE_THRONE }, + { GO_DOOR_AFTER_THRONE, GO_DOOR_AFTER_THRONE }, + { GO_ICE_WALL, GO_ICE_WALL }, + { 0, 0 } +}; + +class instance_halls_of_reflection : public InstanceScript { public: - instance_halls_of_reflection() : InstanceMapScript("instance_halls_of_reflection", MAP_HALLS_OF_REFLECTION) { } - - InstanceScript* GetInstanceScript(InstanceMap* pMap) const override + instance_halls_of_reflection(Map* map) : InstanceScript(map) { - return new instance_halls_of_reflection_InstanceMapScript(pMap); + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + SetPersistentDataCount(PERSISTENT_DATA_COUNT); + LoadObjectData(creatureData, gameObjectData); } - struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript + void Initialize() override { - instance_halls_of_reflection_InstanceMapScript(Map* pMap) : InstanceScript(pMap) + std::fill(std::begin(_trashActive), std::end(_trashActive), false); + _trashCounter = 0; + std::memset(&_chosenComposition, 0, sizeof(_chosenComposition)); + _waveNumber = 0; + _nextWaveTimer = 0; + _playerCheckTimer = 5000; + _waveResumeTimer = 0; + _waveResumeStep = 0; + _falricPhaseComplete = false; + _remainingTrashKills = 0; + _isLichKingFightActive = false; + _batteredHiltStatus = 0; + _outroTimer = 0; + _outroStep = 0; + _transport = nullptr; + } + + bool IsEncounterInProgress() const override + { + return (instance->HavePlayers() && _waveNumber) || _isLichKingFightActive; + } + + void OnCreatureCreate(Creature* creature) override + { + InstanceScript::OnCreatureCreate(creature); + + switch (creature->GetEntry()) { - SetHeaders(DataHeader); - }; - - uint32 EncounterMask; - ObjectGuid NPC_FalricGUID; - ObjectGuid NPC_MarwynGUID; - ObjectGuid NPC_LichKingIntroGUID; - ObjectGuid NPC_LeaderIntroGUID; - ObjectGuid NPC_GuardGUID; - ObjectGuid NPC_UtherGUID; - ObjectGuid NPC_LichKingGUID; - ObjectGuid NPC_LeaderGUID; - ObjectGuid NPC_IceWallTargetGUID[4]; - ObjectGuid NPC_AltarBunnyGUID; - ObjectGuid NPC_QuelDelarGUID; - ObjectGuid NPC_ShipCaptainGUID; - ObjectGuid GO_FrostmourneGUID; - ObjectGuid GO_FrostmourneAltarGUID; - ObjectGuid GO_FrontDoorGUID; - ObjectGuid GO_ArthasDoorGUID; - ObjectGuid GO_CaveInGUID; - ObjectGuid GO_DoorBeforeThroneGUID; - ObjectGuid GO_DoorAfterThroneGUID; - ObjectGuid GO_IceWallGUID; - - ObjectGuid NPC_TrashGUID[NUM_OF_TRASH]; - bool TrashActive[NUM_OF_TRASH]; - uint8 TrashCounter; - uint32 chosenComposition[8][5]; - uint8 WaveNumber; - uint32 NextWaveTimer; - uint16 CheckPlayersTimer; - uint16 ResumeFirstEventTimer; - uint8 ResumeFirstEventStep; - bool bFinished5Waves; - uint8 reqKillCount; - bool IsDuringLKFight; - uint32 BatteredHiltStatus; - - ObjectGuid NPC_FrostswornGeneralGUID; - ObjectGuid NPC_SpiritualReflectionGUID[5]; - - uint32 outroTimer; - uint8 outroStep; - MotionTransport* T1; - - void Initialize() override - { - EncounterMask = 0; - memset(&TrashActive, 0, sizeof(TrashActive)); - TrashCounter = 0; - memset(&chosenComposition, 0, sizeof(chosenComposition)); - WaveNumber = 0; - NextWaveTimer = 0; - CheckPlayersTimer = 5000; - ResumeFirstEventTimer = 0; - ResumeFirstEventStep = 0; - bFinished5Waves = false; - reqKillCount = 0; - IsDuringLKFight = false; - BatteredHiltStatus = 0; - - outroTimer = 0; - outroStep = 0; - T1 = nullptr; - } - - bool IsEncounterInProgress() const override - { - return (instance->HavePlayers() && WaveNumber) || IsDuringLKFight; // during LK fight npcs are active and will unset this variable - } - - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_SYLVANAS_PART1: + case NPC_SYLVANAS_PART1: + creature->SetVisible(false); + creature->SetSpeed(MOVE_RUN, 1.1); + if (GetTeamIdInInstance() == TEAM_ALLIANCE) + creature->UpdateEntry(NPC_JAINA_PART1); + creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_DARK_RANGER_LORALEN: + creature->SetVisible(false); + if (GetTeamIdInInstance() == TEAM_ALLIANCE) + creature->UpdateEntry(NPC_ARCHMAGE_KORELN); + break; + case NPC_UTHER: + creature->SetVisible(false); + creature->SetReactState(REACT_PASSIVE); + break; + case NPC_LICH_KING_EVENT: + creature->SetVisible(false); + creature->SetReactState(REACT_PASSIVE); + creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_FALRIC: + creature->SetVisible(false); + creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_MARWYN: + creature->SetVisible(false); + creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: + if (_trashCounter < NUM_OF_TRASH) + _trashGUID[_trashCounter++] = creature->GetGUID(); + if (GetBossState(DATA_MARWYN) != DONE && !creature->IsAlive()) + creature->Respawn(); + creature->SetVisible(false); + break; + case NPC_FROSTSWORN_GENERAL: + if (GetBossState(DATA_MARWYN) != DONE) + { creature->SetVisible(false); - creature->SetSpeed(MOVE_RUN, 1.1); - NPC_LeaderIntroGUID = creature->GetGUID(); - if (GetTeamIdInInstance() == TEAM_ALLIANCE) - creature->UpdateEntry(NPC_JAINA_PART1); + creature->SetReactState(REACT_PASSIVE); + } + break; + case NPC_SPIRITUAL_REFLECTION: + for (uint8 i = 0; i < MAX_SPIRITUAL_REFLECTIONS; ++i) + if (!_spiritualReflectionGUID[i]) + { + _spiritualReflectionGUID[i] = creature->GetGUID(); + break; + } + creature->SetVisible(false); + break; + case NPC_LICH_KING_BOSS: + if (!GetPersistentData(PERSISTENT_DATA_FROSTSWORN_GENERAL)) + creature->SetVisible(false); + if (!GetPersistentData(PERSISTENT_DATA_LK_INTRO)) + { + creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); + creature->CastSpell(creature, SPELL_SOUL_REAPER, true); + } + else if (GetBossState(DATA_LICH_KING) != DONE) + creature->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature); + else + creature->SetVisible(false); + + creature->SetHealth((creature->GetMaxHealth() * 3) / 4); + creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_SYLVANAS_PART2: + if (!creature->IsAlive()) + creature->Respawn(); + creature->SetWalk(false); + creature->SetSheath(SHEATH_STATE_MELEE); + if (GetTeamIdInInstance() == TEAM_ALLIANCE) + creature->UpdateEntry(NPC_JAINA_PART2); + creature->SetHealth(creature->GetMaxHealth() / 20); + if (!GetPersistentData(PERSISTENT_DATA_FROSTSWORN_GENERAL)) + creature->SetVisible(false); + if (!GetPersistentData(PERSISTENT_DATA_LK_INTRO)) + { + creature->SetSheath(SHEATH_STATE_MELEE); + creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, GetTeamIdInInstance() == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); - creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + creature->CastSpell(creature, GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true); + } + else if (GetBossState(DATA_LICH_KING) != DONE) + { + creature->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + creature->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + creature->UpdatePosition(LeaderEscapePos, true); + creature->StopMovingOnCurrentPos(); + } + else + { + creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true); + creature->StopMovingOnCurrentPos(); + } + creature->SetSheath(SHEATH_STATE_MELEE); + creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + break; + case NPC_ICE_WALL_TARGET: + if (creature->GetPositionX() > 5525.0f) + _iceWallTargetGUID[0] = creature->GetGUID(); + else if (creature->GetPositionX() > 5475.0f) + _iceWallTargetGUID[1] = creature->GetGUID(); + else if (creature->GetPositionX() > 5400.0f) + _iceWallTargetGUID[2] = creature->GetGUID(); + else + _iceWallTargetGUID[3] = creature->GetGUID(); + break; + case NPC_QUEL_DELAR: + creature->SetReactState(REACT_PASSIVE); + break; + } + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_FROSTMOURNE: + HandleGameObject(ObjectGuid::Empty, false, go); + if (GetPersistentData(PERSISTENT_DATA_INTRO)) + go->SetPhaseMask(2, true); + break; + case GO_FRONT_DOOR: + HandleGameObject(ObjectGuid::Empty, true, go); + break; + case GO_ARTHAS_DOOR: + HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_MARWYN) == DONE, go); + break; + } + + InstanceScript::OnGameObjectCreate(go); + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_FALRIC: + if (_waveNumber) + { + if (state == NOT_STARTED) + HandleWaveWipe(); + else if (state == DONE) + _nextWaveTimer = 60000; + } + break; + case DATA_MARWYN: + if (_waveNumber) + { + if (state == NOT_STARTED) + HandleWaveWipe(); + else if (state == DONE) + { + HandleGameObject(GO_FRONT_DOOR, true); + HandleGameObject(GO_ARTHAS_DOOR, true); + if (Creature* general = GetCreature(NPC_FROSTSWORN_GENERAL)) + { + general->SetVisible(true); + general->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + general->SetReactState(REACT_AGGRESSIVE); + general->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + } + _waveNumber = 0; + DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 0); + + instance->DoForAllPlayers([](Player* player) + { + player->CastSpell(player, player->GetTeamId() == TEAM_ALLIANCE ? SPELL_HOR_START_QUEST_ALLY : SPELL_HOR_START_QUEST_HORDE, true); + }); + } + } + break; + case DATA_LICH_KING: + if (state == DONE) + { + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->setActive(false); + if (Creature* lichKing = GetCreature(NPC_LICH_KING_BOSS)) + lichKing->setActive(false); + _isLichKingFightActive = false; + _outroStep = 1; + _outroTimer = 0; + } + break; + } + + return true; + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case DATA_INTRO: + StorePersistentData(PERSISTENT_DATA_INTRO, 1); + StartNextWave(); + break; + case ACTION_SHOW_TRASH: + RandomizeCompositionsAndShow(); + break; + case DATA_FROSTSWORN_GENERAL: + StorePersistentData(PERSISTENT_DATA_FROSTSWORN_GENERAL, 1); + if (data == DONE) + { + if (Creature* lichKing = GetCreature(NPC_LICH_KING_BOSS)) + lichKing->SetVisible(true); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->SetVisible(true); + } + break; + case ACTION_SPIRITUAL_REFLECTIONS_COPY: + { + uint8 reflectionIdx = 0; + instance->DoForAllPlayers([&](Player* player) + { + if (reflectionIdx >= MAX_SPIRITUAL_REFLECTIONS || !player->IsAlive() || player->IsGameMaster()) + return; + Creature* reflection = instance->GetCreature(_spiritualReflectionGUID[reflectionIdx++]); + if (!reflection) + return; + if (!reflection->IsAlive()) + reflection->Respawn(); + reflection->SetCanFly(true); + reflection->SetDisableGravity(true); + reflection->SetVisible(true); + + Item* weapon = player->GetWeaponForAttack(BASE_ATTACK); + reflection->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon ? weapon->GetEntry() : 0); + weapon = player->GetWeaponForAttack(OFF_ATTACK); + reflection->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, weapon ? weapon->GetEntry() : 0); + weapon = player->GetWeaponForAttack(RANGED_ATTACK); + reflection->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, weapon ? weapon->GetEntry() : 0); + player->CastSpell(reflection, SPELL_HOR_CLONE, true); + player->CastSpell(reflection, SPELL_HOR_CLONE_NAME, true); + }); + break; + } + case ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE: + { + Creature* general = GetCreature(NPC_FROSTSWORN_GENERAL); + if (!general) break; - case NPC_DARK_RANGER_LORALEN: - creature->SetVisible(false); - NPC_GuardGUID = creature->GetGUID(); - if (GetTeamIdInInstance() == TEAM_ALLIANCE) - creature->UpdateEntry(NPC_ARCHMAGE_KORELN); - break; - case NPC_UTHER: - creature->SetVisible(false); - NPC_UtherGUID = creature->GetGUID(); - creature->SetReactState(REACT_PASSIVE); - break; - case NPC_LICH_KING_EVENT: - creature->SetVisible(false); - NPC_LichKingIntroGUID = creature->GetGUID(); - creature->SetReactState(REACT_PASSIVE); - creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - break; - case NPC_FALRIC: - creature->SetVisible(false); - NPC_FalricGUID = creature->GetGUID(); - creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - break; - case NPC_MARWYN: - creature->SetVisible(false); - NPC_MarwynGUID = creature->GetGUID(); - creature->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + for (uint8 i = 0; i < MAX_SPIRITUAL_REFLECTIONS; ++i) + if (Creature* reflection = instance->GetCreature(_spiritualReflectionGUID[i])) + if (reflection->IsVisible()) + { + reflection->SetInCombatWithZone(); + reflection->SetCanFly(false); + reflection->SetDisableGravity(false); + reflection->GetMotionMaster()->MoveJump(general->GetPositionX(), general->GetPositionY(), general->GetPositionZ(), 20.0f, 10.0f); + } + break; + } + case ACTION_SPIRITUAL_REFLECTIONS_HIDE: + for (uint8 i = 0; i < MAX_SPIRITUAL_REFLECTIONS; ++i) + if (Creature* reflection = instance->GetCreature(_spiritualReflectionGUID[i])) + reflection->AI()->EnterEvadeMode(); + break; + case DATA_LK_INTRO: + StorePersistentData(PERSISTENT_DATA_LK_INTRO, 1); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->AI()->DoAction(ACTION_START_INTRO); + break; + case ACTION_START_LK_FIGHT: + _isLichKingFightActive = true; + DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT); + DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT); + break; + case ACTION_STOP_LK_FIGHT: + if (!_isLichKingFightActive) break; + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + if (!leader->IsAlive()) + { + leader->Respawn(); + if (GetTeamIdInInstance() == TEAM_ALLIANCE) + leader->UpdateEntry(NPC_JAINA_PART2); + } + leader->GetThreatMgr().ClearAllThreat(); + leader->CombatStop(true); + leader->InterruptNonMeleeSpells(true); + leader->GetMotionMaster()->Clear(); + leader->GetMotionMaster()->MoveIdle(); + leader->UpdatePosition(LeaderEscapePos, true); + leader->StopMovingOnCurrentPos(); + leader->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + leader->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + leader->SetHealth(leader->GetMaxHealth() / 20); + leader->AI()->Reset(); + leader->setActive(false); + leader->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + leader->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + } + if (Creature* lichKing = GetCreature(NPC_LICH_KING_BOSS)) + { + lichKing->GetThreatMgr().ClearAllThreat(); + lichKing->CombatStop(true); + lichKing->InterruptNonMeleeSpells(true); + lichKing->GetMotionMaster()->Clear(); + lichKing->GetMotionMaster()->MoveIdle(); + lichKing->UpdatePosition(lichKing->GetHomePosition(), true); + lichKing->StopMovingOnCurrentPos(); + lichKing->RemoveAllAuras(); + lichKing->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, lichKing); + lichKing->AI()->Reset(); + lichKing->setActive(false); + lichKing->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + lichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + lichKing->SetSpeed(MOVE_RUN, lichKing->GetCreatureTemplate()->speed_run); + } + _isLichKingFightActive = false; + _outroTimer = 0; + _outroStep = 0; + [[fallthrough]]; + case ACTION_DELETE_ICE_WALL: + HandleGameObject(GO_ICE_WALL, true); + break; + case DATA_LICH_KING: + SetBossState(DATA_LICH_KING, static_cast(data)); + break; + case DATA_BATTERED_HILT: + { + if (GetPersistentData(PERSISTENT_DATA_BATTERED_HILT)) + return; + + switch (data) + { + case 1: + StorePersistentData(PERSISTENT_DATA_BATTERED_HILT, 1); + break; + case 2: + if (_batteredHiltStatus) + break; + _batteredHiltStatus |= BHSF_STARTED; + if (Creature* bunny = GetCreature(NPC_ALTAR_BUNNY)) + bunny->CastSpell(bunny, SPELL_FROSTMOURNE_ALTAR_GLOW, true); + if (Creature* uther = GetCreature(NPC_UTHER)) + uther->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*uther, 1), 3s); + break; + case 3: + if (!(_batteredHiltStatus & BHSF_STARTED) || (_batteredHiltStatus & BHSF_THROWN)) + break; + _batteredHiltStatus |= BHSF_THROWN; + if (Creature* uther = GetCreature(NPC_UTHER)) + uther->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*uther, 3), 5500ms); + break; + case 4: + if (Creature* quelDelar = GetCreature(NPC_QUEL_DELAR)) + { + quelDelar->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + quelDelar->SetSpeed(MOVE_RUN, 2.5f); + } + break; + case 5: + if (Creature* uther = GetCreature(NPC_UTHER)) + uther->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*uther, 6), 3s); + break; + case 6: + if (Creature* quelDelar = GetCreature(NPC_QUEL_DELAR)) + { + quelDelar->SetSpeed(MOVE_RUN, quelDelar->GetCreatureTemplate()->speed_run); + quelDelar->GetMotionMaster()->MoveLand(0, quelDelar->GetPositionX(), quelDelar->GetPositionY(), 707.70f, 7.0f); + } + break; + case 7: + if (Creature* quelDelar = GetCreature(NPC_QUEL_DELAR)) + { + quelDelar->SetReactState(REACT_AGGRESSIVE); + quelDelar->SetImmuneToAll(false); + quelDelar->RemoveAurasDueToSpell(SPELL_QUEL_DELAR_HATRED); + } + break; + case 8: + if (Creature* quelDelar = GetCreature(NPC_QUEL_DELAR)) + quelDelar->SetInCombatWithZone(); + break; + case 9: + StorePersistentData(PERSISTENT_DATA_BATTERED_HILT, 1); + _batteredHiltStatus |= BHSF_FINISHED; + break; + } + return; + } + } + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_WAVE_NUMBER: + return static_cast(_waveNumber); + case DATA_BATTERED_HILT: + return _batteredHiltStatus; + } + + return 0; + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case NPC_ICE_WALL_TARGET: + case NPC_ICE_WALL_TARGET + 1: + case NPC_ICE_WALL_TARGET + 2: + case NPC_ICE_WALL_TARGET + 3: + return _iceWallTargetGUID[type - NPC_ICE_WALL_TARGET]; + default: + return GetObjectGuid(type); + } + } + + void OnUnitDeath(Unit* unit) override + { + if (_waveNumber && _remainingTrashKills) + { + switch (unit->GetEntry()) + { case NPC_WAVE_MERCENARY: case NPC_WAVE_FOOTMAN: case NPC_WAVE_RIFLEMAN: case NPC_WAVE_PRIEST: case NPC_WAVE_MAGE: - if (TrashCounter < NUM_OF_TRASH) - NPC_TrashGUID[TrashCounter++] = creature->GetGUID(); - if (!(EncounterMask & (1 << DATA_MARWYN)) && !creature->IsAlive()) - creature->Respawn(); - creature->SetVisible(false); - break; - case NPC_FROSTSWORN_GENERAL: - if (!(EncounterMask & (1 << DATA_MARWYN))) - { - creature->SetVisible(false); - creature->SetReactState(REACT_PASSIVE); - } - NPC_FrostswornGeneralGUID = creature->GetGUID(); - break; - case NPC_SPIRITUAL_REFLECTION: - for (uint8 i = 0; i < 5; ++i) - if (!NPC_SpiritualReflectionGUID[i]) - { - NPC_SpiritualReflectionGUID[i] = creature->GetGUID(); - break; - } - creature->SetVisible(false); - break; - case NPC_LICH_KING_BOSS: - if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL))) - creature->SetVisible(false); - if (!(EncounterMask & (1 << DATA_LK_INTRO))) - { - creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); //the fight cannot be in the form of an emote, it is causing bugs - creature->CastSpell(creature, SPELL_SOUL_REAPER, true); - } - else if (!(EncounterMask & (1 << DATA_LICH_KING))) - creature->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature); - else - creature->SetVisible(false); - - NPC_LichKingGUID = creature->GetGUID(); - creature->SetHealth((creature->GetMaxHealth() * 3) / 4); - creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - break; - case NPC_SYLVANAS_PART2: - if (!creature->IsAlive()) - creature->Respawn(); - NPC_LeaderGUID = creature->GetGUID(); - creature->SetWalk(false); - creature->SetSheath(SHEATH_STATE_MELEE); - if (GetTeamIdInInstance() == TEAM_ALLIANCE) - creature->UpdateEntry(NPC_JAINA_PART2); - creature->SetWalk(false); - creature->SetHealth(creature->GetMaxHealth() / 20); - if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL))) - creature->SetVisible(false); - if (!(EncounterMask & (1 << DATA_LK_INTRO))) - { - creature->SetSheath(SHEATH_STATE_MELEE); - creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, GetTeamIdInInstance() == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); //the fight cannot be in the form of an emote, it is causing bugs. - creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); - creature->CastSpell(creature, GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true); - } - else if (!(EncounterMask & (1 << DATA_LICH_KING))) - { - creature->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - creature->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - creature->UpdatePosition(LeaderEscapePos, true); - creature->StopMovingOnCurrentPos(); - } - else - { - creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true); - creature->StopMovingOnCurrentPos(); - } - creature->SetSheath(SHEATH_STATE_MELEE); - creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - break; - case NPC_ICE_WALL_TARGET: - if (creature->GetPositionX() > 5525.0f) - NPC_IceWallTargetGUID[0] = creature->GetGUID(); - else if (creature->GetPositionX() > 5475.0f) - NPC_IceWallTargetGUID[1] = creature->GetGUID(); - else if (creature->GetPositionX() > 5400.0f) - NPC_IceWallTargetGUID[2] = creature->GetGUID(); - else - NPC_IceWallTargetGUID[3] = creature->GetGUID(); - break; - case NPC_ALTAR_BUNNY: - NPC_AltarBunnyGUID = creature->GetGUID(); - break; - case NPC_QUEL_DELAR: - NPC_QuelDelarGUID = creature->GetGUID(); - creature->SetReactState(REACT_PASSIVE); - break; - case NPC_HIGH_CAPTAIN_JUSTIN_BARLETT: - case NPC_SKY_REAVER_KORM_BLACKSKAR: - NPC_ShipCaptainGUID = creature->GetGUID(); + if ((--_remainingTrashKills) == 0 && _waveNumber % 5 && _nextWaveTimer > 5000) + _nextWaveTimer = 5000; break; } } - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) + if (unit->GetEntry() == NPC_QUEL_DELAR) + if (Creature* uther = GetCreature(NPC_UTHER)) { - case GO_FROSTMOURNE: - GO_FrostmourneGUID = go->GetGUID(); - HandleGameObject(ObjectGuid::Empty, false, go); - if (EncounterMask & (1 << DATA_INTRO)) - go->SetPhaseMask(2, true); - break; - case GO_FROSTMOURNE_ALTAR: - GO_FrostmourneAltarGUID = go->GetGUID(); - break; - case GO_FRONT_DOOR: - GO_FrontDoorGUID = go->GetGUID(); - HandleGameObject(ObjectGuid::Empty, true, go); - break; - case GO_ARTHAS_DOOR: - GO_ArthasDoorGUID = go->GetGUID(); - HandleGameObject(ObjectGuid::Empty, (EncounterMask & (1 << DATA_MARWYN)), go); - break; - case GO_CAVE_IN: - GO_CaveInGUID = go->GetGUID(); - break; - case GO_DOOR_BEFORE_THRONE: - GO_DoorBeforeThroneGUID = go->GetGUID(); - break; - case GO_DOOR_AFTER_THRONE: - GO_DoorAfterThroneGUID = go->GetGUID(); - break; - case GO_ICE_WALL: - GO_IceWallGUID = go->GetGUID(); - break; + uther->SetStandState(UNIT_STAND_STATE_STAND); + uther->SetWalk(false); + uther->GetMotionMaster()->MovePoint(0, 5313.92f, 1989.36f, 707.70f); + uther->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*uther, 9), 7s); } - } + } - void SetData(uint32 type, uint32 data) override + void RandomizeCompositionsAndShow() + { + uint8 r1 = urand(0, 1); + uint8 r2 = urand(2, 3); + for (uint8 i = 0; i < MAX_SPIRITUAL_REFLECTIONS; ++i) { - switch (type) - { - case DATA_INTRO: - EncounterMask |= (1 << DATA_INTRO); - AddWave1(); - break; - case ACTION_SHOW_TRASH: - RandomizeCompositionsAndShow(); - break; - case DATA_FALRIC: - if (WaveNumber) - { - if (data == NOT_STARTED) - DoWipe1(); - else if (data == DONE) - { - NextWaveTimer = 60000; - EncounterMask |= (1 << DATA_FALRIC); - } - } - break; - case DATA_MARWYN: - if (WaveNumber) - { - if (data == NOT_STARTED) - DoWipe1(); - else if (data == DONE) - { - EncounterMask |= (1 << DATA_MARWYN); - HandleGameObject(GO_FrontDoorGUID, true); - HandleGameObject(GO_ArthasDoorGUID, true); - if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID)) - { - c->SetVisible(true); - c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - c->SetReactState(REACT_AGGRESSIVE); - } - if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID)) - { - c->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - } - WaveNumber = 0; - DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 0); - - // give quest - Map::PlayerList const& pl = instance->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - p->CastSpell(p, p->GetTeamId() == TEAM_ALLIANCE ? SPELL_HOR_START_QUEST_ALLY : SPELL_HOR_START_QUEST_HORDE, true); - } - } - break; - case DATA_FROSTSWORN_GENERAL: - EncounterMask |= (1 << DATA_FROSTSWORN_GENERAL); - if (data == DONE) - { - if (Creature* c = instance->GetCreature(NPC_LichKingGUID)) - c->SetVisible(true); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->SetVisible(true); - } - break; - case ACTION_SPIRITUAL_REFLECTIONS_COPY: - { - uint8 i = 0; - Map::PlayerList const& pl = instance->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - if (p->IsAlive() && !p->IsGameMaster()) - if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i++])) - { - if (!c->IsAlive()) - c->Respawn(); - c->SetCanFly(true); - c->SetDisableGravity(true); - c->SetVisible(true); - - Item* i; - i = p->GetWeaponForAttack(BASE_ATTACK); - c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, i ? i->GetEntry() : 0); - i = p->GetWeaponForAttack(OFF_ATTACK); - c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, i ? i->GetEntry() : 0); - i = p->GetWeaponForAttack(RANGED_ATTACK); - c->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, i ? i->GetEntry() : 0); - p->CastSpell(c, SPELL_HOR_CLONE, true); - p->CastSpell(c, SPELL_HOR_CLONE_NAME, true); - } - } - break; - case ACTION_SPIRITUAL_REFLECTIONS_ACTIVATE: - if (Creature* fg = instance->GetCreature(NPC_FrostswornGeneralGUID)) - for (uint8 i = 0; i < 5; ++i) - if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i])) - if (c->IsVisible()) - { - c->SetInCombatWithZone(); - c->SetCanFly(false); - c->SetDisableGravity(false); - c->GetMotionMaster()->MoveJump(fg->GetPositionX(), fg->GetPositionY(), fg->GetPositionZ(), 20.0f, 10.0f); - } - break; - case ACTION_SPIRITUAL_REFLECTIONS_HIDE: - for (uint8 i = 0; i < 5; ++i) - if (Creature* c = instance->GetCreature(NPC_SpiritualReflectionGUID[i])) - c->AI()->EnterEvadeMode(); - break; - case DATA_LK_INTRO: - EncounterMask |= (1 << DATA_LK_INTRO); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->AI()->DoAction(ACTION_START_INTRO); - break; - case ACTION_START_LK_FIGHT: - IsDuringLKFight = true; - DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT); - DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_RETREATING_TIMED_EVENT); - break; - case ACTION_STOP_LK_FIGHT: - if (!IsDuringLKFight) + _chosenComposition[0][i] = allowedCompositions[r1][i]; + _chosenComposition[1][i] = allowedCompositions[r1 == 0 ? 1 : 0][i]; + _chosenComposition[2][i] = allowedCompositions[r2][i]; + _chosenComposition[3][i] = allowedCompositions[r2 == 2 ? 3 : 2][i]; + } + bool left[4] = {true, true, true, true}; + for (uint8 k = 4; k > 0; --k) + { + uint8 r = urand(0, k - 1); + uint8 ur = 0; + for (uint8 j = 0; j < 4; ++j) + if (left[j]) + { + if (ur == r) { + left[j] = false; + for (uint8 i = 0; i < MAX_SPIRITUAL_REFLECTIONS; ++i) + _chosenComposition[8 - k][i] = allowedCompositions[j + 4][i]; break; } - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - { - if (!c->IsAlive()) - { - c->Respawn(); - if (GetTeamIdInInstance() == TEAM_ALLIANCE) - c->UpdateEntry(NPC_JAINA_PART2); - } - c->GetThreatMgr().ClearAllThreat(); - c->CombatStop(true); - c->InterruptNonMeleeSpells(true); - c->GetMotionMaster()->Clear(); - c->GetMotionMaster()->MoveIdle(); - c->UpdatePosition(LeaderEscapePos, true); - c->StopMovingOnCurrentPos(); - c->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - c->SetHealth(c->GetMaxHealth() / 20); - c->AI()->Reset(); - c->setActive(false); - c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - } - if (Creature* c = instance->GetCreature(NPC_LichKingGUID)) - { - c->GetThreatMgr().ClearAllThreat(); - c->CombatStop(true); - c->InterruptNonMeleeSpells(true); - c->GetMotionMaster()->Clear(); - c->GetMotionMaster()->MoveIdle(); - c->UpdatePosition(c->GetHomePosition(), true); - c->StopMovingOnCurrentPos(); - c->RemoveAllAuras(); - c->AddAura(GetTeamIdInInstance() == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, c); - c->AI()->Reset(); - c->setActive(false); - c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - c->SetSpeed(MOVE_RUN, c->GetCreatureTemplate()->speed_run); - } - IsDuringLKFight = false; - outroTimer = 0; - outroStep = 0; - [[fallthrough]]; - case ACTION_DELETE_ICE_WALL: - HandleGameObject(GO_IceWallGUID, true); - GO_IceWallGUID.Clear(); - break; - case DATA_LICH_KING: - if (data == DONE) - { - EncounterMask |= (1 << DATA_LICH_KING); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->setActive(false); - if (Creature* c = instance->GetCreature(NPC_LichKingGUID)) - c->setActive(false); - IsDuringLKFight = false; - outroStep = 1; - outroTimer = 0; - } - break; - case DATA_BATTERED_HILT: - { - if (EncounterMask & (1 << DATA_BATTERED_HILT)) - return; - - switch (data) - { - case 1: // talked to leader - EncounterMask |= (1 << DATA_BATTERED_HILT); - SaveToDB(); - break; - case 2: - if (BatteredHiltStatus) - break; - BatteredHiltStatus |= BHSF_STARTED; - if (Creature* c = instance->GetCreature(NPC_AltarBunnyGUID)) - c->CastSpell(c, 70720, true); - if (Creature* c = instance->GetCreature(NPC_UtherGUID)) - c->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*c, 1), 3s); - break; - case 3: - if ((BatteredHiltStatus & BHSF_STARTED) == 0 || (BatteredHiltStatus & BHSF_THROWN)) - break; - BatteredHiltStatus |= BHSF_THROWN; - if (Creature* c = instance->GetCreature(NPC_UtherGUID)) - { - c->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*c, 3), 5500ms); - } - break; - case 4: - if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID)) - { - c->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); - c->SetSpeed(MOVE_RUN, 2.5f); - } - break; - case 5: - if (Creature* c = instance->GetCreature(NPC_UtherGUID)) - c->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*c, 6), 3s); - break; - case 6: - if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID)) - { - c->SetSpeed(MOVE_RUN, c->GetCreatureTemplate()->speed_run); - c->GetMotionMaster()->MoveLand(0, c->GetPositionX(), c->GetPositionY(), 707.70f, 7.0f); - } - break; - case 7: - if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID)) - { - c->SetReactState(REACT_AGGRESSIVE); - c->SetImmuneToAll(false); - c->RemoveAurasDueToSpell(70300); - } - break; - case 8: - if (Creature* c = instance->GetCreature(NPC_QuelDelarGUID)) - c->SetInCombatWithZone(); - break; - case 9: - EncounterMask |= (1 << DATA_BATTERED_HILT); - BatteredHiltStatus |= BHSF_FINISHED; - SaveToDB(); - break; - } - } - return; - } - - if (data == DONE) - SaveToDB(); - } - - uint32 GetData(uint32 type) const override - { - switch (type) - { - case DATA_INTRO: - case DATA_FALRIC: - case DATA_MARWYN: - case DATA_FROSTSWORN_GENERAL: - case DATA_LK_INTRO: - case DATA_LICH_KING: - return EncounterMask & (1 << type); - case DATA_WAVE_NUMBER: - return (uint32)WaveNumber; - case DATA_BATTERED_HILT: - return BatteredHiltStatus; - } - - return 0; - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case NPC_DARK_RANGER_LORALEN: - return NPC_GuardGUID; - case NPC_LICH_KING_EVENT: - return NPC_LichKingIntroGUID; - case NPC_UTHER: - return NPC_UtherGUID; - case DATA_FALRIC: - return NPC_FalricGUID; - case DATA_MARWYN: - return NPC_MarwynGUID; - case NPC_LICH_KING_BOSS: - return NPC_LichKingGUID; - case NPC_SYLVANAS_PART2: - return NPC_LeaderGUID; - case NPC_ICE_WALL_TARGET: - case NPC_ICE_WALL_TARGET+1: - case NPC_ICE_WALL_TARGET+2: - case NPC_ICE_WALL_TARGET+3: - return NPC_IceWallTargetGUID[type - NPC_ICE_WALL_TARGET]; - case GO_FROSTMOURNE: - return GO_FrostmourneGUID; - case GO_ARTHAS_DOOR: - return GO_ArthasDoorGUID; - case GO_FRONT_DOOR: - return GO_FrontDoorGUID; - } - return ObjectGuid::Empty; - } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> EncounterMask; - BatteredHiltStatus = (EncounterMask & (1 << DATA_BATTERED_HILT)) ? BHSF_FINISHED : BHSF_NONE; - } - - void WriteSaveDataMore(std::ostringstream& data) override - { - data << EncounterMask; - } - - void OnUnitDeath(Unit* unit) override - { - if (WaveNumber && reqKillCount) - if (unit->GetEntry() == NPC_WAVE_MERCENARY || unit->GetEntry() == NPC_WAVE_FOOTMAN || unit->GetEntry() == NPC_WAVE_RIFLEMAN || unit->GetEntry() == NPC_WAVE_PRIEST || unit->GetEntry() == NPC_WAVE_MAGE) - if ((--reqKillCount) == 0 && WaveNumber % 5 && NextWaveTimer > 5000) - NextWaveTimer = 5000; - - if (unit->GetEntry() == NPC_QUEL_DELAR) - if (Creature* c = instance->GetCreature(NPC_UtherGUID)) - { - c->SetStandState(UNIT_STAND_STATE_STAND); - c->SetWalk(false); - c->GetMotionMaster()->MovePoint(0, 5313.92f, 1989.36f, 707.70f); - c->m_Events.AddEventAtOffset(new UtherBatteredHiltEvent(*c, 9), 7s); + ++ur; } } - - void RandomizeCompositionsAndShow() + if (_falricPhaseComplete) { - uint8 r1 = urand(0, 1), r2 = urand(2, 3); - for (uint8 i = 0; i < 5; ++i) + for (; _waveNumber < 4; ++_waveNumber) { - chosenComposition[0][i] = allowedCompositions[r1][i]; - chosenComposition[1][i] = allowedCompositions[r1 == 0 ? 1 : 0][i]; - chosenComposition[2][i] = allowedCompositions[r2][i]; - chosenComposition[3][i] = allowedCompositions[r2 == 2 ? 3 : 2][i]; - } - bool left[4] = {true, true, true, true}; - for (uint8 k = 4; k > 0; --k) - { - uint8 r = urand(0, k - 1); - uint8 ur = 0; - for (uint8 j = 0; j < 4; ++j) - if (left[j]) - { - if (ur == r) - { - left[j] = false; - for (uint8 i = 0; i < 5; ++i) - chosenComposition[8 - k][i] = allowedCompositions[j + 4][i]; - break; - } - ++ur; - } - } - if (bFinished5Waves) - { - for (; WaveNumber < 4; ++WaveNumber) + uint8 numToActivate = (_waveNumber <= 1) ? 3 : 4; + + for (uint8 i = 0; i < numToActivate; ++i) { - uint8 num_to_activate; - if (WaveNumber <= 1) - num_to_activate = 3; - else - num_to_activate = 4; - - for (uint8 i = 0; i < num_to_activate; ++i) - { - uint32 entry = chosenComposition[WaveNumber][i]; - bool forward = !!urand(0, 1); - for (int8 j = (forward ? 0 : NUM_OF_TRASH - 1); (forward ? j= 0); (forward ? ++j : --j)) - if (!TrashActive[j]) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[j])) - if (c->GetEntry() == entry) - { - TrashActive[j] = true; - Unit::Kill(c, c); - break; - } - } - } - WaveNumber = 5; - } - - for (uint8 i = 0; i < NUM_OF_TRASH; ++i) - if (!TrashActive[i]) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[i])) - { - c->SetVisible(true); - c->CastSpell(c, SPELL_WELL_OF_SOULS_VISUAL, false); - } - } - - void AddWave1() - { - if (WaveNumber >= 10) - return; - - ++WaveNumber; - if (WaveNumber >= 6) - bFinished5Waves = true; - - DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 1); - DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVE_COUNT, WaveNumber); - HandleGameObject(GO_FrontDoorGUID, false); - - // some of them could go back to spawn due to vanish, etc. - // on activating next wave make those attack again - for (uint8 i = 0; i < NUM_OF_TRASH; ++i) - if (TrashActive[i]) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[i])) - if (c->IsAlive() && !c->IsInCombat()) - c->AI()->DoAction(1); - - if (WaveNumber == 5 || WaveNumber == 10) - { - NextWaveTimer = 0; - if (WaveNumber == 5) - { - if (Creature* falric = instance->GetCreature(NPC_FalricGUID)) - { - if (falric->IsAlive()) - falric->AI()->DoAction(1); - else - NextWaveTimer = 1; - } - } - else - { - if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID)) - if (marwyn->IsAlive()) // should always be true, but just in case - marwyn->AI()->DoAction(1); - } - } - else - { - NextWaveTimer = 150000; - - uint8 num_to_activate = 5; - if (WaveNumber <= 2) - num_to_activate = 3; - else if (WaveNumber <= 4) - num_to_activate = 4; - reqKillCount += num_to_activate; - for (uint8 i = 0; i < num_to_activate; ++i) - { - uint32 entry = chosenComposition[WaveNumber - (WaveNumber > 5 ? 2 : 1)][i]; + uint32 entry = _chosenComposition[_waveNumber][i]; bool forward = !!urand(0, 1); - for (int8 j = (forward ? 0 : NUM_OF_TRASH - 1); (forward ? j= 0); (forward ? ++j : --j)) - if (!TrashActive[j]) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[j])) + for (int8 j = (forward ? 0 : NUM_OF_TRASH - 1); (forward ? j < NUM_OF_TRASH : j >= 0); (forward ? ++j : --j)) + if (!_trashActive[j]) + if (Creature* c = instance->GetCreature(_trashGUID[j])) if (c->GetEntry() == entry) { - TrashActive[j] = true; - c->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - c->SetImmuneToAll(false); - c->AI()->DoAction(1); + _trashActive[j] = true; + Unit::Kill(c, c); break; } } } + _waveNumber = 5; } - void DoWipe1() - { - if (!WaveNumber) - return; - - DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 0); - DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVE_COUNT, 0); - HandleGameObject(GO_FrontDoorGUID, true); - - TrashCounter = NUM_OF_TRASH; - WaveNumber = 0; - NextWaveTimer = 0; - memset(&chosenComposition, 0, sizeof(chosenComposition)); - - for (uint8 i = 0; i < NUM_OF_TRASH; ++i) - if (TrashActive[i]) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[i])) - { - c->GetThreatMgr().ClearAllThreat(); - c->CombatStop(true); - c->InterruptNonMeleeSpells(true); - c->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - c->SetImmuneToAll(true); - c->Respawn(true); - c->UpdatePosition(c->GetHomePosition(), true); - c->StopMovingOnCurrentPos(); - } - memset(&TrashActive, 0, sizeof(TrashActive)); - if (Creature* falric = instance->GetCreature(NPC_FalricGUID)) - falric->AI()->EnterEvadeMode(); - if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID)) - marwyn->AI()->EnterEvadeMode(); - - ResumeFirstEventTimer = 5000; - ResumeFirstEventStep = 2; - reqKillCount = 0; - } - - void Update(uint32 diff) override - { - if (!instance->HavePlayers()) - return; - - if (CheckPlayersTimer <= diff) - { - CheckPlayersTimer = 5000; - if ((EncounterMask & (1 << DATA_INTRO)) && !(EncounterMask & (1 << DATA_MARWYN))) // first event + for (uint8 i = 0; i < NUM_OF_TRASH; ++i) + if (!_trashActive[i]) + if (Creature* c = instance->GetCreature(_trashGUID[i])) { - Map::PlayerList const& pl = instance->GetPlayers(); - if (WaveNumber || NextWaveTimer) - { - bool allDead = true; - bool outOfRange = false; - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - { - if (p->IsGameMaster()) - continue; - if (p->IsAlive()) - allDead = false; - if (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_IN_COMBAT) - { - outOfRange = true; - break; - } - } - if (allDead || outOfRange) - DoWipe1(); - } - else if (!ResumeFirstEventTimer) - { - bool allInRangeAndAlive = (instance->GetPlayersCountExceptGMs() > 0); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* p = itr->GetSource()) - if (!p->IsGameMaster() && (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_TO_START || !p->IsAlive())) - { - allInRangeAndAlive = false; - break; - } - if (allInRangeAndAlive) - { - ResumeFirstEventTimer = 1; - ResumeFirstEventStep = 0; - } - } + c->SetVisible(true); + c->CastSpell(c, SPELL_WELL_OF_SOULS_VISUAL, false); + } + } + + void StartNextWave() + { + if (_waveNumber >= 10) + return; + + ++_waveNumber; + if (_waveNumber >= 6) + _falricPhaseComplete = true; + + DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVE_COUNT, _waveNumber); + HandleGameObject(GO_FRONT_DOOR, false); + + for (uint8 i = 0; i < NUM_OF_TRASH; ++i) + if (_trashActive[i]) + if (Creature* c = instance->GetCreature(_trashGUID[i])) + if (c->IsAlive() && !c->IsInCombat()) + c->AI()->DoAction(1); + + if (_waveNumber == 5 || _waveNumber == 10) + { + _nextWaveTimer = 0; + if (_waveNumber == 5) + { + if (Creature* falric = GetCreature(DATA_FALRIC)) + { + if (falric->IsAlive()) + falric->AI()->DoAction(1); + else + _nextWaveTimer = 1; } } else - CheckPlayersTimer -= diff; - - if (NextWaveTimer) { - if (NextWaveTimer <= diff) - { - NextWaveTimer = 0; - AddWave1(); - } - else - NextWaveTimer -= diff; - } - - if (ResumeFirstEventTimer) - { - if (ResumeFirstEventTimer <= diff) - { - switch (ResumeFirstEventStep) // After a wipe - { - case 0: - if (Creature* pFalric = instance->GetCreature(NPC_FalricGUID)) - { - pFalric->UpdatePosition(5274.9f, 2039.2f, 709.319f, 5.4619f, true); - pFalric->StopMovingOnCurrentPos(); - pFalric->SetVisible(true); - if (pFalric->IsAlive()) - { - pFalric->GetMotionMaster()->MovePoint(0, FalricMovePos); - if (Aura* a = pFalric->AddAura(SPELL_SHADOWMOURNE_VISUAL, pFalric)) - a->SetDuration(8000); - } - } - if (Creature* pMarwyn = instance->GetCreature(NPC_MarwynGUID)) - { - pMarwyn->UpdatePosition(5343.77f, 1973.86f, 709.319f, 2.35173f, true); - pMarwyn->StopMovingOnCurrentPos(); - pMarwyn->SetVisible(true); - if (pMarwyn->IsAlive()) - { - pMarwyn->GetMotionMaster()->MovePoint(0, MarwynMovePos); - if (Aura* a = pMarwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, pMarwyn)) - a->SetDuration(8000); - } - pMarwyn->AI()->Talk(EMOTE_MARWYN_INTRO_SPIRIT); - } - ++ResumeFirstEventStep; - ResumeFirstEventTimer = 7500; - break; - case 1: - if (Creature* pFalric = instance->GetCreature(NPC_FalricGUID)) - { - if (pFalric->IsAlive()) - { - pFalric->AI()->Talk(SAY_FALRIC_INTRO_2); // Between wave 1 and 4 - } - else - { - if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID)) - { - marwyn->AI()->Talk(SAY_MARWYN_WIPE_AFTER_FALRIC); // Between wave 6 and 9 - } - } - } - SetData(ACTION_SHOW_TRASH, 1); - ResumeFirstEventStep = 0; - ResumeFirstEventTimer = 0; - NextWaveTimer = 7000; - break; - default: - for (uint8 i = 0; i < NUM_OF_TRASH; ++i) - if (Creature* c = instance->GetCreature(NPC_TrashGUID[i])) - c->SetVisible(false); - if (Creature* falric = instance->GetCreature(NPC_FalricGUID)) - falric->SetVisible(false); - if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID)) - marwyn->SetVisible(false); - ResumeFirstEventStep = 0; - ResumeFirstEventTimer = 0; - break; - } - } - else - ResumeFirstEventTimer -= diff; - } - if (outroStep) - { - if (outroTimer <= diff) - { - switch (outroStep) - { - case 1: - if (Creature* lk = instance->GetCreature(NPC_LichKingGUID)) - { - lk->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 2], true); - lk->StopMovingOnCurrentPos(); - lk->RemoveAllAuras(); - lk->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02); - if (!lk->IsVisible()) - lk->SetVisible(true); - if (Creature* leader = instance->GetCreature(NPC_LeaderGUID)) - { - leader->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true); - leader->StopMovingOnCurrentPos(); - leader->RemoveAllAuras(); - leader->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H); - if (!leader->IsVisible()) - leader->SetVisible(true); - lk->CastSpell(leader, SPELL_HARVEST_SOUL, false); - } - } - ++outroStep; - outroTimer = 500; - break; - case 2: - { - uint32 entry = GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_THE_SKYBREAKER : GO_ORGRIMS_HAMMER; - T1 = sTransportMgr->CreateTransport(entry, 0, instance); - - ++outroStep; - outroTimer = GetTeamIdInInstance() == TEAM_ALLIANCE ? 10000 : 10500; - } - break; - case 3: - if (T1) - T1->EnableMovement(false); - if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID)) - c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_FIRE_ALLY : SAY_FIRE_HORDE); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - { - c->RemoveAllAuras(); - c->CastSpell(c, SPELL_GUNSHIP_CANNON_FIRE_PERIODIC, true); - } - if (Creature* c = instance->GetCreature(NPC_LichKingGUID)) - { - c->InterruptNonMeleeSpells(true); - c->RemoveAllAuras(); - } - ++outroStep; - outroTimer = 5000; - break; - case 4: - HandleGameObject(GO_CaveInGUID, false); - ++outroStep; - outroTimer = 3000; - break; - case 5: - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - if (Creature* c = instance->GetCreature(NPC_LichKingGUID)) - { - c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - c->GetThreatMgr().ClearAllThreat(); - c->CombatStop(true); - c->InterruptNonMeleeSpells(true); - c->SetVisible(false); - } - if (instance->IsHeroic()) - instance->ToInstanceMap()->PermBindAllPlayers(); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->CastSpell(c, SPELL_ACHIEVEMENT_CHECK, true); - ++outroStep; - outroTimer = 1000; - break; - case 6: - if (T1) - T1->EnableMovement(true); - ++outroStep; - outroTimer = 3500; - break; - case 7: - if (T1) - T1->EnableMovement(false); - if (Creature* leader = instance->GetCreature(NPC_LeaderGUID)) - { - uint8 index = GetTeamIdInInstance() == TEAM_ALLIANCE ? 0 : 1; - for (uint8 i = 0; i < 3; ++i) - if (StairsPos[index][i].GetPositionX()) - if (GameObject* go = leader->SummonGameObject(GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false)) - go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE); - //Position pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyPortalPos : HordePortalPos; - //leader->SummonGameObject(GO_PORTAL_TO_DALARAN, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400); - //pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyChestPos : HordeChestPos; - //leader->SummonGameObject(instance->GetSpawnMode() ? GO_CHEST_HEROIC : GO_CHEST_NORMAL, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400); - } - ++outroStep; - outroTimer = 1000; - break; - case 8: - if (Creature* c = instance->GetCreature(NPC_ShipCaptainGUID)) - c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_ONBOARD_ALLY : SAY_ONBOARD_HORDE); - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - { - c->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - c->GetMotionMaster()->MovePoint(0, WalkCaveInPos); - c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); // need gossip ID 10931 - } - ++outroStep; - outroTimer = 6000; - break; - case 9: - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_JAINA_FINAL_1 : SAY_SYLVANA_FINAL); - HandleGameObject(GO_CaveInGUID, true); - ++outroStep; - outroTimer = 11000; - break; - case 10: - ++outroStep; - outroTimer = 0; - for (Map::PlayerList::const_iterator itr = instance->GetPlayers().begin(); itr != instance->GetPlayers().end(); ++itr) - if (Player* p = itr->GetSource()) - p->KilledMonsterCredit(NPC_WRATH_OF_THE_LICH_KING_CREDIT); - if (GetTeamIdInInstance() == TEAM_ALLIANCE) - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - { - c->AI()->Talk(SAY_JAINA_FINAL_2); - outroTimer = 10000; - } - break; - case 11: - if (Creature* c = instance->GetCreature(NPC_LeaderGUID)) - c->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - ++outroStep; - outroTimer = 300 * 1000; - break; - case 12: - outroStep = 0; - outroTimer = 0; - if (T1) - T1->setActive(false); - break; - } - } - else - outroTimer -= diff; + if (Creature* marwyn = GetCreature(DATA_MARWYN)) + if (marwyn->IsAlive()) + marwyn->AI()->DoAction(1); } } - }; + else + { + _nextWaveTimer = 150000; + + uint8 numToActivate = 5; + if (_waveNumber <= 2) + numToActivate = 3; + else if (_waveNumber <= 4) + numToActivate = 4; + _remainingTrashKills += numToActivate; + for (uint8 i = 0; i < numToActivate; ++i) + { + uint32 entry = _chosenComposition[_waveNumber - (_waveNumber > 5 ? 2 : 1)][i]; + bool forward = !!urand(0, 1); + for (int8 j = (forward ? 0 : NUM_OF_TRASH - 1); (forward ? j < NUM_OF_TRASH : j >= 0); (forward ? ++j : --j)) + if (!_trashActive[j]) + if (Creature* c = instance->GetCreature(_trashGUID[j])) + if (c->GetEntry() == entry) + { + _trashActive[j] = true; + c->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + c->SetImmuneToAll(false); + c->AI()->DoAction(1); + break; + } + } + } + } + + void HandleWaveWipe() + { + if (!_waveNumber) + return; + + DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVES_ENABLED, 0); + DoUpdateWorldState(WORLD_STATE_HALLS_OF_REFLECTION_WAVE_COUNT, 0); + HandleGameObject(GO_FRONT_DOOR, true); + + _trashCounter = NUM_OF_TRASH; + _waveNumber = 0; + _nextWaveTimer = 0; + std::memset(&_chosenComposition, 0, sizeof(_chosenComposition)); + + for (uint8 i = 0; i < NUM_OF_TRASH; ++i) + if (_trashActive[i]) + if (Creature* c = instance->GetCreature(_trashGUID[i])) + { + c->GetThreatMgr().ClearAllThreat(); + c->CombatStop(true); + c->InterruptNonMeleeSpells(true); + c->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + c->SetImmuneToAll(true); + c->Respawn(true); + c->UpdatePosition(c->GetHomePosition(), true); + c->StopMovingOnCurrentPos(); + } + std::fill(std::begin(_trashActive), std::end(_trashActive), false); + if (Creature* falric = GetCreature(DATA_FALRIC)) + falric->AI()->EnterEvadeMode(); + if (Creature* marwyn = GetCreature(DATA_MARWYN)) + marwyn->AI()->EnterEvadeMode(); + + _waveResumeTimer = 5000; + _waveResumeStep = 2; + _remainingTrashKills = 0; + } + + void Update(uint32 diff) override + { + if (!instance->HavePlayers()) + return; + + if (_playerCheckTimer <= diff) + { + _playerCheckTimer = 5000; + if ((GetPersistentData(PERSISTENT_DATA_INTRO)) && GetBossState(DATA_MARWYN) != DONE) + { + Map::PlayerList const& pl = instance->GetPlayers(); + if (_waveNumber || _nextWaveTimer) + { + bool allDead = true; + bool outOfRange = false; + for (auto itr = pl.begin(); itr != pl.end(); ++itr) + { + Player* p = itr->GetSource(); + if (!p || p->IsGameMaster()) + continue; + if (p->IsAlive()) + allDead = false; + if (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_IN_COMBAT) + { + outOfRange = true; + break; + } + } + if (allDead || outOfRange) + HandleWaveWipe(); + } + else if (!_waveResumeTimer) + { + bool allInRange = (instance->GetPlayersCountExceptGMs() > 0); + for (auto itr = pl.begin(); itr != pl.end(); ++itr) + { + Player* p = itr->GetSource(); + if (!p || p->IsGameMaster()) + continue; + if (p->GetExactDist2d(&CenterPos) > MAX_DIST_FROM_CENTER_TO_START || !p->IsAlive()) + { + allInRange = false; + break; + } + } + if (allInRange) + { + _waveResumeTimer = 1; + _waveResumeStep = 0; + } + } + } + } + else + _playerCheckTimer -= diff; + + if (_nextWaveTimer) + { + if (_nextWaveTimer <= diff) + { + _nextWaveTimer = 0; + StartNextWave(); + } + else + _nextWaveTimer -= diff; + } + + if (_waveResumeTimer) + { + if (_waveResumeTimer <= diff) + { + switch (_waveResumeStep) + { + case 0: + if (Creature* falric = GetCreature(DATA_FALRIC)) + { + falric->UpdatePosition(5274.9f, 2039.2f, 709.319f, 5.4619f, true); + falric->StopMovingOnCurrentPos(); + falric->SetVisible(true); + if (falric->IsAlive()) + { + falric->GetMotionMaster()->MovePoint(0, FalricMovePos); + if (Aura* a = falric->AddAura(SPELL_SHADOWMOURNE_VISUAL, falric)) + a->SetDuration(8000); + } + } + if (Creature* marwyn = GetCreature(DATA_MARWYN)) + { + marwyn->UpdatePosition(5343.77f, 1973.86f, 709.319f, 2.35173f, true); + marwyn->StopMovingOnCurrentPos(); + marwyn->SetVisible(true); + if (marwyn->IsAlive()) + { + marwyn->GetMotionMaster()->MovePoint(0, MarwynMovePos); + if (Aura* a = marwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, marwyn)) + a->SetDuration(8000); + } + marwyn->AI()->Talk(EMOTE_MARWYN_INTRO_SPIRIT); + } + ++_waveResumeStep; + _waveResumeTimer = 7500; + break; + case 1: + if (Creature* falric = GetCreature(DATA_FALRIC)) + { + if (falric->IsAlive()) + falric->AI()->Talk(SAY_FALRIC_INTRO_2); + else if (Creature* marwyn = GetCreature(DATA_MARWYN)) + marwyn->AI()->Talk(SAY_MARWYN_WIPE_AFTER_FALRIC); + } + SetData(ACTION_SHOW_TRASH, 1); + _waveResumeStep = 0; + _waveResumeTimer = 0; + _nextWaveTimer = 7000; + break; + default: + for (uint8 i = 0; i < NUM_OF_TRASH; ++i) + if (Creature* c = instance->GetCreature(_trashGUID[i])) + c->SetVisible(false); + if (Creature* falric = GetCreature(DATA_FALRIC)) + falric->SetVisible(false); + if (Creature* marwyn = GetCreature(DATA_MARWYN)) + marwyn->SetVisible(false); + _waveResumeStep = 0; + _waveResumeTimer = 0; + break; + } + } + else + _waveResumeTimer -= diff; + } + + if (_outroStep) + { + if (_outroTimer <= diff) + UpdateOutro(); + else + _outroTimer -= diff; + } + } + +private: + void UpdateOutro() + { + switch (_outroStep) + { + case 1: + if (Creature* lk = GetCreature(NPC_LICH_KING_BOSS)) + { + lk->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 2], true); + lk->StopMovingOnCurrentPos(); + lk->RemoveAllAuras(); + lk->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02); + if (!lk->IsVisible()) + lk->SetVisible(true); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + leader->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true); + leader->StopMovingOnCurrentPos(); + leader->RemoveAllAuras(); + leader->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_READY1H); + if (!leader->IsVisible()) + leader->SetVisible(true); + lk->CastSpell(leader, SPELL_HARVEST_SOUL, false); + } + } + ++_outroStep; + _outroTimer = 500; + break; + case 2: + { + uint32 entry = GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_THE_SKYBREAKER : GO_ORGRIMS_HAMMER; + _transport = sTransportMgr->CreateTransport(entry, 0, instance); + ++_outroStep; + _outroTimer = GetTeamIdInInstance() == TEAM_ALLIANCE ? 10000 : 10500; + break; + } + case 3: + if (_transport) + _transport->EnableMovement(false); + if (Creature* captain = GetCreature(DATA_SHIP_CAPTAIN)) + captain->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_FIRE_ALLY : SAY_FIRE_HORDE); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + leader->RemoveAllAuras(); + leader->CastSpell(leader, SPELL_GUNSHIP_CANNON_FIRE_PERIODIC, true); + } + if (Creature* lichKing = GetCreature(NPC_LICH_KING_BOSS)) + { + lichKing->InterruptNonMeleeSpells(true); + lichKing->RemoveAllAuras(); + } + ++_outroStep; + _outroTimer = 5000; + break; + case 4: + HandleGameObject(GO_CAVE_IN, false); + ++_outroStep; + _outroTimer = 3000; + break; + case 5: + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + if (Creature* lichKing = GetCreature(NPC_LICH_KING_BOSS)) + { + lichKing->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + lichKing->GetThreatMgr().ClearAllThreat(); + lichKing->CombatStop(true); + lichKing->InterruptNonMeleeSpells(true); + lichKing->SetVisible(false); + } + if (instance->IsHeroic()) + instance->ToInstanceMap()->PermBindAllPlayers(); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->CastSpell(leader, SPELL_ACHIEVEMENT_CHECK, true); + ++_outroStep; + _outroTimer = 1000; + break; + case 6: + if (_transport) + _transport->EnableMovement(true); + ++_outroStep; + _outroTimer = 3500; + break; + case 7: + if (_transport) + _transport->EnableMovement(false); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + uint8 index = GetTeamIdInInstance() == TEAM_ALLIANCE ? 0 : 1; + for (uint8 i = 0; i < 3; ++i) + if (StairsPos[index][i].GetPositionX()) + if (GameObject* go = leader->SummonGameObject(GetTeamIdInInstance() == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false)) + go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE); + } + ++_outroStep; + _outroTimer = 1000; + break; + case 8: + if (Creature* captain = GetCreature(DATA_SHIP_CAPTAIN)) + captain->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_ONBOARD_ALLY : SAY_ONBOARD_HORDE); + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + leader->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + leader->GetMotionMaster()->MovePoint(0, WalkCaveInPos); + leader->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + ++_outroStep; + _outroTimer = 6000; + break; + case 9: + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->AI()->Talk(GetTeamIdInInstance() == TEAM_ALLIANCE ? SAY_JAINA_FINAL_1 : SAY_SYLVANA_FINAL); + HandleGameObject(GO_CAVE_IN, true); + ++_outroStep; + _outroTimer = 11000; + break; + case 10: + ++_outroStep; + _outroTimer = 0; + instance->DoForAllPlayers([](Player* player) + { + player->KilledMonsterCredit(NPC_WRATH_OF_THE_LICH_KING_CREDIT); + }); + if (GetTeamIdInInstance() == TEAM_ALLIANCE) + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + { + leader->AI()->Talk(SAY_JAINA_FINAL_2); + _outroTimer = 10000; + } + break; + case 11: + if (Creature* leader = GetCreature(NPC_SYLVANAS_PART2)) + leader->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + ++_outroStep; + _outroTimer = 300 * 1000; + break; + case 12: + _outroStep = 0; + _outroTimer = 0; + if (_transport) + _transport->setActive(false); + break; + } + } + + // GUIDs not handled by ObjectData (arrays with position-based assignment) + ObjectGuid _spiritualReflectionGUID[MAX_SPIRITUAL_REFLECTIONS]; + ObjectGuid _iceWallTargetGUID[MAX_ICE_WALL_TARGETS]; + ObjectGuid _trashGUID[NUM_OF_TRASH]; + + // Runtime state (not persisted) + uint32 _batteredHiltStatus{}; + + // Wave system + bool _trashActive[NUM_OF_TRASH]{}; + uint8 _trashCounter{}; + uint32 _chosenComposition[8][5]{}; + uint8 _waveNumber{}; + uint32 _nextWaveTimer{}; + uint16 _playerCheckTimer{}; + uint16 _waveResumeTimer{}; + uint8 _waveResumeStep{}; + bool _falricPhaseComplete{}; + uint8 _remainingTrashKills{}; + + // Lich King fight + bool _isLichKingFightActive{}; + uint32 _outroTimer{}; + uint8 _outroStep{}; + MotionTransport* _transport{}; }; void AddSC_instance_halls_of_reflection() { - new instance_halls_of_reflection(); + RegisterInstanceScript(instance_halls_of_reflection, MAP_HALLS_OF_REFLECTION); }