From b8118fa06b7444bcf7cbb9049f6b82fc50e914f0 Mon Sep 17 00:00:00 2001 From: Dan <83884799+elthehablo@users.noreply.github.com> Date: Thu, 8 Feb 2024 03:42:20 +0100 Subject: [PATCH] fix(Scripts/TheEye): Re-factor Kael'thas (#18272) * restructuring base files and instance files * small fix * some fixes * fix * some fixes * up until kael phase * weapon despawn fix * final for now * some minor details * fix weapon despawn * fix by clearing validator still has debug statements to check how far we get * finalise with stop casting * codestyle * remove redundant delay --- .../Outland/TempestKeep/Eye/boss_kaelthas.cpp | 1125 +++++++++-------- .../TempestKeep/Eye/instance_the_eye.cpp | 25 +- .../scripts/Outland/TempestKeep/Eye/the_eye.h | 8 +- 3 files changed, 620 insertions(+), 538 deletions(-) diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 4971d5c70..4fa9f1a27 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -55,7 +55,7 @@ enum Yells enum Spells { - // Phase 2 spells + // _phase 2 spells SPELL_SUMMON_WEAPONS = 36976, SPELL_SUMMON_WEAPONA = 36958, SPELL_SUMMON_WEAPONB = 36959, @@ -65,10 +65,10 @@ enum Spells SPELL_SUMMON_WEAPONF = 36963, SPELL_SUMMON_WEAPONG = 36964, - // Phase 3 spells + // _phase 3 spells SPELL_RESURRECTION = 36450, - // Phase 4 spells + // _phase 4 spells SPELL_FIREBALL = 36805, SPELL_ARCANE_DISRUPTION = 36834, SPELL_PHOENIX = 36723, @@ -94,12 +94,17 @@ enum Spells SPELL_KEAL_STUNNED = 36185, SPELL_KAEL_FULL_POWER = 36187, SPELL_FLOATING_DROWNED = 36550, + SPELL_DARK_BANISH_STATE = 52241, // wrong visual apparently + SPELL_ARCANE_EXPLOSION_VISUAL = 34807, SPELL_PURE_NETHER_BEAM1 = 36196, SPELL_PURE_NETHER_BEAM2 = 36197, SPELL_PURE_NETHER_BEAM3 = 36198, + SPELL_PURE_NETHER_BEAM4 = 36201, + SPELL_PURE_NETHER_BEAM5 = 36290, + SPELL_PURE_NETHER_BEAM6 = 36291, - // Phase 5 spells + // _phase 5 spells SPELL_GRAVITY_LAPSE = 35941, SPELL_GRAVITY_LAPSE_TELEPORT1 = 35966, SPELL_GRAVITY_LAPSE_KNOCKBACK = 34480, @@ -197,6 +202,21 @@ enum Misc EVENT_SCENE_16 = 65 }; +enum KaelActions +{ + ACTION_START_SANGUINAR = 0, + ACTION_START_CAPERNIAN = 1, + ACTION_START_TELONICUS = 2, + ACTION_START_WEAPONS = 3 +}; + +enum SpellGroups +{ + GROUP_PYROBLAST = 0, + GROUP_SHOCK_BARRIER = 1, + GROUP_NETHER_BEAM = 2 +}; + const Position triggersPos[6] = { {799.11f, -38.95f, 85.0f, 0.0f}, @@ -207,549 +227,531 @@ const Position triggersPos[6] = {843.35f, 6.35f, 67.14f, 0.0f} }; -class boss_kaelthas : public CreatureScript +struct boss_kaelthas : public BossAI { -public: - boss_kaelthas() : CreatureScript("boss_kaelthas") { } + boss_kaelthas(Creature* creature) : BossAI(creature, DATA_KAELTHAS) { } - struct boss_kaelthasAI : public BossAI + void PrepareAdvisors() { - boss_kaelthasAI(Creature* creature) : BossAI(creature, DATA_KAELTHAS) { } - - uint8 phase; - EventMap events2; - - void PrepareAdvisors() + for (uint8 advisorData = DATA_THALADRED; advisorData <= DATA_TELONICUS; ++advisorData) { - for (uint8 i = DATA_KAEL_ADVISOR1; i <= DATA_KAEL_ADVISOR4; ++i) - if (Creature* advisor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(i))) - { - advisor->Respawn(true); - advisor->StopMovingOnCurrentPos(); - advisor->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - advisor->SetReactState(REACT_PASSIVE); - summons.Summon(advisor); - } - } - - void SetData(uint32 type, uint32 data) override - { - if (type == DATA_RESURRECT_CAST && data == DATA_RESURRECT_CAST) + if (Creature* advisor = instance->GetCreature(advisorData)) { - for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - if (summon->GetSpawnId()) - { - summon->SetReactState(REACT_PASSIVE); - summon->setDeathState(DeathState::JustRespawned); - summon->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } + advisor->Respawn(true); + advisor->StopMovingOnCurrentPos(); + advisor->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + advisor->SetReactState(REACT_PASSIVE); + summons.Summon(advisor); } } + } - void SetRoomState(GOState state) + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_RESURRECT_CAST && data == DATA_RESURRECT_CAST) { - if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_BRIDGE_WINDOW))) - window->SetGoState(state); - if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_KAEL_STATUE_RIGHT))) - window->SetGoState(state); - if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_KAEL_STATUE_LEFT))) - window->SetGoState(state); + summons.DoForAllSummons([&](WorldObject* summon){ + if (Creature* summonedCreature = summon->ToCreature()) + { + summonedCreature->SetReactState(REACT_PASSIVE); + summonedCreature->setDeathState(DeathState::JustRespawned); + summonedCreature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + }); } + } - void Reset() override + void SetRoomState(GOState state) + { + //TODO: handle door closing + if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_BRIDGE_WINDOW))) + window->SetGoState(state); + if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_KAEL_STATUE_RIGHT))) + window->SetGoState(state); + if (GameObject* window = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_KAEL_STATUE_LEFT))) + window->SetGoState(state); + } + + void Reset() override + { + BossAI::Reset(); + scheduler.Schedule(1s, [this](TaskContext) { - BossAI::Reset(); - events2.Reset(); - events2.ScheduleEvent(EVENT_GATHER_ADVISORS, 1000); - phase = PHASE_NONE; + PrepareAdvisors(); + }); + _phase = PHASE_NONE; - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_HOVER, true); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); - SetRoomState(GO_STATE_READY); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_HOVER, true); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + SetRoomState(GO_STATE_READY); + me->SetDisableGravity(false); + me->SetWalk(false); + ScheduleHealthCheckEvent(50, [&]{ + scheduler.CancelAll(); + me->CastStop(); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->MovePoint(POINT_MIDDLE, me->GetHomePosition(), true, true); + me->ClearUnitState(UNIT_STATE_MELEE_ATTACKING); + me->SendMeleeAttackStop(); + }); + } + + void AttackStart(Unit* who) override + { + if (_phase == PHASE_FINAL /* check is scheduled&& events.GetNextEventTime(EVENT_GRAVITY_LAPSE_END) == 0*/) + BossAI::AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (_phase == PHASE_NONE && who->GetTypeId() == TYPEID_PLAYER && me->IsValidAttackTarget(who)) + { + _phase = PHASE_SINGLE_ADVISOR; + me->SetInCombatWithZone(); + Talk(SAY_INTRO); + ScheduleUniqueTimedEvent(23s, [&] + { + Talk(SAY_INTRO_THALADRED); + }, EVENT_PREFIGHT_PHASE11); + ScheduleUniqueTimedEvent(30s, [&] + { + if (Creature* thaladred = summons.GetCreatureWithEntry(NPC_THALADRED)) + { + thaladred->SetReactState(REACT_AGGRESSIVE); + thaladred->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + thaladred->AI()->AttackStart(target); + thaladred->SetInCombatWithZone(); + } + }, EVENT_PREFIGHT_PHASE12); + } + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + if (summon->GetEntry() == NPC_NETHER_VAPOR) + summon->GetMotionMaster()->MoveRandom(20.0f); + } + + void DoAction(int32 action) override + { + switch(action) + { + case ACTION_START_SANGUINAR: + IntroduceNewAdvisor(SAY_INTRO_SANGUINAR, ACTION_START_SANGUINAR); + break; + case ACTION_START_CAPERNIAN: + IntroduceNewAdvisor(SAY_INTRO_CAPERNIAN, ACTION_START_CAPERNIAN); + break; + case ACTION_START_TELONICUS: + IntroduceNewAdvisor(SAY_INTRO_TELONICUS, ACTION_START_TELONICUS); + break; + case ACTION_START_WEAPONS: + ScheduleUniqueTimedEvent(3s, [&]{ + Talk(SAY_PHASE2_WEAPON); + DoCastSelf(SPELL_SUMMON_WEAPONS); + _phase = PHASE_WEAPONS; + }, EVENT_PREFIGHT_PHASE51); + ScheduleUniqueTimedEvent(9s, [&]{ + summons.DoForAllSummons([&](WorldObject* summon) + { + if (Creature* summonedCreature = summon->ToCreature()) + { + if (!summonedCreature->GetSpawnId()) + { + summonedCreature->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + summonedCreature->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + summonedCreature->AI()->AttackStart(target); + } + } + } + }); + ScheduleUniqueTimedEvent(2min, [&]{ + PhaseAllAdvisorsExecute(); + }, EVENT_PREFIGHT_PHASE61); + }, EVENT_PREFIGHT_PHASE52); + break; + default: + break; + } + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (point == POINT_MIDDLE) + { + ExecuteMiddleEvent(); + } + else if (point == POINT_START_LAST_PHASE) + { me->SetDisableGravity(false); me->SetWalk(false); - } - - void AttackStart(Unit* who) override - { - if (phase == PHASE_FINAL && events.GetNextEventTime(EVENT_GRAVITY_LAPSE_END) == 0) - BossAI::AttackStart(who); - } - - void MoveInLineOfSight(Unit* who) override - { - if (phase == PHASE_NONE && who->GetTypeId() == TYPEID_PLAYER && me->IsValidAttackTarget(who)) + me->RemoveAurasDueToSpell(SPELL_KAEL_FULL_POWER); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + //re-set validator + scheduler.SetValidator([this]{ + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + ScheduleTimedEvent(0ms, [&] { - phase = PHASE_SINGLE_ADVISOR; - me->SetInCombatWithZone(); - Talk(SAY_INTRO); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE11, 23000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE12, 30000); - } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - if (summon->GetEntry() == NPC_NETHER_VAPOR) - summon->GetMotionMaster()->MoveRandom(20.0f); - } - - void SummonedCreatureDies(Creature* summon, Unit*) override - { - if (phase == PHASE_FINAL) - return; - - if (summon->GetSpawnId() && phase == PHASE_ALL_ADVISORS) + DoCastVictim(SPELL_FIREBALL); + }, 2400ms, 7500ms); + ScheduleTimedEvent(10000ms, [&] { - for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - if (summon->GetSpawnId() && summon->IsAlive()) - return; - - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE71, 2000); - return; - } - - if (summon->GetEntry() == NPC_THALADRED) + DoCastRandomTarget(SPELL_FLAME_STRIKE, 0, 100.0f); + }, 30250ms, 50650ms); + ScheduleTimedEvent(20000ms, [&] { - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE21, 2000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE22, 14500); - } - else if (summon->GetEntry() == NPC_LORD_SANGUINAR) + Talk(SAY_SUMMON_PHOENIX); + DoCastSelf(SPELL_PHOENIX); + }, 31450ms, 66550ms); + ScheduleTimedEvent(5s, [&] { - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE31, 2000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE32, 9000); - } - else if (summon->GetEntry() == NPC_CAPERNIAN) - { - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE41, 2000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE42, 10400); - } - else if (summon->GetEntry() == NPC_TELONICUS) - { - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE51, 3000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE52, 9000); - } - } - - void JustDied(Unit* killer) override - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - - Talk(SAY_DEATH); - BossAI::JustDied(killer); - } - - void MovementInform(uint32 type, uint32 point) override - { - if (type != POINT_MOTION_TYPE) - return; - - if (point == POINT_MIDDLE) - { - events2.ScheduleEvent(EVENT_SCENE_1, 0); - events2.ScheduleEvent(EVENT_SCENE_2, 2500); - events2.ScheduleEvent(EVENT_SCENE_3, 4000); - events2.ScheduleEvent(EVENT_SCENE_4, 7000); - events2.ScheduleEvent(EVENT_SCENE_5, 10000); - events2.ScheduleEvent(EVENT_SCENE_6, 14000); - events2.ScheduleEvent(EVENT_SCENE_7, 17500); - events2.ScheduleEvent(EVENT_SCENE_8, 19000); - events2.ScheduleEvent(EVENT_SCENE_9, 22000); // two first lightnings + aura - events2.ScheduleEvent(EVENT_SCENE_10, 22800); // two - events2.ScheduleEvent(EVENT_SCENE_11, 23600); // two - events2.ScheduleEvent(EVENT_SCENE_12, 24500); // two - events2.ScheduleEvent(EVENT_SCENE_13, 24800); // two - events2.ScheduleEvent(EVENT_SCENE_14, 25300); // two - events2.ScheduleEvent(EVENT_SCENE_15, 32000); // full power - events2.ScheduleEvent(EVENT_SCENE_16, 36000); // remove lightnings + aura, move down - } - else if (point == POINT_START_LAST_PHASE) - { - me->SetDisableGravity(false); - me->SetWalk(false); - me->RemoveAurasDueToSpell(SPELL_KAEL_FULL_POWER); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - events.SetTimer(60000); - events.ScheduleEvent(EVENT_SPELL_FIREBALL, 0); - events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 10000); - events.ScheduleEvent(EVENT_SPELL_SUMMON_PHOENIX, 20000); - events.ScheduleEvent(EVENT_SPELL_GRAVITY_LAPSE, 5000); - if (me->GetVictim()) + scheduler.DelayAll(30s); + me->setAttackTimer(BASE_ATTACK, 30000); + DoCastSelf(SPELL_GRAVITY_LAPSE); + DoCastSelf(SPELL_SUMMON_NETHER_VAPOR); + scheduler.Schedule(4s, GROUP_NETHER_BEAM, [this](TaskContext context) + { + DoCastSelf(SPELL_NETHER_BEAM); + context.Repeat(4s); + }).Schedule(0s, GROUP_SHOCK_BARRIER, [this](TaskContext context) + { + DoCastSelf(SPELL_SHOCK_BARRIER); + context.Repeat(10s); + }).Schedule(20500ms, GROUP_SHOCK_BARRIER, [this](TaskContext) + { + scheduler.CancelGroup(GROUP_SHOCK_BARRIER); + }).Schedule(32s, [this](TaskContext) { - me->SetTarget(me->GetVictim()->GetGUID()); - AttackStart(me->GetVictim()); - } - } - } - - void UpdateAI(uint32 diff) override - { - events2.Update(diff); - switch (events2.ExecuteEvent()) - { - case EVENT_GATHER_ADVISORS: - PrepareAdvisors(); - break; - case EVENT_PREFIGHT_PHASE11: - Talk(SAY_INTRO_THALADRED); - break; - case EVENT_PREFIGHT_PHASE12: - if (Creature* advisor = summons.GetCreatureWithEntry(NPC_THALADRED)) - { - advisor->SetReactState(REACT_AGGRESSIVE); - advisor->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - advisor->AI()->AttackStart(target); - advisor->SetInCombatWithZone(); - advisor->AI()->Talk(SAY_THALADRED_AGGRO); - } - break; - case EVENT_PREFIGHT_PHASE21: - Talk(SAY_INTRO_SANGUINAR); - break; - case EVENT_PREFIGHT_PHASE22: - if (Creature* advisor = summons.GetCreatureWithEntry(NPC_LORD_SANGUINAR)) - { - advisor->SetReactState(REACT_AGGRESSIVE); - advisor->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - advisor->AI()->AttackStart(target); - advisor->SetInCombatWithZone(); - advisor->AI()->Talk(SAY_SANGUINAR_AGGRO); - } - break; - case EVENT_PREFIGHT_PHASE31: - Talk(SAY_INTRO_CAPERNIAN); - break; - case EVENT_PREFIGHT_PHASE32: - if (Creature* advisor = summons.GetCreatureWithEntry(NPC_CAPERNIAN)) - { - advisor->SetReactState(REACT_AGGRESSIVE); - advisor->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - advisor->AI()->AttackStart(target); - advisor->SetInCombatWithZone(); - advisor->AI()->Talk(SAY_CAPERNIAN_AGGRO); - } - break; - case EVENT_PREFIGHT_PHASE41: - Talk(SAY_INTRO_TELONICUS); - break; - case EVENT_PREFIGHT_PHASE42: - if (Creature* advisor = summons.GetCreatureWithEntry(NPC_TELONICUS)) - { - advisor->SetReactState(REACT_AGGRESSIVE); - advisor->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - advisor->AI()->AttackStart(target); - advisor->SetInCombatWithZone(); - advisor->AI()->Talk(SAY_TELONICUS_AGGRO); - } - break; - case EVENT_PREFIGHT_PHASE51: - Talk(SAY_PHASE2_WEAPON); - me->CastSpell(me, SPELL_SUMMON_WEAPONS, false); - phase = PHASE_WEAPONS; - break; - case EVENT_PREFIGHT_PHASE52: - for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i) - { - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - if (!summon->GetSpawnId()) - { - summon->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - summon->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - summon->AI()->AttackStart(target); - } - } - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE61, 2 * MINUTE * IN_MILLISECONDS); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE62, 2 * MINUTE * IN_MILLISECONDS + 6000); - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE63, 2 * MINUTE * IN_MILLISECONDS + 12000); - break; - case EVENT_PREFIGHT_PHASE61: - phase = PHASE_ALL_ADVISORS; - Talk(SAY_PHASE3_ADVANCE); - break; - case EVENT_PREFIGHT_PHASE62: - me->CastSpell(me, SPELL_RESURRECTION, false); - break; - case EVENT_PREFIGHT_PHASE63: - for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ++i) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *i)) - if (summon->GetSpawnId()) - { - summon->SetReactState(REACT_AGGRESSIVE); - summon->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - summon->SetInCombatWithZone(); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - summon->AI()->AttackStart(target); - } - events2.ScheduleEvent(EVENT_PREFIGHT_PHASE71, 3 * MINUTE * IN_MILLISECONDS); - break; - case EVENT_PREFIGHT_PHASE71: - events2.CancelEvent(EVENT_PREFIGHT_PHASE71); - Talk(SAY_PHASE4_INTRO2); - phase = PHASE_FINAL; - DoResetThreatList(); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - AttackStart(target); - - events2.Reset(); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_FIREBALL, 1000); - events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 15000); - events.ScheduleEvent(EVENT_SPELL_SUMMON_PHOENIX, 30000); - events.ScheduleEvent(EVENT_SPELL_SEQ_1, 20000); - events.ScheduleEvent(EVENT_SPELL_SEQ_2, 40000); - events.ScheduleEvent(EVENT_SPELL_SEQ_3, 60000); - events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000); - break; - case EVENT_SCENE_1: - me->SetTarget(); - me->SetFacingTo(M_PI); - me->SetWalk(true); - Talk(SAY_PHASE5_NUTS); - break; - case EVENT_SCENE_2: - me->SetTarget(); - me->CastSpell(me, SPELL_KAEL_EXPLODES1, true); - me->CastSpell(me, SPELL_KAEL_GAINING_POWER, false); - me->SetDisableGravity(true); - break; - case EVENT_SCENE_3: - me->SetTarget(); - for (uint8 i = 0; i < 2; ++i) - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i], TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); - me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), 76.0f, false, true); - me->CastSpell(me, SPELL_GROW, true); - break; - case EVENT_SCENE_4: - me->SetTarget(); - me->CastSpell(me, SPELL_GROW, true); - me->CastSpell(me, SPELL_KAEL_EXPLODES2, true); - me->CastSpell(me, SPELL_NETHERBEAM_AURA1, true); - for (uint8 i = 0; i < 2; ++i) - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i + 2], TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); - break; - case EVENT_SCENE_5: - me->SetTarget(); - me->CastSpell(me, SPELL_GROW, true); - me->CastSpell(me, SPELL_KAEL_EXPLODES3, true); - me->CastSpell(me, SPELL_NETHERBEAM_AURA2, true); - for (uint8 i = 0; i < 2; ++i) - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i + 4], TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); - break; - case EVENT_SCENE_6: - me->CastSpell(me, SPELL_GROW, true); - me->CastSpell(me, SPELL_KAEL_EXPLODES4, true); - me->CastSpell(me, SPELL_NETHERBEAM_AURA3, true); - break; - case EVENT_SCENE_7: - SetRoomState(GO_STATE_ACTIVE); - me->SetUnitMovementFlags(MOVEMENTFLAG_HOVER | MOVEMENTFLAG_WALKING | MOVEMENTFLAG_DISABLE_GRAVITY); - me->SendMovementFlagUpdate(); - break; - case EVENT_SCENE_8: - summons.DespawnEntry(WORLD_TRIGGER); - me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA1); - me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA2); - me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA3); - me->CastSpell(me, SPELL_KAEL_EXPLODES5, true); - me->CastSpell(me, SPELL_FLOATING_DROWNED, false); - //me->CastSpell(me, SPELL_KEAL_STUNNED, true); - break; - case EVENT_SCENE_9: - me->CastSpell(me, 52241, true); // WRONG VISUAL - me->CastSpell(me, 34807, true); - me->SummonCreature(NPC_WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); - break; - case EVENT_SCENE_10: - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); - break; - case EVENT_SCENE_11: - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); - break; - case EVENT_SCENE_12: - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); - break; - case EVENT_SCENE_13: - if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); - break; - case EVENT_SCENE_14: - //if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX()-5, me->GetPositionY()+5, me->GetPositionZ()+15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) - // trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); - break; - case EVENT_SCENE_15: - me->RemoveAurasDueToSpell(SPELL_FLOATING_DROWNED); - me->RemoveAurasDueToSpell(SPELL_KEAL_STUNNED); - me->CastSpell(me, SPELL_KAEL_FULL_POWER, false); - me->CastSpell(me, 36709, true); - me->CastSpell(me, 36201, true); - me->CastSpell(me, 36290, true); - me->CastSpell(me, 36291, true); - me->SetUnitMovementFlags(MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_WALKING); - me->SendMovementFlagUpdate(); - break; - case EVENT_SCENE_16: - summons.DespawnEntry(WORLD_TRIGGER); - me->RemoveAurasDueToSpell(52241); // WRONG VISUAL - me->GetMotionMaster()->MovePoint(POINT_START_LAST_PHASE, me->GetHomePosition(), false, true); - break; - } - - if (!events2.Empty()) - return; - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_SEQ_1: - events.ScheduleEvent(EVENT_SPELL_MIND_CONTROL, 0); - events.ScheduleEvent(EVENT_SPELL_ARCANE_DISRUPTION, 3000); - events.ScheduleEvent(EVENT_SPELL_SEQ_1, 50000); - break; - case EVENT_SPELL_SEQ_2: - events.ScheduleEvent(EVENT_SPELL_MIND_CONTROL, 3000); - events.ScheduleEvent(EVENT_SPELL_ARCANE_DISRUPTION, 6000); - events.ScheduleEvent(EVENT_SPELL_SEQ_2, 50000); - break; - case EVENT_SPELL_SEQ_3: - Talk(SAY_PYROBLAST); - me->CastSpell(me, SPELL_SHOCK_BARRIER, false); - events.ScheduleEvent(EVENT_SPELL_SEQ_3, 50000); - events.DelayEvents(10000); - events.ScheduleEvent(EVENT_SPELL_PYROBLAST, 0); - events.ScheduleEvent(EVENT_SPELL_PYROBLAST, 4000); - events.ScheduleEvent(EVENT_SPELL_PYROBLAST, 8000); - break; - case EVENT_SPELL_SHOCK_BARRIER: - me->CastSpell(me, SPELL_SHOCK_BARRIER, false); - break; - case EVENT_SPELL_FIREBALL: - me->CastSpell(me->GetVictim(), SPELL_FIREBALL, false); - events.ScheduleEvent(EVENT_SPELL_FIREBALL, roll_chance_i(70) ? 2000 : 4000); - break; - case EVENT_SPELL_PYROBLAST: - me->CastSpell(me->GetVictim(), SPELL_PYROBLAST, false); - break; - case EVENT_SPELL_FLAMESTRIKE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) - me->CastSpell(target, SPELL_FLAME_STRIKE, false); - events.ScheduleEvent(EVENT_SPELL_FLAMESTRIKE, 20000); - break; - case EVENT_SPELL_ARCANE_DISRUPTION: - me->CastSpell(me, SPELL_ARCANE_DISRUPTION, false); - break; - case EVENT_SPELL_MIND_CONTROL: - if (roll_chance_i(50)) - Talk(SAY_MINDCONTROL); - me->CastCustomSpell(SPELL_MIND_CONTROL, SPELLVALUE_MAX_TARGETS, 3, me, false); - break; - case EVENT_SPELL_SUMMON_PHOENIX: - Talk(SAY_SUMMON_PHOENIX); - me->CastSpell(me, SPELL_PHOENIX, false); - events.ScheduleEvent(EVENT_SPELL_SUMMON_PHOENIX, 40000); - break; - case EVENT_CHECK_HEALTH: - if (me->HealthBelowPct(51)) - { - events.Reset(); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->MovePoint(POINT_MIDDLE, me->GetHomePosition(), true, true); - me->ClearUnitState(UNIT_STATE_MELEE_ATTACKING); - me->SendMeleeAttackStop(); - break; - } - events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000); - break; - case EVENT_SPELL_GRAVITY_LAPSE: - events.DelayEvents(30000); - me->setAttackTimer(BASE_ATTACK, 30000); - events.ScheduleEvent(EVENT_SPELL_GRAVITY_LAPSE, 90000); - events.ScheduleEvent(EVENT_GRAVITY_LAPSE_END, 32000); - events.ScheduleEvent(EVENT_SPELL_SHOCK_BARRIER, 20000); - events.ScheduleEvent(EVENT_SPELL_SHOCK_BARRIER, 10000); - events.ScheduleEvent(EVENT_SPELL_NETHER_BEAM, 4000); - events.ScheduleEvent(EVENT_SPELL_NETHER_VAPOR, 0); - me->CastSpell(me, SPELL_SHOCK_BARRIER, false); - me->CastSpell(me, SPELL_GRAVITY_LAPSE, false); - me->SetTarget(); - me->GetMotionMaster()->Clear(); - me->StopMoving(); - Talk(SAY_GRAVITYLAPSE); - break; - case EVENT_SPELL_NETHER_VAPOR: - me->CastSpell(me, SPELL_SUMMON_NETHER_VAPOR, false); - break; - case EVENT_SPELL_NETHER_BEAM: - me->CastSpell(me, SPELL_NETHER_BEAM, false); - events.ScheduleEvent(EVENT_SPELL_NETHER_BEAM, 4000); - break; - case EVENT_GRAVITY_LAPSE_END: summons.DespawnEntry(NPC_NETHER_VAPOR); - events.CancelEvent(EVENT_SPELL_NETHER_BEAM); + scheduler.CancelGroup(GROUP_NETHER_BEAM); me->SetTarget(me->GetVictim()->GetGUID()); me->GetMotionMaster()->MoveChase(me->GetVictim()); - break; + }); + me->SetTarget(); + me->GetMotionMaster()->Clear(); + me->StopMoving(); + Talk(SAY_GRAVITYLAPSE); + }, 90s); + if (me->GetVictim()) + { + me->SetTarget(me->GetVictim()->GetGUID()); + AttackStart(me->GetVictim()); } - - DoMeleeAttackIfReady(); } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return me->GetHomePosition().GetExactDist2d(me) > 165.0f || !SelectTargetFromPlayerList(165.0f); - } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetTheEyeAI(creature); } -}; + void ExecuteMiddleEvent() + { + scheduler.ClearValidator(); + me->SetTarget(); + me->SetFacingTo(M_PI); + me->SetWalk(true); + Talk(SAY_PHASE5_NUTS); + ScheduleUniqueTimedEvent(2500ms, [&] + { + me->SetTarget(); + DoCastSelf(SPELL_KAEL_EXPLODES1, true); + DoCastSelf(SPELL_KAEL_GAINING_POWER); + me->SetDisableGravity(true); + }, EVENT_SCENE_2); + ScheduleUniqueTimedEvent(4000ms, [&] + { + me->SetTarget(); + for (uint8 i = 0; i < 2; ++i) + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i], TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); + me->GetMotionMaster()->MovePoint(POINT_AIR, me->GetPositionX(), me->GetPositionY(), 76.0f, false, true); + DoCastSelf(SPELL_GROW, true); + }, EVENT_SCENE_3); + ScheduleUniqueTimedEvent(7000ms, [&] + { + me->SetTarget(); + DoCastSelf(SPELL_GROW, true); + DoCastSelf(SPELL_KAEL_EXPLODES2, true); + DoCastSelf(SPELL_NETHERBEAM_AURA1, true); + for (uint8 i = 0; i < 2; ++i) + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i + 2], TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); + }, EVENT_SCENE_4); + ScheduleUniqueTimedEvent(10000ms, [&] + { + me->SetTarget(); + DoCastSelf(SPELL_GROW, true); + DoCastSelf(SPELL_KAEL_EXPLODES3, true); + DoCastSelf(SPELL_NETHERBEAM_AURA2, true); + for (uint8 i = 0; i < 2; ++i) + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, triggersPos[i + 4], TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_NETHERBEAM1 + i, false); + }, EVENT_SCENE_5); + ScheduleUniqueTimedEvent(14000ms, [&] + { + DoCastSelf(SPELL_GROW, true); + DoCastSelf(SPELL_KAEL_EXPLODES4, true); + DoCastSelf(SPELL_NETHERBEAM_AURA3, true); + }, EVENT_SCENE_6); + ScheduleUniqueTimedEvent(17500ms, [&] + { + SetRoomState(GO_STATE_ACTIVE); + me->SetUnitMovementFlags(MOVEMENTFLAG_HOVER | MOVEMENTFLAG_WALKING | MOVEMENTFLAG_DISABLE_GRAVITY); + me->SendMovementFlagUpdate(); + }, EVENT_SCENE_7); + ScheduleUniqueTimedEvent(19000ms, [&] + { + summons.DespawnEntry(WORLD_TRIGGER); + me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA1); + me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA2); + me->RemoveAurasDueToSpell(SPELL_NETHERBEAM_AURA3); + DoCastSelf(SPELL_KAEL_EXPLODES5, true); + DoCastSelf(SPELL_FLOATING_DROWNED); + //me->CastSpell(me, SPELL_KEAL_STUNNED, true); + }, EVENT_SCENE_8); + ScheduleUniqueTimedEvent(22000ms, [&] + { + DoCastSelf(SPELL_DARK_BANISH_STATE, true); + DoCastSelf(SPELL_ARCANE_EXPLOSION_VISUAL, true); + me->SummonCreature(NPC_WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY(), me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); + }, EVENT_SCENE_9); + ScheduleUniqueTimedEvent(22800ms, [&] + { + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); + }, EVENT_SCENE_10); + ScheduleUniqueTimedEvent(23600ms, [&] + { + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); + }, EVENT_SCENE_11); + ScheduleUniqueTimedEvent(24500ms, [&] + { + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX(), me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() + 5, me->GetPositionY() - 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM1, true); + }, EVENT_SCENE_12); + ScheduleUniqueTimedEvent(24800ms, [&] + { + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX() - 5, me->GetPositionY() + 5, me->GetPositionZ() + 15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM2, true); + }, EVENT_SCENE_13); + ScheduleUniqueTimedEvent(25300ms, [&] + { + if (Creature* trigger = me->SummonCreature(WORLD_TRIGGER, me->GetPositionX()-5, me->GetPositionY()+5, me->GetPositionZ()+15.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000)) + trigger->CastSpell(me, SPELL_PURE_NETHER_BEAM3, true); + }, EVENT_SCENE_14); + ScheduleUniqueTimedEvent(32000ms, [&] + { + me->RemoveAurasDueToSpell(SPELL_FLOATING_DROWNED); + me->RemoveAurasDueToSpell(SPELL_KEAL_STUNNED); + DoCastSelf(SPELL_KAEL_FULL_POWER); + DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + DoCastSelf(SPELL_PURE_NETHER_BEAM4, true); + DoCastSelf(SPELL_PURE_NETHER_BEAM5, true); + DoCastSelf(SPELL_PURE_NETHER_BEAM6, true); + me->SetUnitMovementFlags(MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_WALKING); + me->SendMovementFlagUpdate(); + }, EVENT_SCENE_15); + ScheduleUniqueTimedEvent(36000ms, [&] + { + summons.DespawnEntry(WORLD_TRIGGER); + me->CastStop(); + me->GetMotionMaster()->Clear(); + me->RemoveAurasDueToSpell(SPELL_DARK_BANISH_STATE); // WRONG VISUAL + me->GetMotionMaster()->MovePoint(POINT_START_LAST_PHASE, me->GetHomePosition(), false, true); + }, EVENT_SCENE_16); + } + + void IntroduceNewAdvisor(Yells talkIntroduction, KaelActions kaelAction) + { + std::chrono::milliseconds attackStartTimer = 0ms; + EyeNPCs advisorNPCId = NPC_THALADRED; + scheduler.Schedule(2s, [this, talkIntroduction](TaskContext) + { + Talk(talkIntroduction); + }); + //switch because talk times are different + switch(kaelAction) + { + case ACTION_START_SANGUINAR: + attackStartTimer = 14500ms; + advisorNPCId = NPC_LORD_SANGUINAR; + break; + case ACTION_START_CAPERNIAN: + attackStartTimer = 9000ms; + advisorNPCId = NPC_CAPERNIAN; + break; + case ACTION_START_TELONICUS: + attackStartTimer = 10400ms; + advisorNPCId = NPC_TELONICUS; + break; + default: + break; + } + scheduler.Schedule(attackStartTimer, [this, advisorNPCId](TaskContext) + { + if (Creature* advisor = summons.GetCreatureWithEntry(advisorNPCId)) + { + advisor->SetReactState(REACT_AGGRESSIVE); + advisor->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + advisor->AI()->AttackStart(target); + advisor->SetInCombatWithZone(); + } + }); + } + + void PhaseAllAdvisorsExecute() + { + //remove all weapons so they don't get revived + summons.DoForAllSummons([&](WorldObject* summon) + { + if (Creature* summonedCreature = summon->ToCreature()) + { + if (summonedCreature->GetEntry() >= 21268 && summonedCreature->GetEntry() <= 21274) + { + summonedCreature->DespawnOrUnsummon(); + } + } + }); + _phase = PHASE_ALL_ADVISORS; + Talk(SAY_PHASE3_ADVANCE); + ScheduleUniqueTimedEvent(6s, [&]{ + DoCastSelf(SPELL_RESURRECTION); + }, EVENT_PREFIGHT_PHASE62); + ScheduleUniqueTimedEvent(12s, [&]{ + summons.DoForAllSummons([&](WorldObject* summon) + { + if (Creature* summonedCreature = summon->ToCreature()) + { + if (summonedCreature->GetSpawnId()) + { + summonedCreature->SetReactState(REACT_AGGRESSIVE); + summonedCreature->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + summonedCreature->SetInCombatWithZone(); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + summonedCreature->AI()->AttackStart(target); + } + } + } + }); + ScheduleUniqueTimedEvent(3min, [&]{ + PhaseKaelExecute(); + }, EVENT_PREFIGHT_PHASE71); + }, EVENT_PREFIGHT_PHASE63); + } + + void PhaseKaelExecute() + { + scheduler.CancelAll(); + Talk(SAY_PHASE4_INTRO2); + _phase = PHASE_FINAL; + DoResetThreatList(); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + AttackStart(target); + } + ScheduleTimedEvent(1000ms, [&] + { + DoCastVictim(SPELL_FIREBALL); + }, 2400ms, 7500ms); + ScheduleTimedEvent(15000ms, [&] + { + DoCastRandomTarget(SPELL_FLAME_STRIKE, 0, 100.0f); + }, 30250ms, 50650ms); + ScheduleTimedEvent(30000ms, [&] + { + Talk(SAY_SUMMON_PHOENIX); + DoCastSelf(SPELL_PHOENIX); + }, 31450ms, 66550ms); + //sequence + ScheduleTimedEvent(20s, [&] + { + if (roll_chance_i(50)) + Talk(SAY_MINDCONTROL); + me->CastCustomSpell(SPELL_MIND_CONTROL, SPELLVALUE_MAX_TARGETS, 3, me, false); + scheduler.Schedule(3s, [this](TaskContext) + { + DoCastSelf(SPELL_ARCANE_DISRUPTION); + }); + }, 50s); + ScheduleTimedEvent(40s, [&] + { + scheduler.Schedule(3s, [this](TaskContext) + { + if (roll_chance_i(50)) + Talk(SAY_MINDCONTROL); + me->CastCustomSpell(SPELL_MIND_CONTROL, SPELLVALUE_MAX_TARGETS, 3, me, false); + }).Schedule(6s, [this](TaskContext) + { + DoCastSelf(SPELL_ARCANE_DISRUPTION); + }); + }, 50s); + ScheduleTimedEvent(60s, [&] + { + Talk(SAY_PYROBLAST); + DoCastSelf(SPELL_SHOCK_BARRIER); + scheduler.DelayAll(10s); + scheduler.Schedule(0s, GROUP_PYROBLAST, [this](TaskContext context) + { + DoCastVictim(SPELL_PYROBLAST); + context.Repeat(4s); + }).Schedule(8500ms, GROUP_PYROBLAST, [this](TaskContext) + { + scheduler.CancelGroup(GROUP_PYROBLAST); + }); + }, 50s); + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + + bool CheckEvadeIfOutOfCombatArea() const override + { + return me->GetHomePosition().GetExactDist2d(me) > 165.0f || !SelectTargetFromPlayerList(165.0f); + } +private: + uint32 _phase; +}; struct npc_lord_sanguinar : public ScriptedAI { npc_lord_sanguinar(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); @@ -759,10 +761,16 @@ struct npc_lord_sanguinar : public ScriptedAI void Reset() override { scheduler.CancelAll(); + _hasDied = false; + me->SetReactState(REACT_PASSIVE); } void JustEngagedWith(Unit* /*who*/) override { + if (!_hasDied) + { + Talk(SAY_SANGUINAR_AGGRO); + } ScheduleTimedEvent(0s, [&]{ DoCastSelf(SPELL_BELLOWING_ROAR); }, 15s); @@ -770,8 +778,16 @@ struct npc_lord_sanguinar : public ScriptedAI void JustDied(Unit* /*killer*/) override { - Talk(SAY_SANGUINAR_DEATH); - DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (!_hasDied) + { + Talk(SAY_SANGUINAR_DEATH); + DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS)) + { + kael->AI()->DoAction(ACTION_START_CAPERNIAN); + } + _hasDied = true; + } } void UpdateAI(uint32 diff) override @@ -786,11 +802,15 @@ struct npc_lord_sanguinar : public ScriptedAI DoMeleeAttackIfReady(); } +private: + InstanceScript* _instance; + bool _hasDied; }; struct npc_capernian : public ScriptedAI { npc_capernian(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); @@ -800,10 +820,16 @@ struct npc_capernian : public ScriptedAI void Reset() override { scheduler.CancelAll(); + _hasDied = false; + me->SetReactState(REACT_PASSIVE); } void JustEngagedWith(Unit* /*who*/) override { + if (!_hasDied) + { + Talk(SAY_CAPERNIAN_AGGRO); + } ScheduleTimedEvent(0ms, [&]{ DoCastVictim(SPELL_CAPERNIAN_FIREBALL); }, 2500ms); @@ -817,8 +843,16 @@ struct npc_capernian : public ScriptedAI void JustDied(Unit* /*killer*/) override { - Talk(SAY_CAPERNIAN_DEATH); - DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (!_hasDied) + { + Talk(SAY_CAPERNIAN_DEATH); + DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS)) + { + kael->AI()->DoAction(ACTION_START_TELONICUS); + } + _hasDied = true; + } } void UpdateAI(uint32 diff) override @@ -833,11 +867,15 @@ struct npc_capernian : public ScriptedAI DoMeleeAttackIfReady(); } +private: + InstanceScript* _instance; + bool _hasDied; }; struct npc_telonicus : public ScriptedAI { npc_telonicus(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); @@ -847,10 +885,16 @@ struct npc_telonicus : public ScriptedAI void Reset() override { scheduler.CancelAll(); + _hasDied = false; + me->SetReactState(REACT_PASSIVE); } void JustEngagedWith(Unit* /*who*/) override { + if (!_hasDied) + { + Talk(SAY_TELONICUS_AGGRO); + } ScheduleTimedEvent(0ms, [&]{ DoCastVictim(SPELL_BOMB); }, 3600ms, 7100ms); @@ -861,8 +905,16 @@ struct npc_telonicus : public ScriptedAI void JustDied(Unit* /*killer*/) override { - Talk(SAY_TELONICUS_DEATH); - DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (!_hasDied) + { + Talk(SAY_TELONICUS_DEATH); + DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS)) + { + kael->AI()->DoAction(ACTION_START_WEAPONS); + } + _hasDied = true; + } } void UpdateAI(uint32 diff) override @@ -877,11 +929,15 @@ struct npc_telonicus : public ScriptedAI DoMeleeAttackIfReady(); } +private: + InstanceScript* _instance; + bool _hasDied; }; struct npc_thaladred : public ScriptedAI { npc_thaladred(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); scheduler.SetValidator([this] { return !me->HasUnitState(UNIT_STATE_CASTING); @@ -891,11 +947,17 @@ struct npc_thaladred : public ScriptedAI void Reset() override { scheduler.CancelAll(); + me->SetReactState(REACT_PASSIVE); + _hasDied = false; me->SetWalk(true); } void JustEngagedWith(Unit* /*who*/) override { + if (!_hasDied) + { + Talk(SAY_THALADRED_AGGRO); + } ScheduleTimedEvent(100ms, [&] { DoResetThreatList(); @@ -927,8 +989,16 @@ struct npc_thaladred : public ScriptedAI void JustDied(Unit* /*killer*/) override { - Talk(SAY_THALADRED_DEATH); - DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (!_hasDied) + { + Talk(SAY_THALADRED_DEATH); + DoCastSelf(SPELL_KAEL_PHASE_TWO, true); + if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS)) + { + kael->AI()->DoAction(ACTION_START_SANGUINAR); + } + _hasDied = true; + } } void UpdateAI(uint32 diff) override @@ -943,6 +1013,9 @@ struct npc_thaladred : public ScriptedAI DoMeleeAttackIfReady(); } +private: + InstanceScript* _instance; + bool _hasDied; }; class spell_kaelthas_kael_phase_two : public SpellScriptLoader @@ -1275,7 +1348,7 @@ public: void AddSC_boss_kaelthas() { - new boss_kaelthas(); + RegisterTheEyeAI(boss_kaelthas); RegisterTheEyeAI(npc_lord_sanguinar); RegisterTheEyeAI(npc_capernian); RegisterTheEyeAI(npc_telonicus); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp index 8b1ce688b..c02375e37 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp @@ -20,6 +20,21 @@ #include "SpellScriptLoader.h" #include "the_eye.h" +ObjectData const creatureData[] = +{ + { NPC_KAELTHAS, DATA_KAELTHAS }, + { NPC_THALADRED, DATA_THALADRED }, + { NPC_LORD_SANGUINAR, DATA_LORD_SANGUINAR }, + { NPC_CAPERNIAN, DATA_CAPERNIAN }, + { NPC_TELONICUS, DATA_TELONICUS }, + { 0, 0 } +}; + +ObjectData const gameObjectData[] = +{ + { 0, 0 } +}; + class instance_the_eye : public InstanceMapScript { public: @@ -30,6 +45,7 @@ public: instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); + LoadObjectData(creatureData, gameObjectData); SetBossNumber(MAX_ENCOUNTER); } @@ -66,6 +82,7 @@ public: LordSanguinarGUID = creature->GetGUID(); break; } + InstanceScript::OnCreatureCreate(creature); } void OnGameObjectCreate(GameObject* gobject) override @@ -98,14 +115,6 @@ public: return AlarGUID; case NPC_KAELTHAS: return KaelthasGUID; - case DATA_KAEL_ADVISOR1: - return ThaladredTheDarkenerGUID; - case DATA_KAEL_ADVISOR2: - return LordSanguinarGUID; - case DATA_KAEL_ADVISOR3: - return GrandAstromancerCapernianGUID; - case DATA_KAEL_ADVISOR4: - return MasterEngineerTelonicusGUID; } return ObjectGuid::Empty; diff --git a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h index 5961fcc2d..f66fceb71 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h +++ b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h @@ -36,10 +36,10 @@ enum EyeData DATA_KAELTHAS = 3, MAX_ENCOUNTER = 4, - DATA_KAEL_ADVISOR1 = 10, - DATA_KAEL_ADVISOR2 = 11, - DATA_KAEL_ADVISOR3 = 12, - DATA_KAEL_ADVISOR4 = 13 + DATA_THALADRED = 10, + DATA_LORD_SANGUINAR = 11, + DATA_CAPERNIAN = 12, + DATA_TELONICUS = 13 }; enum EyeNPCs