From 2c4b7c3cd4cca7ddbb367025fa4a5a4cc229de39 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 22 Mar 2026 13:38:10 -0300 Subject: [PATCH] refactor(Core/Scripts): convert Blackrock Mountain scripts to register macros (#25178) Co-authored-by: Claude Opus 4.6 (1M context) --- .../BlackrockDepths/blackrock_depths.cpp | 803 +++++---- .../BlackrockDepths/blackrock_depths.h | 3 + .../boss_ambassador_flamelash.cpp | 325 ++-- .../BlackrockDepths/boss_anubshiah.cpp | 117 +- .../boss_emperor_dagran_thaurissan.cpp | 145 +- .../BlackrockDepths/boss_eviscerator.cpp | 101 +- .../boss_general_angerforge.cpp | 156 +- .../boss_gorosh_the_dervish.cpp | 99 +- .../BlackrockDepths/boss_grizzle.cpp | 90 +- .../BlackrockDepths/boss_hedrum.cpp | 91 +- .../boss_high_interrogator_gerstahn.cpp | 108 +- .../BlackrockDepths/boss_magmus.cpp | 78 +- .../boss_moira_bronzebeard.cpp | 52 +- .../BlackrockDepths/boss_okthor.cpp | 122 +- .../BlackrockDepths/boss_tomb_of_seven.cpp | 218 ++- .../instance_blackrock_depths.cpp | 1341 ++++++++-------- .../BlackrockSpire/blackrock_spire.h | 1 + .../BlackrockSpire/boss_drakkisath.cpp | 161 +- .../BlackrockSpire/boss_gyth.cpp | 187 +-- .../BlackrockSpire/boss_halycon.cpp | 95 +- .../BlackrockSpire/boss_highlord_omokk.cpp | 89 +- .../BlackrockSpire/boss_lord_valthalak.cpp | 247 ++- .../BlackrockSpire/boss_mor_grayhoof.cpp | 10 - .../boss_overlord_wyrmthalak.cpp | 136 +- .../boss_pyroguard_emberseer.cpp | 580 ++++--- .../boss_quartermaster_zigris.cpp | 6 - .../BlackrockSpire/boss_rend_blackhand.cpp | 569 ++++--- .../boss_solakar_flamewreath.cpp | 315 ++-- .../BlackrockSpire/boss_the_beast.cpp | 271 ++-- .../BlackrockSpire/boss_urok_doomhowl.cpp | 117 +- .../BlackrockSpire/boss_warmaster_voone.cpp | 131 +- .../instance_blackrock_spire.cpp | 1428 ++++++++--------- .../BlackwingLair/blackwing_lair.h | 1 + .../boss_broodlord_lashlayer.cpp | 315 ++-- .../BlackwingLair/boss_chromaggus.cpp | 314 ++-- .../BlackwingLair/boss_ebonroc.cpp | 109 +- .../BlackwingLair/boss_firemaw.cpp | 89 +- .../BlackwingLair/boss_flamegor.cpp | 91 +- .../BlackwingLair/boss_nefarian.cpp | 589 +++---- .../BlackwingLair/boss_razorgore.cpp | 382 ++--- .../BlackwingLair/boss_vaelastrasz.cpp | 371 ++--- .../BlackwingLair/instance_blackwing_lair.cpp | 651 ++++---- .../MoltenCore/boss_baron_geddon.cpp | 149 +- .../MoltenCore/boss_garr.cpp | 166 +- .../MoltenCore/boss_gehennas.cpp | 89 +- .../MoltenCore/boss_golemagg.cpp | 286 ++-- .../MoltenCore/boss_lucifron.cpp | 67 +- .../MoltenCore/boss_magmadar.cpp | 99 +- .../MoltenCore/boss_majordomo_executus.cpp | 808 +++++----- .../MoltenCore/boss_ragnaros.cpp | 659 ++++---- .../MoltenCore/boss_shazzrah.cpp | 109 +- .../MoltenCore/boss_sulfuron_harbinger.cpp | 238 ++- .../MoltenCore/instance_molten_core.cpp | 693 ++++---- .../MoltenCore/molten_core.cpp | 127 +- .../MoltenCore/molten_core.h | 3 + 55 files changed, 6659 insertions(+), 7938 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp index 14ab0e15e..3409fe6fa 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp @@ -18,6 +18,7 @@ #include "blackrock_depths.h" #include "AreaTriggerScript.h" #include "CreatureScript.h" +#include "GameObjectAI.h" #include "GameObjectScript.h" #include "GameTime.h" #include "Player.h" @@ -34,93 +35,76 @@ enum IronhandData constexpr Milliseconds IRONHAND_FLAMES_TIMER = 16s; constexpr Milliseconds IRONHAND_FLAMES_TIMER_RAND = 3s; -class go_shadowforge_brazier : public GameObjectScript +struct go_shadowforge_brazier : public GameObjectAI { -public: - go_shadowforge_brazier() : GameObjectScript("go_shadowforge_brazier") {} + go_shadowforge_brazier(GameObject* go) : GameObjectAI(go) {} - bool OnGossipHello(Player* /*player*/, GameObject* go) override + bool GossipHello(Player* /*player*/, bool /*reportUse*/) override { - if (InstanceScript* instance = go->GetInstanceScript()) + if (InstanceScript* instance = me->GetInstanceScript()) { - GameObject* northBrazier = ObjectAccessor::GetGameObject(*go, instance->GetGuidData(DATA_SF_BRAZIER_N)); - GameObject* southBrazier = ObjectAccessor::GetGameObject(*go, instance->GetGuidData(DATA_SF_BRAZIER_S)); + GameObject* northBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_N)); + GameObject* southBrazier = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SF_BRAZIER_S)); if (!northBrazier || !southBrazier) - { return false; - } // should only happen on first brazier if (instance->GetData(TYPE_LYCEUM) == NOT_STARTED) - { instance->SetData(TYPE_LYCEUM, IN_PROGRESS); - } // Check if the opposite brazier is lit - if it is, open the gates. - if ((go->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (go->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE)) + if ((me->GetGUID() == northBrazier->GetGUID() && southBrazier->GetGoState() == GO_STATE_ACTIVE) || (me->GetGUID() == southBrazier->GetGUID() && northBrazier->GetGoState() == GO_STATE_ACTIVE)) { instance->SetData(TYPE_LYCEUM, DONE); } return false; } return false; - }; + } }; -class ironhand_guardian : public CreatureScript +struct brd_ironhand_guardian : public CreatureAI { -public: - ironhand_guardian() : CreatureScript("brd_ironhand_guardian") {} + brd_ironhand_guardian(Creature* creature) : CreatureAI(creature) {} - CreatureAI* GetAI(Creature* creature) const override + void SetData(uint32 id, uint32 value) override { - return GetBlackrockDepthsAI(creature); + if (id == 0) + if (value == 0 || value == 1) + { + _flamesEnabled = (bool) (value); + events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS); + } } - struct ironhand_guardianAI : public CreatureAI + void UpdateAI(uint32 diff) override { - ironhand_guardianAI(Creature* creature) : CreatureAI(creature) {} - bool flames_enabled = false; + events.Update(diff); - void SetData(uint32 id, uint32 value) override + if (_flamesEnabled) { - if (id == 0) + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - if (value == 0 || value == 1) + switch (eventId) { - flames_enabled = (bool) (value); - events.ScheduleEvent(SPELL_GOUT_OF_FLAMES, urand(1, IRONHAND_N_GROUPS) * IRONHAND_FLAMES_TIMER / IRONHAND_N_GROUPS); + case SPELL_GOUT_OF_FLAMES: + DoCast(SPELL_GOUT_OF_FLAMES); + events.RescheduleEvent(SPELL_GOUT_OF_FLAMES, IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND); + break; + default: + break; } } } + } - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if (flames_enabled) - { - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_GOUT_OF_FLAMES: - DoCast(SPELL_GOUT_OF_FLAMES); - events.RescheduleEvent(SPELL_GOUT_OF_FLAMES, IRONHAND_FLAMES_TIMER - IRONHAND_FLAMES_TIMER_RAND, IRONHAND_FLAMES_TIMER + IRONHAND_FLAMES_TIMER_RAND); - break; - default: - break; - } - } - } - } - EventMap events; - }; +private: + bool _flamesEnabled = false; + EventMap events; }; struct WaveCreature @@ -159,13 +143,10 @@ public: { time_t now = GameTime::GetGameTime().count(); if (instance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || instance->GetData(TYPE_RING_OF_LAW) == DONE) - { return false; - } + if (now - instance->GetData(DATA_TIME_RING_FAIL) < 2 * 60) // in case of wipe, so people can rez. - { return false; - } instance->SetData(TYPE_RING_OF_LAW, IN_PROGRESS); return true; @@ -185,249 +166,232 @@ enum GrimstoneTexts SAY_TEXT6 = 5 }; -class npc_grimstone : public CreatureScript +struct npc_grimstone : public npc_escortAI { -public: - npc_grimstone() : CreatureScript("npc_grimstone") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_grimstone(Creature* creature) : npc_escortAI(creature), summons(me) { - return GetBlackrockDepthsAI(creature); + instance = creature->GetInstanceScript(); + MobSpawnId = instance ? instance->GetData(DATA_ARENA_MOBS) : urand(0, 5); + BossSpawnId = instance ? instance->GetData(DATA_ARENA_BOSS) : urand(0, 5); + eventPhase = 0; + eventTimer = 1000; + resetTimer = 0; + theldrenEvent = false; + summons.DespawnAll(); } - struct npc_grimstoneAI : public npc_escortAI + InstanceScript* instance; + SummonList summons; + + uint8 eventPhase; + uint32 eventTimer; + uint32 resetTimer; + uint8 MobSpawnId; + uint8 BossSpawnId; + bool theldrenEvent; + + void Reset() override { - npc_grimstoneAI(Creature* creature) : npc_escortAI(creature), summons(me) + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + if (Unit* target = SelectTargetFromPlayerList(100.0f)) + summon->AI()->AttackStart(target); + } + + void SummonedCreatureDies(Creature* summon, Unit*) override + { + summons.Despawn(summon); + // All Summons killed, next phase + if (summons.empty()) { - instance = creature->GetInstanceScript(); - MobSpawnId = instance ? instance->GetData(DATA_ARENA_MOBS) : urand(0, 5); - BossSpawnId = instance ? instance->GetData(DATA_ARENA_BOSS) : urand(0, 5); - eventPhase = 0; - eventTimer = 1000; resetTimer = 0; - theldrenEvent = false; - summons.DespawnAll(); + eventTimer = 5000; } + } - InstanceScript* instance; - SummonList summons; - - uint8 eventPhase; - uint32 eventTimer; - uint32 resetTimer; - uint8 MobSpawnId; - uint8 BossSpawnId; - bool theldrenEvent; - - void Reset() override + void WaypointReached(uint32 waypointId) override + { + switch (waypointId) { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - if (Unit* target = SelectTargetFromPlayerList(100.0f)) - summon->AI()->AttackStart(target); - } - - void SummonedCreatureDies(Creature* summon, Unit*) override - { - summons.Despawn(summon); - // All Summons killed, next phase - if (summons.empty()) - { - resetTimer = 0; + case 0: + Talk(SAY_TEXT1); + SetEscortPaused(true); eventTimer = 5000; - } + break; + case 1: + Talk(SAY_TEXT2); + SetEscortPaused(true); + eventTimer = 5000; + break; + case 2: + SetEscortPaused(true); + break; + case 3: + Talk(SAY_TEXT3); + break; + case 4: + Talk(SAY_TEXT4); + SetEscortPaused(true); + eventTimer = 5000; + break; + case 5: + if (instance) + { + me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me); + instance->SetData(TYPE_RING_OF_LAW, DONE); + } + break; } + } - void WaypointReached(uint32 waypointId) override + void HandleGameObject(uint32 id, bool open) + { + instance->HandleGameObject(instance->GetGuidData(id), open); + } + + void SummonBoss() + { + if (me->FindNearestGameObject(GO_BANNER_OF_PROVOCATION, 100.0f)) { - switch (waypointId) + theldrenEvent = true; + me->SummonCreature(NPC_THELDREN, 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); + uint8 rand = urand(0, 4); + for (uint8 i = rand; i < rand + 4; ++i) + me->SummonCreature(theldrenTeam[i], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + else + me->SummonCreature(RingBoss[BossSpawnId], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); + resetTimer = 30000; + } + + bool updateReset(uint32 diff) + { + // as long as the summoned creatures have someone to attack, we reset the timer. + // once they don't find anyone, the timer will count down until it is smaller than diff and reset. + bool doReset = false; + if (resetTimer > 0) + { + for (auto const& sum : summons) { - case 0: - Talk(SAY_TEXT1); - SetEscortPaused(true); - eventTimer = 5000; - break; - case 1: - Talk(SAY_TEXT2); - SetEscortPaused(true); - eventTimer = 5000; - break; - case 2: - SetEscortPaused(true); - break; - case 3: - Talk(SAY_TEXT3); - break; - case 4: - Talk(SAY_TEXT4); - SetEscortPaused(true); - eventTimer = 5000; - break; - case 5: - if (instance) + if (Creature* creature = ObjectAccessor::GetCreature(*me, sum)) + { + if (creature->IsAlive() && creature->GetVictim()) { - me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, NPC_GRIMSTONE, me); - instance->SetData(TYPE_RING_OF_LAW, DONE); + resetTimer = 30000; + break; // only need to find one. } - break; + } } + + resetTimer -= diff; + if (resetTimer <= diff) + doReset = true; + } + return doReset; + } + + void SpawnWave(uint32 mobId) + { + for (uint32 i = 0; i < RingMobs[mobId].amount; i++) + me->SummonCreature(RingMobs[mobId].entry, 608.960f + 0.4f * i, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0); + resetTimer = 30000; + } + + void UpdateEscortAI(uint32 diff) override + { + if (!instance) + return; + + // reset if our mobs don't have a target. + if (updateReset(diff)) + { + summons.DespawnAll(); + HandleGameObject(DATA_ARENA4, true); + HandleGameObject(DATA_ARENA3, false); + HandleGameObject(DATA_ARENA2, false); + HandleGameObject(DATA_ARENA1, false); + instance->SetData(TYPE_RING_OF_LAW, FAIL); } - void HandleGameObject(uint32 id, bool open) + if (eventTimer) { - instance->HandleGameObject(instance->GetGuidData(id), open); - } - - void SummonBoss() - { - if (me->FindNearestGameObject(GO_BANNER_OF_PROVOCATION, 100.0f)) + if (eventTimer <= diff) { - theldrenEvent = true; - me->SummonCreature(NPC_THELDREN, 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); - uint8 rand = urand(0, 4); - for (uint8 i = rand; i < rand + 4; ++i) - me->SummonCreature(theldrenTeam[i], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); + switch (eventPhase) + { + case 0: + Talk(SAY_TEXT5); + HandleGameObject(DATA_ARENA4, false); + me->SetWalk(true); + Start(false); + eventTimer = 0; + break; + case 1: + SetEscortPaused(false); + eventTimer = 0; + break; + case 2: + eventTimer = 2000; + break; + case 3: + HandleGameObject(DATA_ARENA1, true); + eventTimer = 3000; + break; + case 4: + SetEscortPaused(false); + me->SetVisible(false); + SpawnWave(MobSpawnId); // wave 1 + eventTimer = 15000; + break; + case 5: + SpawnWave(MobSpawnId); // wave 2 + eventTimer = 0; // will be set from SummonedCreatureDies + break; + case 6: + me->SetVisible(true); + HandleGameObject(DATA_ARENA1, false); + Talk(SAY_TEXT6); + SetEscortPaused(false); + eventTimer = 0; + break; + case 7: + HandleGameObject(DATA_ARENA2, true); + eventTimer = 5000; + break; + case 8: + me->SetVisible(false); + SummonBoss(); + eventTimer = 0; + break; + case 9: + if (theldrenEvent) + { + // All objects are removed from world once tempsummons despawn, so have a player spawn it instead. + Player* player = me->SelectNearestPlayer(100.0f); + if (GameObject* go = player->SummonGameObject(GO_ARENA_SPOILS, 596.48f, -187.91f, -54.14f, 4.9f, 0.0f, 0.0f, 0.0f, 0.0f, 300)) + go->SetOwnerGUID(ObjectGuid::Empty); + + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + itr->GetSource()->KilledMonsterCredit(16166); + } + + HandleGameObject(DATA_ARENA2, false); + HandleGameObject(DATA_ARENA3, true); + HandleGameObject(DATA_ARENA4, true); + SetEscortPaused(false); + break; + } + ++eventPhase; } else - me->SummonCreature(RingBoss[BossSpawnId], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0); - resetTimer = 30000; + eventTimer -= diff; } - - bool updateReset(uint32 diff) - { - // as long as the summoned creatures have someone to attack, we reset the timer. - // once they don't find anyone, the timer will count down until it is smaller than diff and reset. - bool doReset = false; - if (resetTimer > 0) - { - for (auto const& sum : summons) - { - if (Creature* creature = ObjectAccessor::GetCreature(*me, sum)) - { - if (creature->IsAlive() && creature->GetVictim()) - { - resetTimer = 30000; - break; // only need to find one. - } - } - } - - resetTimer -= diff; - if (resetTimer <= diff) - { - doReset = true; - } - } - return doReset; - } - - void SpawnWave(uint32 mobId) - { - for (uint32 i = 0; i < RingMobs[mobId].amount; i++) - { - me->SummonCreature(RingMobs[mobId].entry, 608.960f + 0.4f * i, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - resetTimer = 30000; - } - - void UpdateEscortAI(uint32 diff) override - { - if (!instance) - return; - - // reset if our mobs don't have a target. - if (updateReset(diff)) - { - summons.DespawnAll(); - HandleGameObject(DATA_ARENA4, true); - HandleGameObject(DATA_ARENA3, false); - HandleGameObject(DATA_ARENA2, false); - HandleGameObject(DATA_ARENA1, false); - instance->SetData(TYPE_RING_OF_LAW, FAIL); - } - - if (eventTimer) - { - if (eventTimer <= diff) - { - switch (eventPhase) - { - case 0: - Talk(SAY_TEXT5); - HandleGameObject(DATA_ARENA4, false); - me->SetWalk(true); - Start(false); - eventTimer = 0; - break; - case 1: - SetEscortPaused(false); - eventTimer = 0; - break; - case 2: - eventTimer = 2000; - break; - case 3: - HandleGameObject(DATA_ARENA1, true); - eventTimer = 3000; - break; - case 4: - SetEscortPaused(false); - me->SetVisible(false); - SpawnWave(MobSpawnId); // wave 1 - eventTimer = 15000; - break; - case 5: - SpawnWave(MobSpawnId); // wave 2 - eventTimer = 0; // will be set from SummonedCreatureDies - break; - case 6: - me->SetVisible(true); - HandleGameObject(DATA_ARENA1, false); - Talk(SAY_TEXT6); - SetEscortPaused(false); - eventTimer = 0; - break; - case 7: - HandleGameObject(DATA_ARENA2, true); - eventTimer = 5000; - break; - case 8: - me->SetVisible(false); - SummonBoss(); - eventTimer = 0; - break; - case 9: - if (theldrenEvent) - { - // All objects are removed from world once tempsummons despawn, so have a player spawn it instead. - Player* player = me->SelectNearestPlayer(100.0f); - if (GameObject* go = player->SummonGameObject(GO_ARENA_SPOILS, 596.48f, -187.91f, -54.14f, 4.9f, 0.0f, 0.0f, 0.0f, 0.0f, 300)) - { - go->SetOwnerGUID(ObjectGuid::Empty); - } - - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - itr->GetSource()->KilledMonsterCredit(16166); - } - - HandleGameObject(DATA_ARENA2, false); - HandleGameObject(DATA_ARENA3, true); - HandleGameObject(DATA_ARENA4, true); - SetEscortPaused(false); - break; - } - ++eventPhase; - } - else - eventTimer -= diff; - } - } - }; + } }; // npc_phalanx @@ -438,67 +402,53 @@ enum PhalanxSpells SPELL_MIGHTYBLOW = 14099 }; -class npc_phalanx : public CreatureScript +struct npc_phalanx : public ScriptedAI { -public: - npc_phalanx() : CreatureScript("npc_phalanx") { } + npc_phalanx(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockDepthsAI(creature); + _thunderClapTimer = 12000; + _fireballVolleyTimer = 0; + _mightyBlowTimer = 15000; } - struct npc_phalanxAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - npc_phalanxAI(Creature* creature) : ScriptedAI(creature) { } + if (!UpdateVictim()) + return; - uint32 ThunderClap_Timer; - uint32 FireballVolley_Timer; - uint32 MightyBlow_Timer; - - void Reset() override + if (_thunderClapTimer <= diff) { - ThunderClap_Timer = 12000; - FireballVolley_Timer = 0; - MightyBlow_Timer = 15000; + DoCastVictim(SPELL_THUNDERCLAP); + _thunderClapTimer = 10000; + } + else _thunderClapTimer -= diff; + + if (HealthBelowPct(51)) + { + if (_fireballVolleyTimer <= diff) + { + DoCastVictim(SPELL_FIREBALLVOLLEY); + _fireballVolleyTimer = 15000; + } + else _fireballVolleyTimer -= diff; } - void UpdateAI(uint32 diff) override + if (_mightyBlowTimer <= diff) { - //Return since we have no target - if (!UpdateVictim()) - return; - - //ThunderClap_Timer - if (ThunderClap_Timer <= diff) - { - DoCastVictim(SPELL_THUNDERCLAP); - ThunderClap_Timer = 10000; - } - else ThunderClap_Timer -= diff; - - //FireballVolley_Timer - if (HealthBelowPct(51)) - { - if (FireballVolley_Timer <= diff) - { - DoCastVictim(SPELL_FIREBALLVOLLEY); - FireballVolley_Timer = 15000; - } - else FireballVolley_Timer -= diff; - } - - //MightyBlow_Timer - if (MightyBlow_Timer <= diff) - { - DoCastVictim(SPELL_MIGHTYBLOW); - MightyBlow_Timer = 10000; - } - else MightyBlow_Timer -= diff; - - DoMeleeAttackIfReady(); + DoCastVictim(SPELL_MIGHTYBLOW); + _mightyBlowTimer = 10000; } - }; + else _mightyBlowTimer -= diff; + + DoMeleeAttackIfReady(); + } + +private: + uint32 _thunderClapTimer; + uint32 _fireballVolleyTimer; + uint32 _mightyBlowTimer; }; // npc_lokhtos_darkbargainer @@ -518,12 +468,11 @@ enum LokhtosSpells SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059 }; -class npc_lokhtos_darkbargainer : public CreatureScript +struct npc_lokhtos_darkbargainer : public ScriptedAI { -public: - npc_lokhtos_darkbargainer() : CreatureScript("npc_lokhtos_darkbargainer") { } + npc_lokhtos_darkbargainer(Creature* creature) : ScriptedAI(creature) { } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); if (action == GOSSIP_ACTION_INFO_DEF + 1) @@ -532,32 +481,26 @@ public: player->CastSpell(player, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND, false); } if (action == GOSSIP_ACTION_TRADE) - player->GetSession()->SendListInventory(creature->GetGUID()); - - return true; + player->GetSession()->SendListInventory(me->GetGUID()); } - bool OnGossipHello(Player* player, Creature* creature) override + void sGossipHello(Player* player) override { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); + if (me->IsQuestGiver()) + player->PrepareQuestMenu(me->GetGUID()); - if (creature->IsVendor() && player->GetReputationRank(59) >= REP_FRIENDLY) + if (me->IsVendor() && player->GetReputationRank(59) >= REP_FRIENDLY) AddGossipItemFor(player, 4781, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); if (player->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) != 1 && !player->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) && player->HasItemCount(ITEM_SULFURON_INGOT)) - { AddGossipItemFor(player, 4781, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - } if (player->GetReputationRank(59) < REP_FRIENDLY) - SendGossipMenuFor(player, 3673, creature->GetGUID()); + SendGossipMenuFor(player, 3673, me->GetGUID()); else - SendGossipMenuFor(player, 3677, creature->GetGUID()); - - return true; + SendGossipMenuFor(player, 3677, me->GetGUID()); } }; @@ -577,19 +520,29 @@ enum RocknotQuests QUEST_ALE = 4295 }; -class npc_rocknot : public CreatureScript +struct npc_rocknot : public npc_escortAI { -public: - npc_rocknot() : CreatureScript("npc_rocknot") { } - - bool OnQuestReward(Player* /*player*/, Creature* creature, Quest const* quest, uint32 /*item*/) override + npc_rocknot(Creature* creature) : npc_escortAI(creature) + { + instance = creature->GetInstanceScript(); + } + + void Reset() override + { + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + _breakKegTimer = 0; + _breakDoorTimer = 0; + } + + void sQuestReward(Player* /*player*/, Quest const* quest, uint32 /*opt*/) override { - InstanceScript* instance = creature->GetInstanceScript(); if (!instance) - return true; + return; if (instance->GetData(TYPE_BAR) == DONE || instance->GetData(TYPE_BAR) == SPECIAL) - return true; + return; if (quest->GetQuestId() == QUEST_ALE) { @@ -601,120 +554,92 @@ public: //keep track of amount in instance script, returns SPECIAL if amount ok and event in progress if (instance->GetData(TYPE_BAR) == SPECIAL) { - creature->AI()->Talk(SAY_GOT_BEER); - creature->CastSpell(creature, SPELL_DRUNKEN_RAGE, false); - - if (npc_escortAI* escortAI = CAST_AI(npc_rocknot::npc_rocknotAI, creature->AI())) - { - creature->SetWalk(true); - escortAI->Start(false); - } + Talk(SAY_GOT_BEER); + me->CastSpell(me, SPELL_DRUNKEN_RAGE, false); + me->SetWalk(true); + Start(false); } } - - return true; } - CreatureAI* GetAI(Creature* creature) const override + void DoGo(uint32 id, uint32 state) { - return GetBlackrockDepthsAI(creature); + if (GameObject* go = instance->instance->GetGameObject(instance->GetGuidData(id))) + go->SetGoState((GOState)state); } - struct npc_rocknotAI : public npc_escortAI + void WaypointReached(uint32 waypointId) override { - npc_rocknotAI(Creature* creature) : npc_escortAI(creature) + switch (waypointId) { - instance = creature->GetInstanceScript(); + case 1: + me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); + break; + case 2: + me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); + break; + case 3: + me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); + break; + case 4: + me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); + break; + case 5: + me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); + _breakKegTimer = 2000; + break; } + } - InstanceScript* instance; - - uint32 BreakKeg_Timer; - uint32 BreakDoor_Timer; - - void Reset() override + void UpdateAI(uint32 diff) override + { + if (_breakKegTimer) { - if (HasEscortState(STATE_ESCORT_ESCORTING)) - return; - - BreakKeg_Timer = 0; - BreakDoor_Timer = 0; - } - - void DoGo(uint32 id, uint32 state) - { - if (GameObject* go = instance->instance->GetGameObject(instance->GetGuidData(id))) - go->SetGoState((GOState)state); - } - - void WaypointReached(uint32 waypointId) override - { - switch (waypointId) + if (_breakKegTimer <= diff) { - case 1: - me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); - break; - case 2: - me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); - break; - case 3: - me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED); - break; - case 4: - me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); - break; - case 5: - me->HandleEmoteCommand(EMOTE_ONESHOT_KICK); - BreakKeg_Timer = 2000; - break; + DoGo(DATA_GO_BAR_KEG, 0); + _breakKegTimer = 0; + _breakDoorTimer = 1000; } + else _breakKegTimer -= diff; } - void UpdateAI(uint32 diff) override + if (_breakDoorTimer) { - if (BreakKeg_Timer) + if (_breakDoorTimer <= diff) { - if (BreakKeg_Timer <= diff) - { - DoGo(DATA_GO_BAR_KEG, 0); - BreakKeg_Timer = 0; - BreakDoor_Timer = 1000; - } - else BreakKeg_Timer -= diff; + DoGo(DATA_GO_BAR_DOOR, 2); + DoGo(DATA_GO_BAR_KEG_TRAP, 0); //doesn't work very well, leaving code here for future + //spell by trap has effect61, this indicate the bar go hostile + + if (Unit* tmp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PHALANX))) + tmp->SetFaction(FACTION_MONSTER); + + //for later, this event(s) has alot more to it. + //optionally, DONE can trigger bar to go hostile. + instance->SetData(TYPE_BAR, DONE); + + _breakDoorTimer = 0; } - - if (BreakDoor_Timer) - { - if (BreakDoor_Timer <= diff) - { - DoGo(DATA_GO_BAR_DOOR, 2); - DoGo(DATA_GO_BAR_KEG_TRAP, 0); //doesn't work very well, leaving code here for future - //spell by trap has effect61, this indicate the bar go hostile - - if (Unit* tmp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_PHALANX))) - tmp->SetFaction(FACTION_MONSTER); - - //for later, this event(s) has alot more to it. - //optionally, DONE can trigger bar to go hostile. - instance->SetData(TYPE_BAR, DONE); - - BreakDoor_Timer = 0; - } - else BreakDoor_Timer -= diff; - } - - npc_escortAI::UpdateAI(diff); + else _breakDoorTimer -= diff; } - }; + + npc_escortAI::UpdateAI(diff); + } + +private: + InstanceScript* instance; + uint32 _breakKegTimer; + uint32 _breakDoorTimer; }; void AddSC_blackrock_depths() { - new go_shadowforge_brazier(); + RegisterBlackrockDepthsGameObjectAI(go_shadowforge_brazier); new at_ring_of_law(); - new npc_grimstone(); - new npc_phalanx(); - new npc_lokhtos_darkbargainer(); - new npc_rocknot(); - new ironhand_guardian(); + RegisterBlackrockDepthsCreatureAI(npc_grimstone); + RegisterBlackrockDepthsCreatureAI(npc_phalanx); + RegisterBlackrockDepthsCreatureAI(npc_lokhtos_darkbargainer); + RegisterBlackrockDepthsCreatureAI(npc_rocknot); + RegisterBlackrockDepthsCreatureAI(brd_ironhand_guardian); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h index 82c587049..03d6aac22 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h @@ -151,4 +151,7 @@ inline AI* GetBlackrockDepthsAI(T* obj) return GetInstanceAI(obj, BRDScriptName); } +#define RegisterBlackrockDepthsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackrockDepthsAI) +#define RegisterBlackrockDepthsGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackrockDepthsAI) + #endif diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp index e60657290..e76062bd7 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp @@ -50,219 +50,184 @@ const Position SummonPositions[7] = std::vector gobjectDwarfRunesEntry { 170578, 170579, 170580, 170581, 170582, 170583, 170584 }; -class boss_ambassador_flamelash : public CreatureScript +struct boss_ambassador_flamelash : public BossAI { -public: - boss_ambassador_flamelash() : CreatureScript("boss_ambassador_flamelash") { } + boss_ambassador_flamelash(Creature* creature) : BossAI(creature, BOSS_AMBASSADOR_FLAMELASH) { } - CreatureAI* GetAI(Creature* creature) const override + void DoAction(int32 param) override { - return GetBlackrockDepthsAI(creature); + switch (param) + { + case EVENT_SUMMON_SPIRITS: + events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); + break; + } } - struct boss_ambassador_flamelashAI : public BossAI + void Reset() override { - boss_ambassador_flamelashAI(Creature* creature) : BossAI(creature, BOSS_AMBASSADOR_FLAMELASH), summons(me) { } + _Reset(); + TurnRunes(false); + _foundValidPosition = false; + _validPosition.clear(); + } - EventMap _events; + void TurnRunes(bool mode) + { + // Active makes the runes burn, ready turns them off + GOState state = mode ? GO_STATE_ACTIVE : GO_STATE_READY; - // This will help reseting the boss - SummonList summons; + for (int RuneEntry : gobjectDwarfRunesEntry) + if (GameObject* dwarfRune = me->FindNearestGameObject(RuneEntry, 200.0f)) + dwarfRune->SetGoState(state); + } - // This will allow to find a valid position to spawn them - std::vector validPosition; - bool foundValidPosition = false; + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 2s); - void JustSummoned(Creature* cr) override { summons.Summon(cr); } + // Spawn 7 Embers initially + for (int i = 0; i < 4; ++i) + events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 4s); - void DoAction(int32 param) override + // Activate the runes (Start burning) + TurnRunes(true); + + Talk(AGGRO_TEXT); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + TurnRunes(false); + } + + int getValidRandomPosition() + { + /* Generate a random position which + * have not been used in 4 summonings. + * Since we are calling the event whenever the Spirit + * dies and not all at the time, we need to save at + * least 4 positions until reseting the vector + */ + + // Searching a new position so reset this bool check + _foundValidPosition = false; + int randomPosition; + + while (!_foundValidPosition) { - switch (param) + /* When we have summoned 4 creatures, reset the vector + * so we can summon new spirits in other positions.*/ + if (_validPosition.size() == 4) + _validPosition.clear(); + + // The random ranges from the position 0 to the position 6 + randomPosition = urand(0, 6); + + // When we have an empty vector we can use any random position generated. + if (_validPosition.empty()) + _foundValidPosition = true; + + /* This check is done to avoid running the vector + * when it is empty. Because if it is empty, then any + * position can be used to summon Spirits. + */ + if (!_foundValidPosition) { - case EVENT_SUMMON_SPIRITS: - _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); - break; - } - } - - void Reset() override - { - _events.Reset(); - summons.DespawnAll(); - TurnRunes(false); - foundValidPosition = false; - validPosition.clear(); - } - - void TurnRunes(bool mode) - { - // Active makes the runes burn, ready turns them off - GOState state = mode ? GO_STATE_ACTIVE : GO_STATE_READY; - - for (int RuneEntry : gobjectDwarfRunesEntry) - if (GameObject* dwarfRune = me->FindNearestGameObject(RuneEntry, 200.0f)) - dwarfRune->SetGoState(state); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 2s); - - // Spawn 7 Embers initially - for (int i = 0; i < 4; ++i) - _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 4s); - - // Activate the runes (Start burning) - TurnRunes(true); - - Talk(AGGRO_TEXT); - } - - void JustDied(Unit* /*killer*/) override - { - TurnRunes(false); - _events.Reset(); - summons.DespawnAll(); - } - - int getValidRandomPosition() - { - /* Generate a random position which - * have not been used in 4 summonings. - * Since we are calling the event whenever the Spirit - * dies and not all at the time, we need to save at - * least 4 positions until reseting the vector - */ - - // Searching a new position so reset this bool check - foundValidPosition = false; - int randomPosition; - - while (!foundValidPosition) - { - /* When we have summoned 4 creatures, reset the vector - * so we can summon new spirits in other positions.*/ - if (validPosition.size() == 4) - validPosition.clear(); - - // The random ranges from the position 0 to the position 6 - randomPosition = urand(0, 6); - - // When we have an empty vector we can use any random position generated. - if (validPosition.empty()) - foundValidPosition = true; - - /* This check is done to avoid running the vector - * when it is empty. Because if it is empty, then any - * position can be used to summon Spirits. - */ - if (!foundValidPosition) + // Check every position inside the vector + for (int pos : _validPosition) { - // Check every position inside the vector - for (int pos : validPosition) + // If the random is different, we found a temporary true, + // until we find one that is equal, which means it has been used. + if (pos != randomPosition) + _foundValidPosition = true; + else { - // If the random is different, we found a temporary true, - // until we find one that is equal, which means it has been used. - if (pos != randomPosition) - foundValidPosition = true; - else - { - foundValidPosition = false; - break; - } + _foundValidPosition = false; + break; } } } - - // We found a valid position. Save it and return it to summon. - validPosition.emplace_back(randomPosition); - return randomPosition; } - void SummonSpirits() + // We found a valid position. Save it and return it to summon. + _validPosition.emplace_back(randomPosition); + return randomPosition; + } + + void SummonSpirits() + { + // Make the Spirits chase Ambassador Flamelash + me->SummonCreature(NPC_FIRE_SPIRIT, SummonPositions[getValidRandomPosition()], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); + } + + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + switch (events.ExecuteEvent()) { - // Make the Spirits chase Ambassador Flamelash - me->SummonCreature(NPC_FIRE_SPIRIT, SummonPositions[getValidRandomPosition()], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60 * IN_MILLISECONDS); - _events.ScheduleEvent(EVENT_SUMMON_SPIRITS, 12s, 14s); + case EVENT_SPELL_FIREBLAST: + DoCastVictim(SPELL_FIREBLAST); + events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s); + break; + case EVENT_SUMMON_SPIRITS: + SummonSpirits(); + break; } - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; + DoMeleeAttackIfReady(); + } - _events.Update(diff); - - switch (_events.ExecuteEvent()) - { - case EVENT_SPELL_FIREBLAST: - DoCastVictim(SPELL_FIREBLAST); - _events.ScheduleEvent(EVENT_SPELL_FIREBLAST, 7s); - break; - case EVENT_SUMMON_SPIRITS: - SummonSpirits(); - break; - } - - DoMeleeAttackIfReady(); - } - }; +private: + // This will allow to find a valid position to spawn them + std::vector _validPosition; + bool _foundValidPosition = false; }; -class npc_burning_spirit : public CreatureScript +struct npc_burning_spirit : public ScriptedAI { -public: - npc_burning_spirit() : CreatureScript("npc_burning_spirit") { } + npc_burning_spirit(Creature* creature) : ScriptedAI(creature) {} - struct npc_burning_spiritAI : public ScriptedAI + void IsSummonedBy(WorldObject* summoner) override { - npc_burning_spiritAI(Creature* creature) : ScriptedAI(creature) {} + if (!summoner->IsCreature()) + return; - void IsSummonedBy(WorldObject* summoner) override - { - if (!summoner->IsCreature()) - { - return; - } - - _flamelasherGUID = summoner->GetGUID(); - me->GetMotionMaster()->MoveFollow(summoner->ToCreature(), 0.f, 0.f); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID)) - { - me->GetMotionMaster()->MoveFollow(flamelasher, 5.f, 0.f); - } - } - - void MovementInform(uint32 type, uint32 /*id*/) override - { - if (type != FOLLOW_MOTION_TYPE) - return; - - if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID)) - { - flamelasher->CastSpell(flamelasher, SPELL_BURNING_SPIRIT); - Unit::Kill(flamelasher, me); - } - } - - private: - EventMap _events; - ObjectGuid _flamelasherGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockDepthsAI(creature); + _flamelasherGUID = summoner->GetGUID(); + me->GetMotionMaster()->MoveFollow(summoner->ToCreature(), 0.f, 0.f); } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID)) + me->GetMotionMaster()->MoveFollow(flamelasher, 5.f, 0.f); + } + + void MovementInform(uint32 type, uint32 /*id*/) override + { + if (type != FOLLOW_MOTION_TYPE) + return; + + if (Creature* flamelasher = ObjectAccessor::GetCreature(*me, _flamelasherGUID)) + { + flamelasher->CastSpell(flamelasher, SPELL_BURNING_SPIRIT); + Unit::Kill(flamelasher, me); + } + } + +private: + ObjectGuid _flamelasherGUID; }; void AddSC_boss_ambassador_flamelash() { - new boss_ambassador_flamelash(); - new npc_burning_spirit(); + RegisterBlackrockDepthsCreatureAI(boss_ambassador_flamelash); + RegisterBlackrockDepthsCreatureAI(npc_burning_spirit); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_anubshiah.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_anubshiah.cpp index f706bf5a0..1e7a9296a 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_anubshiah.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_anubshiah.cpp @@ -34,84 +34,67 @@ constexpr Milliseconds TIMER_CURSE_WEAKNESS = 12s; constexpr Milliseconds TIMER_DEMON_ARMOR = 3s; //virtually only cast once constexpr Milliseconds TIMER_ENVELOPING_WEB = 16s; -class boss_anubshiah : public CreatureScript +struct boss_anubshiah : public BossAI { -public: - boss_anubshiah() : CreatureScript("boss_anubshiah") { } + boss_anubshiah(Creature* creature) : BossAI(creature, DATA_ANUBSHIAH) { } - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 5); + events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES / 5); + events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS / 5); + events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR / 5); + events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB / 5); } - struct boss_anubshiahAI : public BossAI + void UpdateAI(uint32 diff) override { - boss_anubshiahAI(Creature* creature) : BossAI(creature, DATA_ANUBSHIAH) { } + //Return since we have no target + if (!UpdateVictim()) + return; - void JustEngagedWith(Unit* /*who*/) override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 5); - events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES / 5); - events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS / 5); - events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR / 5); - events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB / 5); + switch (eventId) + { + case SPELL_SHADOWBOLT: + DoCastVictim(SPELL_SHADOWBOLT); + events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT - 2s, TIMER_SHADOWBOLT + 2s); + break; + case SPELL_CURSE_TONGUES: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_CURSE_TONGUES); + events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES - 2s, TIMER_CURSE_TONGUES + 2s); + break; + case SPELL_CURSE_WEAKNESS: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_CURSE_WEAKNESS); + events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS - 2s, TIMER_CURSE_WEAKNESS + 2s); + break; + case SPELL_DEMON_ARMOR: + DoCast(me, SPELL_DEMON_ARMOR); + events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR); + break; + case SPELL_ENVELOPING_WEB: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_ENVELOPING_WEB); + events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB - 2s, TIMER_ENVELOPING_WEB + 2s); + break; + default: + break; + } } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_SHADOWBOLT: - DoCastVictim(SPELL_SHADOWBOLT); - events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT - 2s, TIMER_SHADOWBOLT + 2s); - break; - case SPELL_CURSE_TONGUES: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - DoCast(target, SPELL_CURSE_TONGUES); - } - events.ScheduleEvent(SPELL_CURSE_TONGUES, TIMER_CURSE_TONGUES - 2s, TIMER_CURSE_TONGUES + 2s); - break; - case SPELL_CURSE_WEAKNESS: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - DoCast(target, SPELL_CURSE_WEAKNESS); - } - events.ScheduleEvent(SPELL_CURSE_WEAKNESS, TIMER_CURSE_WEAKNESS - 2s, TIMER_CURSE_WEAKNESS + 2s); - break; - case SPELL_DEMON_ARMOR: - DoCast(me, SPELL_DEMON_ARMOR); - events.ScheduleEvent(SPELL_DEMON_ARMOR, TIMER_DEMON_ARMOR); - break; - case SPELL_ENVELOPING_WEB: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_ENVELOPING_WEB); - events.ScheduleEvent(SPELL_ENVELOPING_WEB, TIMER_ENVELOPING_WEB - 2s, TIMER_ENVELOPING_WEB + 2s); - break; - default: - break; - } - } - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_anubshiah() { - new boss_anubshiah(); + RegisterBlackrockDepthsCreatureAI(boss_anubshiah); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp index cb97adeb7..2b725fef1 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp @@ -34,106 +34,87 @@ enum Spells #define DATA_PERCENT_DEAD_SENATORS 0 -class boss_emperor_dagran_thaurissan : public CreatureScript +struct boss_emperor_dagran_thaurissan : public BossAI { -public: - boss_emperor_dagran_thaurissan() : CreatureScript("boss_emperor_dagran_thaurissan") { } + uint32 hasYelled = 0; + uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database - CreatureAI* GetAI(Creature* creature) const override + boss_emperor_dagran_thaurissan(Creature* creature) : BossAI(creature, DATA_EMPEROR){} + + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + if (hasYelled != 5) + Talk(YELL_SENATORS_ALIVE); + else + Talk(YELL_SENATORS_DEAD); + + me->CallForHelp(VISIBLE_RANGE); + events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s); + events.ScheduleEvent(SPELL_AVATAROFFLAME, 10s, 12s); } - struct boss_draganthaurissanAI : public BossAI + void KilledUnit(Unit* /*victim*/) override { - uint32 hasYelled = 0; - uint32 SenatorYells[5] = {3, 4, 5, 6, 7}; // IDs in creature_text database + Talk(SAY_SLAY); + } - boss_draganthaurissanAI(Creature* creature) : BossAI(creature, DATA_EMPEROR){} - - void JustEngagedWith(Unit* /*who*/) override + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_PERCENT_DEAD_SENATORS) { - if (hasYelled != 5) + if (data >= 20 * (hasYelled + 1)) // map the 5 yells to %. Yell after 20,40,60,80,100% { - Talk(YELL_SENATORS_ALIVE); - } - else - { - Talk(YELL_SENATORS_DEAD); - } - - me->CallForHelp(VISIBLE_RANGE); - events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s); - events.ScheduleEvent(SPELL_AVATAROFFLAME, 10s, 12s); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } - - void SetData(uint32 type, uint32 data) override - { - if (type == DATA_PERCENT_DEAD_SENATORS) - { - if (data >= 20 * (hasYelled + 1)) // map the 5 yells to %. Yell after 20,40,60,80,100% - { - if (hasYelled < 5) - { - if (me->IsAlive()) - { - Talk(SenatorYells[hasYelled]); - } - } - hasYelled++; - } + if (hasYelled < 5) + if (me->IsAlive()) + Talk(SenatorYells[hasYelled]); + hasYelled++; } } + } - void JustDied(Unit* /*killer*/) override + void JustDied(Unit* /*killer*/) override + { + if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOIRA))) { - if (Creature* Moira = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MOIRA))) + Moira->AI()->EnterEvadeMode(); + Moira->AI()->Talk(0); + Moira->SetFaction(FACTION_FRIENDLY); + } + } + + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - Moira->AI()->EnterEvadeMode(); - Moira->AI()->Talk(0); - Moira->SetFaction(FACTION_FRIENDLY); + case SPELL_HANDOFTHAURISSAN: + DoCast(SelectTarget(SelectTargetMethod::Random), SPELL_HANDOFTHAURISSAN); + //DoCastVictim(SPELL_HANDOFTHAURISSAN); + events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s); + break; + case SPELL_AVATAROFFLAME: + DoCastSelf(SPELL_AVATAROFFLAME); + events.ScheduleEvent(SPELL_AVATAROFFLAME, 23s, 27s); + break; + default: + break; } } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_HANDOFTHAURISSAN: - DoCast(SelectTarget(SelectTargetMethod::Random), SPELL_HANDOFTHAURISSAN); - //DoCastVictim(SPELL_HANDOFTHAURISSAN); - events.ScheduleEvent(SPELL_HANDOFTHAURISSAN, 4s, 7s); - break; - case SPELL_AVATAROFFLAME: - DoCastSelf(SPELL_AVATAROFFLAME); - events.ScheduleEvent(SPELL_AVATAROFFLAME, 23s, 27s); - break; - default: - break; - } - } - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_draganthaurissan() { - new boss_emperor_dagran_thaurissan(); + RegisterBlackrockDepthsCreatureAI(boss_emperor_dagran_thaurissan); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_eviscerator.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_eviscerator.cpp index 3952b9f9c..b02b0ce31 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_eviscerator.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_eviscerator.cpp @@ -30,78 +30,65 @@ constexpr Milliseconds TIMER_SHADOWBOLT_VOLLEY = 7s; constexpr Milliseconds TIMER_REND = 20s; constexpr Milliseconds TIMER_SHIELD = 12s; -class boss_eviscerator : public CreatureScript +struct boss_eviscerator : public BossAI { -public: - boss_eviscerator() : CreatureScript("boss_eviscerator") {} + boss_eviscerator(Creature* creature) : BossAI(creature, DATA_EVISCERATOR) {} - CreatureAI* GetAI(Creature* creature) const override + bool SpellShieldReady = false; + + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY / 5); + events.ScheduleEvent(SPELL_REND, TIMER_REND / 5); + events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD / 5); } - struct boss_evisceratorAI : public BossAI + void DamageTaken(Unit* /* doneBy */, uint32& /* damage */, DamageEffectType /* damagetype */, SpellSchoolMask damageSchoolMask) override { - boss_evisceratorAI(Creature* creature) : BossAI(creature, DATA_EVISCERATOR) {} - - bool SpellShieldReady = false; - - void JustEngagedWith(Unit* /*who*/) override + if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY / 5); - events.ScheduleEvent(SPELL_REND, TIMER_REND / 5); - events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD / 5); + DoCast(SPELL_SHIELD); + SpellShieldReady = false; + events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD); } + } - void DamageTaken(Unit* /* doneBy */, uint32& /* damage */, DamageEffectType /* damagetype */, SpellSchoolMask damageSchoolMask) override + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - if ((damageSchoolMask & SPELL_SCHOOL_MASK_MAGIC) && SpellShieldReady) + switch (eventId) { - DoCast(SPELL_SHIELD); - SpellShieldReady = false; - events.ScheduleEvent(SPELL_SHIELD, TIMER_SHIELD); + case SPELL_SHADOWBOLT_VOLLEY: + DoCastVictim(SPELL_SHADOWBOLT_VOLLEY); + events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY - 2s, TIMER_SHADOWBOLT_VOLLEY + 2s); + break; + case SPELL_REND: + DoCastVictim(SPELL_REND); + events.ScheduleEvent(SPELL_REND, TIMER_REND - 2s, TIMER_REND + 2s); + break; + case SPELL_SHIELD: + SpellShieldReady = true; + break; + default: + break; } } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_SHADOWBOLT_VOLLEY: - DoCastVictim(SPELL_SHADOWBOLT_VOLLEY); - events.ScheduleEvent(SPELL_SHADOWBOLT_VOLLEY, TIMER_SHADOWBOLT_VOLLEY - 2s, TIMER_SHADOWBOLT_VOLLEY + 2s); - break; - case SPELL_REND: - DoCastVictim(SPELL_REND); - events.ScheduleEvent(SPELL_REND, TIMER_REND - 2s, TIMER_REND + 2s); - break; - case SPELL_SHIELD: - SpellShieldReady = true; - break; - default: - break; - } - } - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_eviscerator() { - new boss_eviscerator(); + RegisterBlackrockDepthsCreatureAI(boss_eviscerator); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp index d04b97eca..21b6597df 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp @@ -26,108 +26,94 @@ enum Spells SPELL_CLEAVE = 20691 }; -class boss_general_angerforge : public CreatureScript +struct boss_general_angerforge : public ScriptedAI { -public: - boss_general_angerforge() : CreatureScript("boss_general_angerforge") { } + boss_general_angerforge(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockDepthsAI(creature); + _mightyBlowTimer = 8000; + _hamStringTimer = 12000; + _cleaveTimer = 16000; + _addsTimer = 0; + _medics = false; } - struct boss_general_angerforgeAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { } + + void SummonAdds(Unit* victim) { - boss_general_angerforgeAI(Creature* creature) : ScriptedAI(creature) { } + if (Creature* SummonedAdd = DoSpawnCreature(8901, float(irand(-14, 14)), float(irand(-14, 14)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000)) + SummonedAdd->AI()->AttackStart(victim); + } - uint32 MightyBlow_Timer; - uint32 HamString_Timer; - uint32 Cleave_Timer; - uint32 Adds_Timer; - bool Medics; + void SummonMedics(Unit* victim) + { + if (Creature* SummonedMedic = DoSpawnCreature(8894, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000)) + SummonedMedic->AI()->AttackStart(victim); + } - void Reset() override + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + + if (_mightyBlowTimer <= diff) { - MightyBlow_Timer = 8000; - HamString_Timer = 12000; - Cleave_Timer = 16000; - Adds_Timer = 0; - Medics = false; + DoCastVictim(SPELL_MIGHTYBLOW); + _mightyBlowTimer = 18000; + } + else _mightyBlowTimer -= diff; + + if (_hamStringTimer <= diff) + { + DoCastVictim(SPELL_HAMSTRING); + _hamStringTimer = 15000; + } + else _hamStringTimer -= diff; + + if (_cleaveTimer <= diff) + { + DoCastVictim(SPELL_CLEAVE); + _cleaveTimer = 9000; + } + else _cleaveTimer -= diff; + + if (HealthBelowPct(21)) + { + if (_addsTimer <= diff) + { + // summon 3 Adds every 25s + SummonAdds(me->GetVictim()); + SummonAdds(me->GetVictim()); + SummonAdds(me->GetVictim()); + + _addsTimer = 25000; + } + else _addsTimer -= diff; } - void JustEngagedWith(Unit* /*who*/) override { } - - void SummonAdds(Unit* victim) + //Summon Medics + if (!_medics && HealthBelowPct(21)) { - if (Creature* SummonedAdd = DoSpawnCreature(8901, float(irand(-14, 14)), float(irand(-14, 14)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000)) - SummonedAdd->AI()->AttackStart(victim); + SummonMedics(me->GetVictim()); + SummonMedics(me->GetVictim()); + _medics = true; } - void SummonMedics(Unit* victim) - { - if (Creature* SummonedMedic = DoSpawnCreature(8894, float(irand(-9, 9)), float(irand(-9, 9)), 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 120000)) - SummonedMedic->AI()->AttackStart(victim); - } + DoMeleeAttackIfReady(); + } - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - - //MightyBlow_Timer - if (MightyBlow_Timer <= diff) - { - DoCastVictim(SPELL_MIGHTYBLOW); - MightyBlow_Timer = 18000; - } - else MightyBlow_Timer -= diff; - - //HamString_Timer - if (HamString_Timer <= diff) - { - DoCastVictim(SPELL_HAMSTRING); - HamString_Timer = 15000; - } - else HamString_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer <= diff) - { - DoCastVictim(SPELL_CLEAVE); - Cleave_Timer = 9000; - } - else Cleave_Timer -= diff; - - //Adds_Timer - if (HealthBelowPct(21)) - { - if (Adds_Timer <= diff) - { - // summon 3 Adds every 25s - SummonAdds(me->GetVictim()); - SummonAdds(me->GetVictim()); - SummonAdds(me->GetVictim()); - - Adds_Timer = 25000; - } - else Adds_Timer -= diff; - } - - //Summon Medics - if (!Medics && HealthBelowPct(21)) - { - SummonMedics(me->GetVictim()); - SummonMedics(me->GetVictim()); - Medics = true; - } - - DoMeleeAttackIfReady(); - } - }; +private: + uint32 _mightyBlowTimer; + uint32 _hamStringTimer; + uint32 _cleaveTimer; + uint32 _addsTimer; + bool _medics; }; void AddSC_boss_general_angerforge() { - new boss_general_angerforge(); + RegisterBlackrockDepthsCreatureAI(boss_general_angerforge); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_gorosh_the_dervish.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_gorosh_the_dervish.cpp index 43d93e397..449e7f801 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_gorosh_the_dervish.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_gorosh_the_dervish.cpp @@ -30,78 +30,65 @@ constexpr Milliseconds TIMER_WHIRLWIND = 12s; constexpr Milliseconds TIMER_MORTAL = 22s; constexpr Milliseconds TIMER_BLOODLUST = 30s; -class boss_gorosh_the_dervish : public CreatureScript +struct boss_gorosh_the_dervish : public BossAI { -public: - boss_gorosh_the_dervish() : CreatureScript("boss_gorosh_the_dervish") { } + boss_gorosh_the_dervish(Creature* creature) : BossAI(creature, DATA_GOROSH) { } - CreatureAI* GetAI(Creature* creature) const override + Milliseconds nextWhirlwindTime; + + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_WHIRLWIND, TIMER_WHIRLWIND / 5); + events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL / 5); + events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST / 5); } - struct boss_gorosh_the_dervishAI : public BossAI + void UpdateAI(uint32 diff) override { - boss_gorosh_the_dervishAI(Creature* creature) : BossAI(creature, DATA_GOROSH) { } + // Return since we have no target + if (!UpdateVictim()) + return; - Milliseconds nextWhirlwindTime; + events.Update(diff); - void JustEngagedWith(Unit* /*who*/) override + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_WHIRLWIND, TIMER_WHIRLWIND / 5); - events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL / 5); - events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST / 5); - } - - void UpdateAI(uint32 diff) override - { - // Return since we have no target - if (!UpdateVictim()) + switch (eventId) { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) + case SPELL_WHIRLWIND: + if (me->GetDistance2d(me->GetVictim()) < 10.0f) { - case SPELL_WHIRLWIND: - if (me->GetDistance2d(me->GetVictim()) < 10.0f) - { - DoCastVictim(SPELL_WHIRLWIND); - nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s); - } - else - { - // reschedule sooner - nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s) / 3; - } - events.ScheduleEvent(SPELL_WHIRLWIND, nextWhirlwindTime); - break; - case SPELL_MORTALSTRIKE: - DoCastVictim(SPELL_MORTALSTRIKE); - events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL - 2s, TIMER_MORTAL + 2s); - break; - case SPELL_BLOODLUST: - DoCastSelf(SPELL_BLOODLUST); - events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST - 2s, TIMER_BLOODLUST + 2s); - break; - default: - break; + DoCastVictim(SPELL_WHIRLWIND); + nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s); } + else + { + // reschedule sooner + nextWhirlwindTime = randtime(TIMER_WHIRLWIND - 2s, TIMER_WHIRLWIND + 2s) / 3; + } + events.ScheduleEvent(SPELL_WHIRLWIND, nextWhirlwindTime); + break; + case SPELL_MORTALSTRIKE: + DoCastVictim(SPELL_MORTALSTRIKE); + events.ScheduleEvent(SPELL_MORTALSTRIKE, TIMER_MORTAL - 2s, TIMER_MORTAL + 2s); + break; + case SPELL_BLOODLUST: + DoCastSelf(SPELL_BLOODLUST); + events.ScheduleEvent(SPELL_BLOODLUST, TIMER_BLOODLUST - 2s, TIMER_BLOODLUST + 2s); + break; + default: + break; } - DoMeleeAttackIfReady(); } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_gorosh_the_dervish() { - new boss_gorosh_the_dervish(); + RegisterBlackrockDepthsCreatureAI(boss_gorosh_the_dervish); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_grizzle.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_grizzle.cpp index eff584834..646f65992 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_grizzle.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_grizzle.cpp @@ -29,74 +29,60 @@ enum Grizzle constexpr Milliseconds TIMER_GROUNDTREMOR = 10s; constexpr Milliseconds TIMER_FRENZY = 15s; -class boss_grizzle : public CreatureScript +struct boss_grizzle : public BossAI { -public: - boss_grizzle() : CreatureScript("boss_grizzle") { } + boss_grizzle(Creature* creature) : BossAI(creature, DATA_GRIZZLE) {} - CreatureAI* GetAI(Creature* creature) const override + Milliseconds nextTremorTime; + + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_GROUNDTREMOR, TIMER_GROUNDTREMOR / 5); + events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY / 5); } - struct boss_grizzleAI : public BossAI + void UpdateAI(uint32 diff) override { - boss_grizzleAI(Creature* creature) : BossAI(creature, DATA_GRIZZLE) {} + //Return since we have no target + if (!UpdateVictim()) + return; - Milliseconds nextTremorTime; + events.Update(diff); - void JustEngagedWith(Unit* /*who*/) override + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_GROUNDTREMOR, TIMER_GROUNDTREMOR / 5); - events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY / 5); - } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) + switch (eventId) { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) + case SPELL_GROUNDTREMOR: + if (me->GetDistance2d(me->GetVictim()) < 10.0f) { - case SPELL_GROUNDTREMOR: - if (me->GetDistance2d(me->GetVictim()) < 10.0f) - { - DoCastVictim(SPELL_GROUNDTREMOR); - nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s); - } - else - { - nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s) / 3; - } - events.ScheduleEvent(SPELL_GROUNDTREMOR, nextTremorTime); - break; - case SPELL_FRENZY: - DoCastSelf(SPELL_FRENZY); - events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY - 2s, TIMER_FRENZY + 2s); - Talk(EMOTE_FRENZY_KILL); - break; - default: - break; + DoCastVictim(SPELL_GROUNDTREMOR); + nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s); } + else + { + nextTremorTime = randtime(TIMER_GROUNDTREMOR - 2s, TIMER_GROUNDTREMOR + 2s) / 3; + } + events.ScheduleEvent(SPELL_GROUNDTREMOR, nextTremorTime); + break; + case SPELL_FRENZY: + DoCastSelf(SPELL_FRENZY); + events.ScheduleEvent(SPELL_FRENZY, TIMER_FRENZY - 2s, TIMER_FRENZY + 2s); + Talk(EMOTE_FRENZY_KILL); + break; + default: + break; } - DoMeleeAttackIfReady(); } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_grizzle() { - new boss_grizzle(); + RegisterBlackrockDepthsCreatureAI(boss_grizzle); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_hedrum.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_hedrum.cpp index 787c72780..c12f84f18 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_hedrum.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_hedrum.cpp @@ -30,70 +30,55 @@ constexpr Milliseconds TIMER_PARALYZING = 20s; constexpr Milliseconds TIMER_BANEFUL = 24s; constexpr Milliseconds TIMER_WEB_EXPLOSION = 20s; -class boss_hedrum : public CreatureScript +struct boss_hedrum : public BossAI { -public: - boss_hedrum() : CreatureScript("boss_hedrum") {} + boss_hedrum(Creature* creature) : BossAI(creature, DATA_HEDRUM) {} - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING / 5); + events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL / 5); + events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION / 5); } - struct boss_hedrumAI : public BossAI + void UpdateAI(uint32 diff) override { - boss_hedrumAI(Creature* creature) : BossAI(creature, DATA_HEDRUM) {} + // Return since we have no target + if (!UpdateVictim()) + return; - void JustEngagedWith(Unit* /*who*/) override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING / 5); - events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL / 5); - events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION / 5); + switch (eventId) + { + case SPELL_PARALYZING: + DoCastVictim(SPELL_PARALYZING); + events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING - 2s, TIMER_PARALYZING + 2s); + break; + case SPELL_BANEFUL: + DoCastVictim(SPELL_BANEFUL); + events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL - 2s, TIMER_BANEFUL + 2s); + break; + case SPELL_WEB_EXPLOSION: + if (me->GetDistance2d(me->GetVictim()) < 100.0f) + DoCast(SPELL_WEB_EXPLOSION); + events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION - 2s, TIMER_WEB_EXPLOSION + 2s); + break; + default: + break; + } } - - void UpdateAI(uint32 diff) override - { - // Return since we have no target - if (!UpdateVictim()) - { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_PARALYZING: - DoCastVictim(SPELL_PARALYZING); - events.ScheduleEvent(SPELL_PARALYZING, TIMER_PARALYZING - 2s, TIMER_PARALYZING + 2s); - break; - case SPELL_BANEFUL: - DoCastVictim(SPELL_BANEFUL); - events.ScheduleEvent(SPELL_BANEFUL, TIMER_BANEFUL - 2s, TIMER_BANEFUL + 2s); - break; - case SPELL_WEB_EXPLOSION: - if (me->GetDistance2d(me->GetVictim()) < 100.0f) - { - DoCast(SPELL_WEB_EXPLOSION); - } - events.ScheduleEvent(SPELL_WEB_EXPLOSION, TIMER_WEB_EXPLOSION - 2s, TIMER_WEB_EXPLOSION + 2s); - break; - default: - break; - } - } - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_hedrum() { - new boss_hedrum(); + RegisterBlackrockDepthsCreatureAI(boss_hedrum); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp index 87202e6f0..dc6ada187 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp @@ -27,81 +27,67 @@ enum Spells SPELL_SHADOWSHIELD = 22417 }; -class boss_high_interrogator_gerstahn : public CreatureScript +struct boss_high_interrogator_gerstahn : public ScriptedAI { -public: - boss_high_interrogator_gerstahn() : CreatureScript("boss_high_interrogator_gerstahn") { } + boss_high_interrogator_gerstahn(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockDepthsAI(creature); + _shadowWordPainTimer = 4000; + _manaBurnTimer = 14000; + _psychicScreamTimer = 32000; + _shadowShieldTimer = 8000; } - struct boss_high_interrogator_gerstahnAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { } + + void UpdateAI(uint32 diff) override { - boss_high_interrogator_gerstahnAI(Creature* creature) : ScriptedAI(creature) { } + //Return since we have no target + if (!UpdateVictim()) + return; - uint32 ShadowWordPain_Timer; - uint32 ManaBurn_Timer; - uint32 PsychicScream_Timer; - uint32 ShadowShield_Timer; - - void Reset() override + if (_shadowWordPainTimer <= diff) { - ShadowWordPain_Timer = 4000; - ManaBurn_Timer = 14000; - PsychicScream_Timer = 32000; - ShadowShield_Timer = 8000; + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_SHADOWWORDPAIN); + _shadowWordPainTimer = 7000; } + else _shadowWordPainTimer -= diff; - void JustEngagedWith(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override + if (_manaBurnTimer <= diff) { - //Return since we have no target - if (!UpdateVictim()) - return; - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = 7000; - } - else ShadowWordPain_Timer -= diff; - - //ManaBurn_Timer - if (ManaBurn_Timer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - DoCast(target, SPELL_MANABURN); - ManaBurn_Timer = 10000; - } - else ManaBurn_Timer -= diff; - - //PsychicScream_Timer - if (PsychicScream_Timer <= diff) - { - DoCastVictim(SPELL_PSYCHICSCREAM); - PsychicScream_Timer = 30000; - } - else PsychicScream_Timer -= diff; - - //ShadowShield_Timer - if (ShadowShield_Timer <= diff) - { - DoCast(me, SPELL_SHADOWSHIELD); - ShadowShield_Timer = 25000; - } - else ShadowShield_Timer -= diff; - - DoMeleeAttackIfReady(); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_MANABURN); + _manaBurnTimer = 10000; } - }; + else _manaBurnTimer -= diff; + + if (_psychicScreamTimer <= diff) + { + DoCastVictim(SPELL_PSYCHICSCREAM); + _psychicScreamTimer = 30000; + } + else _psychicScreamTimer -= diff; + + if (_shadowShieldTimer <= diff) + { + DoCast(me, SPELL_SHADOWSHIELD); + _shadowShieldTimer = 25000; + } + else _shadowShieldTimer -= diff; + + DoMeleeAttackIfReady(); + } + +private: + uint32 _shadowWordPainTimer; + uint32 _manaBurnTimer; + uint32 _psychicScreamTimer; + uint32 _shadowShieldTimer; }; void AddSC_boss_high_interrogator_gerstahn() { - new boss_high_interrogator_gerstahn(); + RegisterBlackrockDepthsCreatureAI(boss_high_interrogator_gerstahn); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp index 8551a20b1..3e326e817 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp @@ -25,66 +25,54 @@ enum Spells SPELL_WARSTOMP = 24375 }; -class boss_magmus : public CreatureScript +struct boss_magmus : public BossAI { -public: - boss_magmus() : CreatureScript("boss_magmus") { } + boss_magmus(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {} - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockDepthsAI(creature); + _Reset(); + instance->SetData(TYPE_IRON_HALL, NOT_STARTED); } - struct boss_magmusAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_magmusAI(Creature* creature) : BossAI(creature, TYPE_IRON_HALL) {} + instance->SetData(TYPE_IRON_HALL, IN_PROGRESS); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s); + events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s); + } - void Reset() override - { - _Reset(); - instance->SetData(TYPE_IRON_HALL, NOT_STARTED); - } + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - void JustEngagedWith(Unit* /*who*/) override - { - instance->SetData(TYPE_IRON_HALL, IN_PROGRESS); - _JustEngagedWith(); - events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s); - events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s); - } + events.Update(diff); - void UpdateAI(uint32 diff) override + while (uint32 eventId = events.ExecuteEvent()) { - //Return since we have no target - if (!UpdateVictim()) + switch (eventId) { - return; + case SPELL_WARSTOMP: + DoCastVictim(SPELL_WARSTOMP); + events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s); + break; + case SPELL_FIERYBURST: + DoCastVictim(SPELL_FIERYBURST); + events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s); + break; + default: + break; } - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_WARSTOMP: - DoCastVictim(SPELL_WARSTOMP); - events.ScheduleEvent(SPELL_WARSTOMP, 8s, 12s); - break; - case SPELL_FIERYBURST: - DoCastVictim(SPELL_FIERYBURST); - events.ScheduleEvent(SPELL_FIERYBURST, 4s, 8s); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); } - }; + + DoMeleeAttackIfReady(); + } }; void AddSC_boss_magmus() { - new boss_magmus(); + RegisterBlackrockDepthsCreatureAI(boss_magmus); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp index ddcbfaa9e..15804801a 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp @@ -34,10 +34,10 @@ constexpr Milliseconds TIMER_RENEW = 12s; constexpr Milliseconds TIMER_SHADOWBOLT = 16s; constexpr Milliseconds TIMER_WORDPAIN = 12s; -struct boss_moira_bronzebeardAI : public BossAI +struct boss_moira_bronzebeard : public BossAI { // use a default value so we can inherit for priestess - boss_moira_bronzebeardAI(Creature* creature, uint32 data = DATA_MOIRA) : BossAI(creature, data) {} + boss_moira_bronzebeard(Creature* creature, uint32 data = DATA_MOIRA) : BossAI(creature, data) {} void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); @@ -49,15 +49,13 @@ struct boss_moira_bronzebeardAI : public BossAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } + events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) @@ -83,22 +81,18 @@ struct boss_moira_bronzebeardAI : public BossAI { Creature* emperor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EMPEROR)); if (emperor && emperor->HealthBelowPct(90)) - { DoCast(emperor, spell); - } else if (HealthBelowPct(90)) - { DoCastSelf(spell); - } events.ScheduleEvent(spell, timer - 2s, timer + 2s); } }; // high priestess should be fairly identical to Moira. // Running away when emperor dies is handled through GUID from emperor, therefore not relevant here. -struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI +struct boss_high_priestess_thaurissan : public boss_moira_bronzebeard { - boss_high_priestess_thaurissanAI(Creature* creature) : boss_moira_bronzebeardAI(creature, DATA_PRIESTESS) {} + boss_high_priestess_thaurissan(Creature* creature) : boss_moira_bronzebeard(creature, DATA_PRIESTESS) {} void JustEngagedWith(Unit* /*who*/) override { @@ -110,18 +104,16 @@ struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI events.ScheduleEvent(SPELL_SHADOWBOLT, TIMER_SHADOWBOLT / 2); } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } + events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) @@ -148,34 +140,12 @@ struct boss_high_priestess_thaurissanAI : public boss_moira_bronzebeardAI } }; -class boss_moira_bronzebeard : public CreatureScript -{ -public: - boss_moira_bronzebeard() : CreatureScript("boss_moira_bronzebeard") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockDepthsAI(creature); - } -}; - -class boss_high_priestess_thaurissan : public CreatureScript -{ -public: - boss_high_priestess_thaurissan() : CreatureScript("boss_high_priestess_thaurissan") {} - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockDepthsAI(creature); - } -}; - void AddSC_boss_moira_bronzebeard() { - new boss_moira_bronzebeard(); + RegisterBlackrockDepthsCreatureAI(boss_moira_bronzebeard); } void AddSC_boss_high_priestess_thaurissan() { - new boss_high_priestess_thaurissan(); + RegisterBlackrockDepthsCreatureAI(boss_high_priestess_thaurissan); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_okthor.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_okthor.cpp index 0fd86d6be..688858ac0 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_okthor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_okthor.cpp @@ -32,92 +32,74 @@ constexpr Milliseconds TIMER_ARCANE_EXPLOSION = 24s; constexpr Milliseconds TIMER_POLYMORPH = 12s; constexpr Milliseconds TIMER_SLOW = 15s; -class boss_okthor : public CreatureScript +struct boss_okthor : public BossAI { -public: - boss_okthor() : CreatureScript("boss_okthor") {} + boss_okthor(Creature* creature) : BossAI(creature, DATA_OKTHOR) {} - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockDepthsAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT / 5); + events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, TIMER_ARCANE_EXPLOSION / 5); + events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH / 5); + events.ScheduleEvent(SPELL_SLOW, 500ms); } - struct boss_okthorAI : public BossAI + void UpdateAI(uint32 diff) override { - boss_okthorAI(Creature* creature) : BossAI(creature, DATA_OKTHOR) {} + //Return since we have no target + if (!UpdateVictim()) + return; - Milliseconds nextArcaneExplosionTime; + events.Update(diff); - void JustEngagedWith(Unit* /*who*/) override + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT / 5); - events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, TIMER_ARCANE_EXPLOSION / 5); - events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH / 5); - events.ScheduleEvent(SPELL_SLOW, 500ms); - } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) + switch (eventId) { - return; - } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) + case SPELL_ARCANE_BOLT: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_ARCANE_BOLT); + events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT - 2s, TIMER_ARCANE_BOLT + 2s); + break; + case SPELL_ARCANE_EXPLOSION: + if (me->GetDistance2d(me->GetVictim()) < 50.0f) { - case SPELL_ARCANE_BOLT: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - DoCast(target, SPELL_ARCANE_BOLT); - } - events.ScheduleEvent(SPELL_ARCANE_BOLT, TIMER_ARCANE_BOLT - 2s, TIMER_ARCANE_BOLT + 2s); - break; - case SPELL_ARCANE_EXPLOSION: - if (me->GetDistance2d(me->GetVictim()) < 50.0f) - { - DoCast(SPELL_ARCANE_EXPLOSION); - nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s); - } - else - { - nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s) / 3; - } - events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, nextArcaneExplosionTime); - break; - case SPELL_POLYMORPH: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - DoCast(target, SPELL_POLYMORPH); - } - events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH - 2s, TIMER_POLYMORPH + 2s); - break; - case SPELL_SLOW: - if (me->GetDistance2d(me->GetVictim()) < 50.0f) - { - DoCast(SPELL_SLOW); - } - events.ScheduleEvent(SPELL_SLOW, TIMER_SLOW); - break; - - default: - break; + DoCast(SPELL_ARCANE_EXPLOSION); + _nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s); } + else + { + _nextArcaneExplosionTime = randtime(TIMER_ARCANE_EXPLOSION - 2s, TIMER_ARCANE_EXPLOSION + 2s) / 3; + } + events.ScheduleEvent(SPELL_ARCANE_EXPLOSION, _nextArcaneExplosionTime); + break; + case SPELL_POLYMORPH: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + DoCast(target, SPELL_POLYMORPH); + events.ScheduleEvent(SPELL_POLYMORPH, TIMER_POLYMORPH - 2s, TIMER_POLYMORPH + 2s); + break; + case SPELL_SLOW: + if (me->GetDistance2d(me->GetVictim()) < 50.0f) + DoCast(SPELL_SLOW); + events.ScheduleEvent(SPELL_SLOW, TIMER_SLOW); + break; + + default: + break; } - DoMeleeAttackIfReady(); } - }; + DoMeleeAttackIfReady(); + } + +private: + Milliseconds _nextArcaneExplosionTime; }; void AddSC_boss_okthor() { - new boss_okthor(); + RegisterBlackrockDepthsCreatureAI(boss_okthor); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp index 3feabc95f..da9242590 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp @@ -53,19 +53,18 @@ enum Gossip SAY_QUEST_COMPLETED_END = 2606, // You have shown me your desire, and have payed with precious stone. I will teach you... }; -class boss_gloomrel : public CreatureScript +struct boss_gloomrel : public ScriptedAI { -public: - boss_gloomrel() : CreatureScript("boss_gloomrel") { } + boss_gloomrel(Creature* creature) : ScriptedAI(creature) { } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); switch (action) { case GOSSIP_ACTION_INFO_DEF+1: AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - SendGossipMenuFor(player, SAY_QUEST_COMPLETED_END, creature->GetGUID()); + SendGossipMenuFor(player, SAY_QUEST_COMPLETED_END, me->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+11: CloseGossipMenuFor(player); @@ -73,33 +72,29 @@ public: break; case GOSSIP_ACTION_INFO_DEF+2: AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - SendGossipMenuFor(player, SAY_QUEST_ACCEPTED, creature->GetGUID()); + SendGossipMenuFor(player, SAY_QUEST_ACCEPTED, me->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+22: CloseGossipMenuFor(player); - if (InstanceScript* instance = creature->GetInstanceScript()) - { + if (InstanceScript* instance = me->GetInstanceScript()) //are 5 minutes expected? go template may have data to despawn when used at quest instance->DoRespawnGameObject(instance->GetGuidData(DATA_GO_CHALICE), MINUTE * 5); - } break; } - return true; } - bool OnGossipHello(Player* player, Creature* creature) override + void sGossipHello(Player* player) override { if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 1 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN && !player->HasSpell(SPELL_SMELT_DARK_IRON)) { AddGossipItemFor(player, GOSSIP_GROOMREL, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - SendGossipMenuFor(player, SAY_QUEST_COMPLETED, creature->GetGUID()); + SendGossipMenuFor(player, SAY_QUEST_COMPLETED, me->GetGUID()); } if (player->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) == 0 && player->GetSkillValue(SKILL_MINING) >= DATA_SKILLPOINT_MIN) AddGossipItemFor(player, GOSSIP_GROOMREL, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); - return true; + SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); } }; @@ -120,145 +115,124 @@ enum DoomrelEvents EVENT_SPELL_SUMMON_VOIDWALKERS = 5, }; -class boss_doomrel : public CreatureScript +struct boss_doomrel : public ScriptedAI { -public: - boss_doomrel() : CreatureScript("boss_doomrel") { } + boss_doomrel(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override + InstanceScript* instance; + EventMap _events; + bool Voidwalkers; + + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); switch (action) { case GOSSIP_ACTION_INFO_DEF+1: AddGossipItemFor(player, GOSSIP_TEXT_CONTINUE, 1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - SendGossipMenuFor(player, SAY_QUEST_COMPLETED, creature->GetGUID()); + SendGossipMenuFor(player, SAY_QUEST_COMPLETED, me->GetGUID()); break; case GOSSIP_ACTION_INFO_DEF+2: CloseGossipMenuFor(player); - creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); // Start encounter - InstanceScript* instance = creature->GetInstanceScript(); if (instance) - { instance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS); - } - creature->AI()->Talk(SAY_START_FIGHT); + Talk(SAY_START_FIGHT); break; } - return true; } - bool OnGossipHello(Player* player, Creature* creature) override + void sGossipHello(Player* player) override { AddGossipItemFor(player, GOSSIP_DOOMREL_START_COMBAT, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - SendGossipMenuFor(player, SAY_DOOMREL_HELLO, creature->GetGUID()); - - return true; + SendGossipMenuFor(player, SAY_DOOMREL_HELLO, me->GetGUID()); } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockDepthsAI(creature); + Voidwalkers = false; + me->SetFaction(FACTION_FRIENDLY); + + // was set before event start, so set again + me->SetImmuneToPC(true); + + if (instance->GetData(TYPE_TOMB_OF_SEVEN) == DONE) // what is this trying to do? Probably some kind of crash recovery + me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); + else + me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP); } - struct boss_doomrelAI : public ScriptedAI + void JustEngagedWith(Unit* /*who*/) override { - boss_doomrelAI(Creature* creature) : ScriptedAI(creature) + _events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 10s); + _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 18s); + _events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 5s); + _events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 16s); + _events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + me->RemoveAllAuras(); + me->GetThreatMgr().ClearAllThreat(); + me->CombatStop(true); + me->LoadCreaturesAddon(true); + if (me->IsAlive()) + me->GetMotionMaster()->MoveTargetedHome(); + me->SetLootRecipient(nullptr); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + switch (_events.ExecuteEvent()) { - instance = creature->GetInstanceScript(); + case EVENT_SPELL_SHADOWBOLTVOLLEY: + DoCastVictim(SPELL_SHADOWBOLTVOLLEY); + _events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 12s); + break; + case EVENT_SPELL_IMMOLATE: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + { + DoCast(target, SPELL_IMMOLATE); + _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 25s); + } + // Didn't get a target, try again in 1s + _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 1s); + break; + case EVENT_SPELL_CURSEOFWEAKNESS: + DoCastVictim(SPELL_CURSEOFWEAKNESS); + _events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 45s); + break; + case EVENT_SPELL_DEMONARMOR: + DoCast(me, SPELL_DEMONARMOR); + _events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 300s); + break; + case EVENT_SPELL_SUMMON_VOIDWALKERS: + if (!Voidwalkers && HealthBelowPct(51)) + { + DoCastVictim(SPELL_SUMMON_VOIDWALKERS, true); + Voidwalkers = true; + } + // Not ready yet, try again in 1s + _events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s); + break; } - InstanceScript* instance; - EventMap _events; - bool Voidwalkers; - - void Reset() override - { - Voidwalkers = false; - me->SetFaction(FACTION_FRIENDLY); - - // was set before event start, so set again - me->SetImmuneToPC(true); - - if (instance->GetData(TYPE_TOMB_OF_SEVEN) == DONE) // what is this trying to do? Probably some kind of crash recovery - { - me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); - } - else - { - me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - _events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 10s); - _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 18s); - _events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 5s); - _events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 16s); - _events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - me->RemoveAllAuras(); - me->GetThreatMgr().ClearAllThreat(); - me->CombatStop(true); - me->LoadCreaturesAddon(true); - if (me->IsAlive()) - me->GetMotionMaster()->MoveTargetedHome(); - me->SetLootRecipient(nullptr); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _events.Update(diff); - - switch (_events.ExecuteEvent()) - { - case EVENT_SPELL_SHADOWBOLTVOLLEY: - DoCastVictim(SPELL_SHADOWBOLTVOLLEY); - _events.ScheduleEvent(EVENT_SPELL_SHADOWBOLTVOLLEY, 12s); - break; - case EVENT_SPELL_IMMOLATE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - DoCast(target, SPELL_IMMOLATE); - _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 25s); - } - // Didn't get a target, try again in 1s - _events.ScheduleEvent(EVENT_SPELL_IMMOLATE, 1s); - break; - case EVENT_SPELL_CURSEOFWEAKNESS: - DoCastVictim(SPELL_CURSEOFWEAKNESS); - _events.ScheduleEvent(EVENT_SPELL_CURSEOFWEAKNESS, 45s); - break; - case EVENT_SPELL_DEMONARMOR: - DoCast(me, SPELL_DEMONARMOR); - _events.ScheduleEvent(EVENT_SPELL_DEMONARMOR, 300s); - break; - case EVENT_SPELL_SUMMON_VOIDWALKERS: - if (!Voidwalkers && HealthBelowPct(51)) - { - DoCastVictim(SPELL_SUMMON_VOIDWALKERS, true); - Voidwalkers = true; - } - // Not ready yet, try again in 1s - _events.ScheduleEvent(EVENT_SPELL_SUMMON_VOIDWALKERS, 1s); - break; - } - - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_tomb_of_seven() { - new boss_gloomrel(); - new boss_doomrel(); + RegisterBlackrockDepthsCreatureAI(boss_gloomrel); + RegisterBlackrockDepthsCreatureAI(boss_doomrel); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp index f6c487ba9..678885ce2 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp @@ -95,762 +95,715 @@ private: Creature* _boss; }; -class instance_blackrock_depths : public InstanceMapScript +struct instance_blackrock_depths : public InstanceScript { -public: - instance_blackrock_depths() : InstanceMapScript("instance_blackrock_depths", MAP_BLACKROCK_DEPTHS) { } - - InstanceScript* GetInstanceScript(InstanceMap* map) const override + instance_blackrock_depths(Map* map) : InstanceScript(map) { - return new instance_blackrock_depths_InstanceMapScript(map); + SetHeaders(DataHeader); } - struct instance_blackrock_depths_InstanceMapScript : public InstanceScript + uint32 encounter[MAX_ENCOUNTER]; + std::string str_data; + + ObjectGuid EmperorGUID; + ObjectGuid PhalanxGUID; + ObjectGuid MagmusGUID; + ObjectGuid MoiraGUID; + ObjectGuid PriestessGUID; + ObjectGuid IronhandGUID[6]; + ObjectGuid CorenGUID; + + ObjectGuid GoArena1GUID; + ObjectGuid GoArena2GUID; + ObjectGuid GoArena3GUID; + ObjectGuid GoArena4GUID; + ObjectGuid GoShadowLockGUID; + ObjectGuid GoShadowMechGUID; + ObjectGuid GoShadowGiantGUID; + ObjectGuid GoShadowDummyGUID; + ObjectGuid GoBarKegGUID; + ObjectGuid GoBarKegTrapGUID; + ObjectGuid GoBarDoorGUID; + ObjectGuid GoTombEnterGUID; + ObjectGuid GoTombExitGUID; + ObjectGuid GoLyceumGUID; + ObjectGuid GoSFSGUID; + ObjectGuid GoSFNGUID; + ObjectGuid GoGolemNGUID; + ObjectGuid GoGolemSGUID; + ObjectGuid GoThroneGUID; + ObjectGuid GoChestGUID; + ObjectGuid GoSpectralChaliceGUID; + + uint32 BarAleCount; + uint32 GhostKillCount; + ObjectGuid TombBossGUIDs[7]; + uint32 tombResetTimer; + uint32 TombTimer; + uint32 TombEventCounter; + uint32 OpenedCoofers; + uint32 IronhandCounter; + + GuidList ArgelmachAdds; + ObjectGuid ArgelmachGUID; + + TempSummon* TempSummonGrimstone = nullptr; + Position GrimstonePositon = Position(625.559f, -205.618f, -52.735f, 2.609f); + time_t timeRingFail = 0; + uint8 arenaMobsToSpawn; + uint8 arenaBossToSpawn; + + std::vector ArenaSpectators; + Position CenterOfRingOfLaw = Position(595.289, -186.56); + + ObjectGuid EmperorSenators[5]; + std::vector EmperorSenatorsVector; + Position EmperorSpawnPos = Position(1380.52, -831, 115); + + void OnPlayerEnter(Player* /* player */) override { - instance_blackrock_depths_InstanceMapScript(Map* map) : InstanceScript(map) + ReplaceMoiraIfSaved(); // In case a player joins the party during the run + // SetData(TYPE_RING_OF_LAW, DONE); + } + + void ReplaceMoiraIfSaved() + { + ObjectGuid* GUIDToReplace = &PriestessGUID; // default to having Moira + ObjectGuid* GUIDToSpawn = &MoiraGUID; + uint32 NPCEntry = NPC_MOIRA; + bool MoiraSaved = true; + + // check if all players saved her. + Map::PlayerList const& lPlayers = instance->GetPlayers(); + if (!lPlayers.IsEmpty()) { - SetHeaders(DataHeader); - } - - uint32 encounter[MAX_ENCOUNTER]; - std::string str_data; - - ObjectGuid EmperorGUID; - ObjectGuid PhalanxGUID; - ObjectGuid MagmusGUID; - ObjectGuid MoiraGUID; - ObjectGuid PriestessGUID; - ObjectGuid IronhandGUID[6]; - ObjectGuid CorenGUID; - - ObjectGuid GoArena1GUID; - ObjectGuid GoArena2GUID; - ObjectGuid GoArena3GUID; - ObjectGuid GoArena4GUID; - ObjectGuid GoShadowLockGUID; - ObjectGuid GoShadowMechGUID; - ObjectGuid GoShadowGiantGUID; - ObjectGuid GoShadowDummyGUID; - ObjectGuid GoBarKegGUID; - ObjectGuid GoBarKegTrapGUID; - ObjectGuid GoBarDoorGUID; - ObjectGuid GoTombEnterGUID; - ObjectGuid GoTombExitGUID; - ObjectGuid GoLyceumGUID; - ObjectGuid GoSFSGUID; - ObjectGuid GoSFNGUID; - ObjectGuid GoGolemNGUID; - ObjectGuid GoGolemSGUID; - ObjectGuid GoThroneGUID; - ObjectGuid GoChestGUID; - ObjectGuid GoSpectralChaliceGUID; - - uint32 BarAleCount; - uint32 GhostKillCount; - ObjectGuid TombBossGUIDs[7]; - uint32 tombResetTimer; - uint32 TombTimer; - uint32 TombEventCounter; - uint32 OpenedCoofers; - uint32 IronhandCounter; - - GuidList ArgelmachAdds; - ObjectGuid ArgelmachGUID; - - TempSummon* TempSummonGrimstone = nullptr; - Position GrimstonePositon = Position(625.559f, -205.618f, -52.735f, 2.609f); - time_t timeRingFail = 0; - uint8 arenaMobsToSpawn; - uint8 arenaBossToSpawn; - - std::vector ArenaSpectators; - Position CenterOfRingOfLaw = Position(595.289, -186.56); - - ObjectGuid EmperorSenators[5]; - std::vector EmperorSenatorsVector; - Position EmperorSpawnPos = Position(1380.52, -831, 115); - - void OnPlayerEnter(Player* /* player */) override - { - ReplaceMoiraIfSaved(); // In case a player joins the party during the run - // SetData(TYPE_RING_OF_LAW, DONE); - } - - void ReplaceMoiraIfSaved() - { - ObjectGuid* GUIDToReplace = &PriestessGUID; // default to having Moira - ObjectGuid* GUIDToSpawn = &MoiraGUID; - uint32 NPCEntry = NPC_MOIRA; - bool MoiraSaved = true; - - // check if all players saved her. - Map::PlayerList const& lPlayers = instance->GetPlayers(); - if (!lPlayers.IsEmpty()) + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { - for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + if (Player* player = itr->GetSource()) { - if (Player* player = itr->GetSource()) - { - // set to false if this player hasn't saved her. Another player can't put it to true. - MoiraSaved = MoiraSaved && ((player->GetQuestStatus(PRINCESS_QUEST_HORDE) == QUEST_STATUS_REWARDED) - || (player->GetQuestStatus(PRINCESS_QUEST_ALLIANCE) == QUEST_STATUS_REWARDED)); - } + // set to false if this player hasn't saved her. Another player can't put it to true. + MoiraSaved = MoiraSaved && ((player->GetQuestStatus(PRINCESS_QUEST_HORDE) == QUEST_STATUS_REWARDED) + || (player->GetQuestStatus(PRINCESS_QUEST_ALLIANCE) == QUEST_STATUS_REWARDED)); } } - - // assign correct GUIDs and spawn targets - if (MoiraSaved) - { - GUIDToReplace = &MoiraGUID; - GUIDToSpawn = &PriestessGUID; - NPCEntry = NPC_PRIESTESS; - } - - if (Creature* CreatureToReplace = instance->GetCreature(*GUIDToReplace)) - { - Creature* NewSpawn = instance->SummonCreature(NPCEntry, CreatureToReplace->GetPosition()); - CreatureToReplace->RemoveFromWorld(); - *GUIDToSpawn = NewSpawn->GetGUID(); - } } - void Initialize() override + // assign correct GUIDs and spawn targets + if (MoiraSaved) { - memset(&encounter, 0, sizeof(encounter)); - - BarAleCount = 0; - GhostKillCount = 0; - TombTimer = TIMER_TOMB_START; - TombEventCounter = 0; - tombResetTimer = 0; - OpenedCoofers = 0; - IronhandCounter = 0; - ArenaSpectators.clear(); - - // these are linked to the dungeon and not how many times the arena started. - arenaMobsToSpawn = urand(0, 5); - arenaBossToSpawn = urand(0, 5); + GUIDToReplace = &MoiraGUID; + GUIDToSpawn = &PriestessGUID; + NPCEntry = NPC_PRIESTESS; } - void OnCreatureCreate(Creature* creature) override + if (Creature* CreatureToReplace = instance->GetCreature(*GUIDToReplace)) { - switch (creature->GetEntry()) - { - case NPC_EMPEROR: - EmperorGUID = creature->GetGUID(); - break; - case NPC_PHALANX: - PhalanxGUID = creature->GetGUID(); - break; - case NPC_MOIRA: - MoiraGUID = creature->GetGUID(); - break; - case NPC_COREN_DIREBREW: - CorenGUID = creature->GetGUID(); - break; - case NPC_ANGERREL: - TombBossGUIDs[0] = creature->GetGUID(); - break; - case NPC_SEETHREL: - TombBossGUIDs[1] = creature->GetGUID(); - break; - case NPC_DOPEREL: - TombBossGUIDs[2] = creature->GetGUID(); - break; - case NPC_GLOOMREL: - TombBossGUIDs[3] = creature->GetGUID(); - break; - case NPC_VILEREL: - TombBossGUIDs[4] = creature->GetGUID(); - break; - case NPC_HATEREL: - TombBossGUIDs[5] = creature->GetGUID(); - break; - case NPC_DOOMREL: - TombBossGUIDs[6] = creature->GetGUID(); - break; - case NPC_MAGMUS: - MagmusGUID = creature->GetGUID(); - if (!creature->IsAlive()) - HandleGameObject(GoThroneGUID, true); // if Magmus is dead open door to last boss - break; - case NPC_WEAPON_TECHNICIAN: - case NPC_DOOMFORGE_ARCANASMITH: - case NPC_RAGEREAVER_GOLEM: - case NPC_WRATH_HAMMER_CONSTRUCT: - if (creature->IsAlive() && creature->GetPositionZ() < -51.5f && creature->GetPositionZ() > -55.f) - { - ArgelmachAdds.push_back(creature->GetGUID()); - } - break; - case NPC_GOLEM_LORD_ARGELMACH: - ArgelmachGUID = creature->GetGUID(); - break; - case NPC_IRONHAND_GUARDIAN: - IronhandGUID[IronhandCounter] = creature->GetGUID(); - IronhandCounter++; - break; - case NPC_ARENA_SPECTATOR: - ArenaSpectators.push_back(creature->GetGUID()); - if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes - { - creature->SetFaction(FACTION_NEUTRAL); - creature->SetReactState(REACT_DEFENSIVE); - } - break; - case NPC_SHADOWFORGE_PEASANT: - case NPC_SHADOWFORCE_CITIZEN: // both do the same - if (creature->GetDistance2d(CenterOfRingOfLaw.GetPositionX(), CenterOfRingOfLaw.GetPositionY()) < (float)RADIUS_RING_OF_LAW) - { - ArenaSpectators.push_back(creature->GetGUID()); - } - if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes - { - creature->SetFaction(FACTION_NEUTRAL); - creature->SetReactState(REACT_DEFENSIVE); - } - break; - case NPC_SHADOWFORGE_SENATOR: - // keep track of Senators that are not too far from emperor. Can't really use emperor as creature due to him possibly not being spawned. - // some senators spawn at ring of law - if (creature->GetDistance2d(EmperorSpawnPos.GetPositionX(), EmperorSpawnPos.GetPositionY()) < (float)DISTANCE_EMPEROR_ROOM) - { - EmperorSenatorsVector.push_back(creature->GetGUID()); - } - break; - default: - break; - } + Creature* NewSpawn = instance->SummonCreature(NPCEntry, CreatureToReplace->GetPosition()); + CreatureToReplace->RemoveFromWorld(); + *GUIDToSpawn = NewSpawn->GetGUID(); } + } - void OnGameObjectCreate(GameObject* go) override + void Initialize() override + { + memset(&encounter, 0, sizeof(encounter)); + + BarAleCount = 0; + GhostKillCount = 0; + TombTimer = TIMER_TOMB_START; + TombEventCounter = 0; + tombResetTimer = 0; + OpenedCoofers = 0; + IronhandCounter = 0; + ArenaSpectators.clear(); + + // these are linked to the dungeon and not how many times the arena started. + arenaMobsToSpawn = urand(0, 5); + arenaBossToSpawn = urand(0, 5); + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) { - switch (go->GetEntry()) - { - case GO_ARENA1: - GoArena1GUID = go->GetGUID(); - break; - case GO_ARENA2: - GoArena2GUID = go->GetGUID(); - break; - case GO_ARENA3: - GoArena3GUID = go->GetGUID(); - break; - case GO_ARENA4: - GoArena4GUID = go->GetGUID(); - break; - case GO_SHADOW_LOCK: - GoShadowLockGUID = go->GetGUID(); - break; - case GO_SHADOW_MECHANISM: - GoShadowMechGUID = go->GetGUID(); - break; - case GO_SHADOW_GIANT_DOOR: - GoShadowGiantGUID = go->GetGUID(); - break; - case GO_SHADOW_DUMMY: - GoShadowDummyGUID = go->GetGUID(); - break; - case GO_BAR_KEG_SHOT: - GoBarKegGUID = go->GetGUID(); - break; - case GO_BAR_KEG_TRAP: - GoBarKegTrapGUID = go->GetGUID(); - break; - case GO_BAR_DOOR: - GoBarDoorGUID = go->GetGUID(); - break; - case GO_TOMB_ENTER: - GoTombEnterGUID = go->GetGUID(); - break; - case GO_TOMB_EXIT: - GoTombExitGUID = go->GetGUID(); - if (GhostKillCount >= 7) - HandleGameObject(ObjectGuid::Empty, true, go); - else - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_LYCEUM: - GoLyceumGUID = go->GetGUID(); - break; - case GO_SF_S: - GoSFSGUID = go->GetGUID(); - break; - case GO_SF_N: - GoSFNGUID = go->GetGUID(); - break; - case GO_GOLEM_ROOM_N: - GoGolemNGUID = go->GetGUID(); - break; - case GO_GOLEM_ROOM_S: - GoGolemSGUID = go->GetGUID(); - break; - case GO_THRONE_ROOM: - GoThroneGUID = go->GetGUID(); - break; - case GO_CHEST_SEVEN: - GoChestGUID = go->GetGUID(); - break; - case GO_SPECTRAL_CHALICE: - GoSpectralChaliceGUID = go->GetGUID(); - break; - } - } - - void OnUnitDeath(Unit* unit) override - { - uint32 deadSenators = 0; - switch (unit->GetEntry()) - { - case NPC_WEAPON_TECHNICIAN: - case NPC_DOOMFORGE_ARCANASMITH: - case NPC_RAGEREAVER_GOLEM: - case NPC_WRATH_HAMMER_CONSTRUCT: - ArgelmachAdds.remove(unit->GetGUID()); - break; - case NPC_MAGMUS: - SetData(TYPE_IRON_HALL, DONE); - break; - case NPC_SHADOWFORGE_SENATOR: - deadSenators = 1; //hacky, but we cannot count the unit that just died through its state because OnUnitDeath() is called before the state is set. - for (const auto &senatorGUID: EmperorSenatorsVector) - { - if (Creature* senator = instance->GetCreature(senatorGUID)) - { - if (!senator->IsAlive() || senator->isDying()) - { - deadSenators++; - } - } - } - - if (Creature* emperor = instance->GetCreature(EmperorGUID)) - { - // send % of senators that died - emperor->AI()->SetData(0, (100 * deadSenators) / EmperorSenatorsVector.size()); - } - break; - case NPC_ANGERREL: - case NPC_DOPEREL: - case NPC_HATEREL: - case NPC_VILEREL: - case NPC_SEETHREL: - case NPC_GLOOMREL: - case NPC_DOOMREL: - GhostKillCount++; - if (GhostKillCount >= 7) - { - SetData(TYPE_TOMB_OF_SEVEN, DONE); - } - break; - default: - break; - } - } - - void SetData(uint32 type, uint32 data) override - { - LOG_DEBUG("scripts.ai", "Instance Blackrock Depths: SetData update (Type: {} Data {})", type, data); - - switch (type) - { - case TYPE_RING_OF_LAW: - encounter[0] = data; - switch (data) - { - case IN_PROGRESS: - TempSummonGrimstone = instance->SummonCreature(NPC_GRIMSTONE, GrimstonePositon); - break; - case FAIL: - if (TempSummonGrimstone) - { - TempSummonGrimstone->RemoveFromWorld(); - TempSummonGrimstone = nullptr; - timeRingFail = GameTime::GetGameTime().count(); - } - SetData(TYPE_RING_OF_LAW, NOT_STARTED); - break; - case DONE: - for (auto const& itr : ArenaSpectators) - { - if (Creature* spectator = instance->GetCreature(itr)) - { - spectator->SetFaction(FACTION_NEUTRAL); - spectator->SetReactState(REACT_DEFENSIVE); - } - } - break; - default: - break; - } - break; - case TYPE_VAULT: - encounter[1] = data; - break; - case TYPE_BAR: - if (data == SPECIAL) - ++BarAleCount; - else - encounter[2] = data; - break; - case TYPE_TOMB_OF_SEVEN: - encounter[3] = data; - switch (data) - { - case IN_PROGRESS: - HandleGameObject(GoTombExitGUID, false); - HandleGameObject(GoTombEnterGUID, false); - break; - case DONE: - DoRespawnGameObject(GoChestGUID, DAY); - HandleGameObject(GoTombExitGUID, true); - HandleGameObject(GoTombEnterGUID, true); - break; - } - break; - case TYPE_LYCEUM: - encounter[4] = data; - if (data == DONE) - { - HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_N), true); - HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_S), true); - if (Creature* magmus = instance->GetCreature(MagmusGUID)) - { - magmus->AI()->Talk(0); - } - ReplaceMoiraIfSaved(); // Need to place the correct final boss, but we need her to be spawned first. - } - break; - case TYPE_IRON_HALL: - encounter[5] = data; - switch (data) - { - case NOT_STARTED: - case IN_PROGRESS: - for (int i = 0; i < 6; i++) - { - if (Creature* ironhand = instance->GetCreature(IronhandGUID[i])) - { - ironhand->AI()->SetData(0, data == IN_PROGRESS); - } - } - break; - case DONE: - HandleGameObject(GetGuidData(DATA_THRONE_DOOR), true); - break; - default: - break; - } - break; - case DATA_OPEN_COFFER_DOORS: - OpenedCoofers += 1; - if (OpenedCoofers == 12) - { - Position pos = {812.15f, -348.91f, -50.579f, 0.7f}; - if (TempSummon* summon = instance->SummonCreature(NPC_WATCHMAN_DOOMGRIP, pos)) - summon->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); - } - break; - case DATA_GOLEM_LORD_ARGELMACH_INIT: + case NPC_EMPEROR: + EmperorGUID = creature->GetGUID(); + break; + case NPC_PHALANX: + PhalanxGUID = creature->GetGUID(); + break; + case NPC_MOIRA: + MoiraGUID = creature->GetGUID(); + break; + case NPC_COREN_DIREBREW: + CorenGUID = creature->GetGUID(); + break; + case NPC_ANGERREL: + TombBossGUIDs[0] = creature->GetGUID(); + break; + case NPC_SEETHREL: + TombBossGUIDs[1] = creature->GetGUID(); + break; + case NPC_DOPEREL: + TombBossGUIDs[2] = creature->GetGUID(); + break; + case NPC_GLOOMREL: + TombBossGUIDs[3] = creature->GetGUID(); + break; + case NPC_VILEREL: + TombBossGUIDs[4] = creature->GetGUID(); + break; + case NPC_HATEREL: + TombBossGUIDs[5] = creature->GetGUID(); + break; + case NPC_DOOMREL: + TombBossGUIDs[6] = creature->GetGUID(); + break; + case NPC_MAGMUS: + MagmusGUID = creature->GetGUID(); + if (!creature->IsAlive()) + HandleGameObject(GoThroneGUID, true); // if Magmus is dead open door to last boss + break; + case NPC_WEAPON_TECHNICIAN: + case NPC_DOOMFORGE_ARCANASMITH: + case NPC_RAGEREAVER_GOLEM: + case NPC_WRATH_HAMMER_CONSTRUCT: + if (creature->IsAlive() && creature->GetPositionZ() < -51.5f && creature->GetPositionZ() > -55.f) + ArgelmachAdds.push_back(creature->GetGUID()); + break; + case NPC_GOLEM_LORD_ARGELMACH: + ArgelmachGUID = creature->GetGUID(); + break; + case NPC_IRONHAND_GUARDIAN: + IronhandGUID[IronhandCounter] = creature->GetGUID(); + IronhandCounter++; + break; + case NPC_ARENA_SPECTATOR: + ArenaSpectators.push_back(creature->GetGUID()); + if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes { - if (Creature* argelmach = instance->GetCreature(ArgelmachGUID)) + creature->SetFaction(FACTION_NEUTRAL); + creature->SetReactState(REACT_DEFENSIVE); + } + break; + case NPC_SHADOWFORGE_PEASANT: + case NPC_SHADOWFORCE_CITIZEN: // both do the same + if (creature->GetDistance2d(CenterOfRingOfLaw.GetPositionX(), CenterOfRingOfLaw.GetPositionY()) < (float)RADIUS_RING_OF_LAW) + ArenaSpectators.push_back(creature->GetGUID()); + if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes + { + creature->SetFaction(FACTION_NEUTRAL); + creature->SetReactState(REACT_DEFENSIVE); + } + break; + case NPC_SHADOWFORGE_SENATOR: + // keep track of Senators that are not too far from emperor. Can't really use emperor as creature due to him possibly not being spawned. + // some senators spawn at ring of law + if (creature->GetDistance2d(EmperorSpawnPos.GetPositionX(), EmperorSpawnPos.GetPositionY()) < (float)DISTANCE_EMPEROR_ROOM) + EmperorSenatorsVector.push_back(creature->GetGUID()); + break; + default: + break; + } + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_ARENA1: + GoArena1GUID = go->GetGUID(); + break; + case GO_ARENA2: + GoArena2GUID = go->GetGUID(); + break; + case GO_ARENA3: + GoArena3GUID = go->GetGUID(); + break; + case GO_ARENA4: + GoArena4GUID = go->GetGUID(); + break; + case GO_SHADOW_LOCK: + GoShadowLockGUID = go->GetGUID(); + break; + case GO_SHADOW_MECHANISM: + GoShadowMechGUID = go->GetGUID(); + break; + case GO_SHADOW_GIANT_DOOR: + GoShadowGiantGUID = go->GetGUID(); + break; + case GO_SHADOW_DUMMY: + GoShadowDummyGUID = go->GetGUID(); + break; + case GO_BAR_KEG_SHOT: + GoBarKegGUID = go->GetGUID(); + break; + case GO_BAR_KEG_TRAP: + GoBarKegTrapGUID = go->GetGUID(); + break; + case GO_BAR_DOOR: + GoBarDoorGUID = go->GetGUID(); + break; + case GO_TOMB_ENTER: + GoTombEnterGUID = go->GetGUID(); + break; + case GO_TOMB_EXIT: + GoTombExitGUID = go->GetGUID(); + if (GhostKillCount >= 7) + HandleGameObject(ObjectGuid::Empty, true, go); + else + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_LYCEUM: + GoLyceumGUID = go->GetGUID(); + break; + case GO_SF_S: + GoSFSGUID = go->GetGUID(); + break; + case GO_SF_N: + GoSFNGUID = go->GetGUID(); + break; + case GO_GOLEM_ROOM_N: + GoGolemNGUID = go->GetGUID(); + break; + case GO_GOLEM_ROOM_S: + GoGolemSGUID = go->GetGUID(); + break; + case GO_THRONE_ROOM: + GoThroneGUID = go->GetGUID(); + break; + case GO_CHEST_SEVEN: + GoChestGUID = go->GetGUID(); + break; + case GO_SPECTRAL_CHALICE: + GoSpectralChaliceGUID = go->GetGUID(); + break; + } + } + + void OnUnitDeath(Unit* unit) override + { + uint32 deadSenators = 0; + switch (unit->GetEntry()) + { + case NPC_WEAPON_TECHNICIAN: + case NPC_DOOMFORGE_ARCANASMITH: + case NPC_RAGEREAVER_GOLEM: + case NPC_WRATH_HAMMER_CONSTRUCT: + ArgelmachAdds.remove(unit->GetGUID()); + break; + case NPC_MAGMUS: + SetData(TYPE_IRON_HALL, DONE); + break; + case NPC_SHADOWFORGE_SENATOR: + deadSenators = 1; //hacky, but we cannot count the unit that just died through its state because OnUnitDeath() is called before the state is set. + for (const auto &senatorGUID: EmperorSenatorsVector) + if (Creature* senator = instance->GetCreature(senatorGUID)) + if (!senator->IsAlive() || senator->isDying()) + deadSenators++; + + if (Creature* emperor = instance->GetCreature(EmperorGUID)) + // send % of senators that died + emperor->AI()->SetData(0, (100 * deadSenators) / EmperorSenatorsVector.size()); + break; + case NPC_ANGERREL: + case NPC_DOPEREL: + case NPC_HATEREL: + case NPC_VILEREL: + case NPC_SEETHREL: + case NPC_GLOOMREL: + case NPC_DOOMREL: + GhostKillCount++; + if (GhostKillCount >= 7) + SetData(TYPE_TOMB_OF_SEVEN, DONE); + break; + default: + break; + } + } + + void SetData(uint32 type, uint32 data) override + { + LOG_DEBUG("scripts.ai", "Instance Blackrock Depths: SetData update (Type: {} Data {})", type, data); + + switch (type) + { + case TYPE_RING_OF_LAW: + encounter[0] = data; + switch (data) + { + case IN_PROGRESS: + TempSummonGrimstone = instance->SummonCreature(NPC_GRIMSTONE, GrimstonePositon); + break; + case FAIL: + if (TempSummonGrimstone) { - GuidList adds = ArgelmachAdds; - for (GuidList::const_iterator itr = adds.begin(); itr != adds.end();) + TempSummonGrimstone->RemoveFromWorld(); + TempSummonGrimstone = nullptr; + timeRingFail = GameTime::GetGameTime().count(); + } + SetData(TYPE_RING_OF_LAW, NOT_STARTED); + break; + case DONE: + for (auto const& itr : ArenaSpectators) + if (Creature* spectator = instance->GetCreature(itr)) { - if (Creature* argelmachAdd = instance->GetCreature(*itr)) + spectator->SetFaction(FACTION_NEUTRAL); + spectator->SetReactState(REACT_DEFENSIVE); + } + break; + default: + break; + } + break; + case TYPE_VAULT: + encounter[1] = data; + break; + case TYPE_BAR: + if (data == SPECIAL) + ++BarAleCount; + else + encounter[2] = data; + break; + case TYPE_TOMB_OF_SEVEN: + encounter[3] = data; + switch (data) + { + case IN_PROGRESS: + HandleGameObject(GoTombExitGUID, false); + HandleGameObject(GoTombEnterGUID, false); + break; + case DONE: + DoRespawnGameObject(GoChestGUID, DAY); + HandleGameObject(GoTombExitGUID, true); + HandleGameObject(GoTombEnterGUID, true); + break; + } + break; + case TYPE_LYCEUM: + encounter[4] = data; + if (data == DONE) + { + HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_N), true); + HandleGameObject(GetGuidData(DATA_GOLEM_DOOR_S), true); + if (Creature* magmus = instance->GetCreature(MagmusGUID)) + magmus->AI()->Talk(0); + ReplaceMoiraIfSaved(); // Need to place the correct final boss, but we need her to be spawned first. + } + break; + case TYPE_IRON_HALL: + encounter[5] = data; + switch (data) + { + case NOT_STARTED: + case IN_PROGRESS: + for (int i = 0; i < 6; i++) + if (Creature* ironhand = instance->GetCreature(IronhandGUID[i])) + ironhand->AI()->SetData(0, data == IN_PROGRESS); + break; + case DONE: + HandleGameObject(GetGuidData(DATA_THRONE_DOOR), true); + break; + default: + break; + } + break; + case DATA_OPEN_COFFER_DOORS: + OpenedCoofers += 1; + if (OpenedCoofers == 12) + { + Position pos = {812.15f, -348.91f, -50.579f, 0.7f}; + if (TempSummon* summon = instance->SummonCreature(NPC_WATCHMAN_DOOMGRIP, pos)) + summon->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); + } + break; + case DATA_GOLEM_LORD_ARGELMACH_INIT: + { + if (Creature* argelmach = instance->GetCreature(ArgelmachGUID)) + { + GuidList adds = ArgelmachAdds; + for (GuidList::const_iterator itr = adds.begin(); itr != adds.end();) + { + if (Creature* argelmachAdd = instance->GetCreature(*itr)) + { + if (argelmachAdd->GetEntry() == NPC_WRATH_HAMMER_CONSTRUCT) { - if (argelmachAdd->GetEntry() == NPC_WRATH_HAMMER_CONSTRUCT) + argelmachAdd->RemoveAurasDueToSpell(SPELL_STONED); + argelmachAdd->AI()->AttackStart(argelmach->GetVictim()); + itr = adds.erase(itr); + } + else if (argelmachAdd->GetEntry() == NPC_RAGEREAVER_GOLEM) + { + if (argelmachAdd->IsWithinDist2d(argelmach, 10.f)) { argelmachAdd->RemoveAurasDueToSpell(SPELL_STONED); argelmachAdd->AI()->AttackStart(argelmach->GetVictim()); itr = adds.erase(itr); } - else if (argelmachAdd->GetEntry() == NPC_RAGEREAVER_GOLEM) - { - if (argelmachAdd->IsWithinDist2d(argelmach, 10.f)) - { - argelmachAdd->RemoveAurasDueToSpell(SPELL_STONED); - argelmachAdd->AI()->AttackStart(argelmach->GetVictim()); - itr = adds.erase(itr); - } - else - ++itr; - } else - { ++itr; - } } else { ++itr; } } - - if (!adds.empty()) - { - argelmach->SetReactState(REACT_PASSIVE); - argelmach->SetTarget(); - argelmach->AI()->SetData(DATA_GOLEM_LORD_ARGELMACH_INIT, IN_PROGRESS); - } else { - argelmach->AI()->SetData(DATA_GOLEM_LORD_ARGELMACH_INIT, DONE); + ++itr; } } - break; - } - case DATA_GOLEM_LORD_ARGELMACH_ADDS: - { - if (Creature* argelmach = instance->GetCreature(ArgelmachGUID)) + + if (!adds.empty()) { - argelmach->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT); - argelmach->m_Events.AddEventAtOffset(new RestoreAttack(argelmach), 3s); - - for (ObjectGuid const& argelmachAddGUID : ArgelmachAdds) - { - if (Creature* argelmachAdd = instance->GetCreature(argelmachAddGUID)) - { - if (!argelmachAdd->IsInCombat()) - { - argelmachAdd->RemoveAurasDueToSpell(SPELL_STONED); - argelmachAdd->AI()->AttackStart(argelmach->GetVictim()); - } - } - } + argelmach->SetReactState(REACT_PASSIVE); + argelmach->SetTarget(); + argelmach->AI()->SetData(DATA_GOLEM_LORD_ARGELMACH_INIT, IN_PROGRESS); } - break; - } - default: - break; - } - - if (data == DONE || GhostKillCount >= 7) - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << encounter[0] << ' ' << encounter[1] << ' ' << encounter[2] << ' ' - << encounter[3] << ' ' << encounter[4] << ' ' << encounter[5] << ' ' << GhostKillCount; - - str_data = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } - } - - uint32 GetData(uint32 type) const override - { - switch (type) - { - case TYPE_RING_OF_LAW: - return encounter[0]; - case TYPE_VAULT: - return encounter[1]; - case TYPE_BAR: - if (encounter[2] == IN_PROGRESS && BarAleCount == 3) - return SPECIAL; else - return encounter[2]; - case TYPE_TOMB_OF_SEVEN: - return encounter[3]; - case TYPE_LYCEUM: - return encounter[4]; - case TYPE_IRON_HALL: - return encounter[5]; - case DATA_TIME_RING_FAIL: - return timeRingFail; - case DATA_ARENA_MOBS: - return arenaMobsToSpawn; - case DATA_ARENA_BOSS: - return arenaBossToSpawn; - } - return 0; - } - - ObjectGuid GetGuidData(uint32 data) const override - { - switch (data) - { - case DATA_EMPEROR: - return EmperorGUID; - case DATA_PHALANX: - return PhalanxGUID; - case DATA_MOIRA: - return MoiraGUID; - case DATA_COREN: - return CorenGUID; - case DATA_ARENA1: - return GoArena1GUID; - case DATA_ARENA2: - return GoArena2GUID; - case DATA_ARENA3: - return GoArena3GUID; - case DATA_ARENA4: - return GoArena4GUID; - case DATA_GO_BAR_KEG: - return GoBarKegGUID; - case DATA_GO_BAR_KEG_TRAP: - return GoBarKegTrapGUID; - case DATA_GO_BAR_DOOR: - return GoBarDoorGUID; - case DATA_SF_BRAZIER_N: - return GoSFNGUID; - case DATA_SF_BRAZIER_S: - return GoSFSGUID; - case DATA_THRONE_DOOR: - return GoThroneGUID; - case DATA_GOLEM_DOOR_N: - return GoGolemNGUID; - case DATA_GOLEM_DOOR_S: - return GoGolemSGUID; - case DATA_GO_CHALICE: - return GoSpectralChaliceGUID; - case DATA_MAGMUS: - { - return MagmusGUID; - } - } - - return ObjectGuid::Empty; - } - - std::string GetSaveData() override - { - return str_data; - } - - void Load(const char* in) override - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - - std::istringstream loadStream(in); - loadStream >> encounter[0] >> encounter[1] >> encounter[2] >> encounter[3] - >> encounter[4] >> encounter[5] >> GhostKillCount; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (encounter[i] == IN_PROGRESS) - encounter[i] = NOT_STARTED; - if (GhostKillCount > 0 && GhostKillCount < 7) - GhostKillCount = 0;//reset tomb of seven event - if (GhostKillCount >= 7) - GhostKillCount = 7; - - OUT_LOAD_INST_DATA_COMPLETE; - } - - void TombOfSevenEvent() - { - if (GhostKillCount < 7 && TombBossGUIDs[TombEventCounter]) - { - if (Creature* boss = instance->GetCreature(TombBossGUIDs[TombEventCounter])) - { - ++TombEventCounter; - boss->SetFaction(FACTION_DARK_IRON_DWARVES); - boss->SetImmuneToPC(false); - - // find suitable target here. - Player* target = boss->SelectNearestPlayer(130); - if (target && boss->CanCreatureAttack(target, true)) { - boss->AI()->AttackStart(target); - boss->AI()->DoZoneInCombat(); - tombResetTimer = TIMER_TOMB_RESET; + argelmach->AI()->SetData(DATA_GOLEM_LORD_ARGELMACH_INIT, DONE); } } + break; } + case DATA_GOLEM_LORD_ARGELMACH_ADDS: + { + if (Creature* argelmach = instance->GetCreature(ArgelmachGUID)) + { + argelmach->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT); + argelmach->m_Events.AddEventAtOffset(new RestoreAttack(argelmach), 3s); + + for (ObjectGuid const& argelmachAddGUID : ArgelmachAdds) + if (Creature* argelmachAdd = instance->GetCreature(argelmachAddGUID)) + if (!argelmachAdd->IsInCombat()) + { + argelmachAdd->RemoveAurasDueToSpell(SPELL_STONED); + argelmachAdd->AI()->AttackStart(argelmach->GetVictim()); + } + } + break; + } + default: + break; } - void TombOfSevenReset() + if (data == DONE || GhostKillCount >= 7) { - HandleGameObject(GoTombExitGUID, false);// close exit door - HandleGameObject(GoTombEnterGUID, true);// open entrance door - for (uint8 i = 0; i < 7; ++i) - { - if (Creature* boss = instance->GetCreature(TombBossGUIDs[i])) - { - if (!boss->IsAlive()) - { - //do not call EnterEvadeMode(), it will create infinit loops - boss->Respawn(); - boss->RemoveAllAuras(); - boss->GetThreatMgr().ClearAllThreat(); - boss->CombatStop(true); - boss->LoadCreaturesAddon(true); - boss->GetMotionMaster()->MoveTargetedHome(); - boss->SetLootRecipient(nullptr); - } - boss->SetFaction(FACTION_FRIENDLY); - boss->SetImmuneToPC(true); // think this is useless - if (i == 6) // doomrel needs explicit reset - { - boss->AI()->Reset(); - } - } - } + OUT_SAVE_INST_DATA; - GhostKillCount = 0; - TombEventCounter = 0; - TombTimer = TIMER_TOMB_START; - SetData(TYPE_TOMB_OF_SEVEN, NOT_STARTED); + std::ostringstream saveStream; + saveStream << encounter[0] << ' ' << encounter[1] << ' ' << encounter[2] << ' ' + << encounter[3] << ' ' << encounter[4] << ' ' << encounter[5] << ' ' << GhostKillCount; + + str_data = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } + } - bool CheckTombReset(uint32 diff) + uint32 GetData(uint32 type) const override + { + switch (type) { - bool anyBossAlive = false; // status of the bosses up until the current one - for (uint8 i = 0; i < TombEventCounter; i++) - { - Creature* boss = instance->GetCreature(TombBossGUIDs[i]); - if (boss) - { - anyBossAlive |= boss->IsAlive(); - if (boss->IsAlive() && boss->IsInCombat()) - { - tombResetTimer = TIMER_TOMB_RESET; - return false; // any boss in combat means we shouldn't reset. - } - } - } - if (!anyBossAlive) // no boss alive, put reset timer back up - { - tombResetTimer = TIMER_TOMB_RESET; - } - tombResetTimer -= diff; - return tombResetTimer < diff; - } - - void Update(uint32 diff) override - { - if ((GetData(TYPE_TOMB_OF_SEVEN) == IN_PROGRESS) && GhostKillCount < 7) - { - if (TombTimer <= diff) - { - TombTimer = TIMER_TOMBOFTHESEVEN; - TombOfSevenEvent(); - } + case TYPE_RING_OF_LAW: + return encounter[0]; + case TYPE_VAULT: + return encounter[1]; + case TYPE_BAR: + if (encounter[2] == IN_PROGRESS && BarAleCount == 3) + return SPECIAL; else - { - TombTimer -= diff; - } + return encounter[2]; + case TYPE_TOMB_OF_SEVEN: + return encounter[3]; + case TYPE_LYCEUM: + return encounter[4]; + case TYPE_IRON_HALL: + return encounter[5]; + case DATA_TIME_RING_FAIL: + return timeRingFail; + case DATA_ARENA_MOBS: + return arenaMobsToSpawn; + case DATA_ARENA_BOSS: + return arenaBossToSpawn; + } + return 0; + } - if (CheckTombReset(diff)) + ObjectGuid GetGuidData(uint32 data) const override + { + switch (data) + { + case DATA_EMPEROR: + return EmperorGUID; + case DATA_PHALANX: + return PhalanxGUID; + case DATA_MOIRA: + return MoiraGUID; + case DATA_COREN: + return CorenGUID; + case DATA_ARENA1: + return GoArena1GUID; + case DATA_ARENA2: + return GoArena2GUID; + case DATA_ARENA3: + return GoArena3GUID; + case DATA_ARENA4: + return GoArena4GUID; + case DATA_GO_BAR_KEG: + return GoBarKegGUID; + case DATA_GO_BAR_KEG_TRAP: + return GoBarKegTrapGUID; + case DATA_GO_BAR_DOOR: + return GoBarDoorGUID; + case DATA_SF_BRAZIER_N: + return GoSFNGUID; + case DATA_SF_BRAZIER_S: + return GoSFSGUID; + case DATA_THRONE_DOOR: + return GoThroneGUID; + case DATA_GOLEM_DOOR_N: + return GoGolemNGUID; + case DATA_GOLEM_DOOR_S: + return GoGolemSGUID; + case DATA_GO_CHALICE: + return GoSpectralChaliceGUID; + case DATA_MAGMUS: + { + return MagmusGUID; + } + } + + return ObjectGuid::Empty; + } + + std::string GetSaveData() override + { + return str_data; + } + + void Load(const char* in) override + { + if (!in) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(in); + + std::istringstream loadStream(in); + loadStream >> encounter[0] >> encounter[1] >> encounter[2] >> encounter[3] + >> encounter[4] >> encounter[5] >> GhostKillCount; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (encounter[i] == IN_PROGRESS) + encounter[i] = NOT_STARTED; + if (GhostKillCount > 0 && GhostKillCount < 7) + GhostKillCount = 0;//reset tomb of seven event + if (GhostKillCount >= 7) + GhostKillCount = 7; + + OUT_LOAD_INST_DATA_COMPLETE; + } + + void TombOfSevenEvent() + { + if (GhostKillCount < 7 && TombBossGUIDs[TombEventCounter]) + { + if (Creature* boss = instance->GetCreature(TombBossGUIDs[TombEventCounter])) + { + ++TombEventCounter; + boss->SetFaction(FACTION_DARK_IRON_DWARVES); + boss->SetImmuneToPC(false); + + // find suitable target here. + Player* target = boss->SelectNearestPlayer(130); + if (target && boss->CanCreatureAttack(target, true)) { - TombOfSevenReset(); + boss->AI()->AttackStart(target); + boss->AI()->DoZoneInCombat(); + tombResetTimer = TIMER_TOMB_RESET; } } } - }; + } + + void TombOfSevenReset() + { + HandleGameObject(GoTombExitGUID, false);// close exit door + HandleGameObject(GoTombEnterGUID, true);// open entrance door + for (uint8 i = 0; i < 7; ++i) + if (Creature* boss = instance->GetCreature(TombBossGUIDs[i])) + { + if (!boss->IsAlive()) + { + //do not call EnterEvadeMode(), it will create infinit loops + boss->Respawn(); + boss->RemoveAllAuras(); + boss->GetThreatMgr().ClearAllThreat(); + boss->CombatStop(true); + boss->LoadCreaturesAddon(true); + boss->GetMotionMaster()->MoveTargetedHome(); + boss->SetLootRecipient(nullptr); + } + boss->SetFaction(FACTION_FRIENDLY); + boss->SetImmuneToPC(true); // think this is useless + if (i == 6) // doomrel needs explicit reset + boss->AI()->Reset(); + } + + GhostKillCount = 0; + TombEventCounter = 0; + TombTimer = TIMER_TOMB_START; + SetData(TYPE_TOMB_OF_SEVEN, NOT_STARTED); + } + + bool CheckTombReset(uint32 diff) + { + bool anyBossAlive = false; // status of the bosses up until the current one + for (uint8 i = 0; i < TombEventCounter; i++) + { + Creature* boss = instance->GetCreature(TombBossGUIDs[i]); + if (boss) + { + anyBossAlive |= boss->IsAlive(); + if (boss->IsAlive() && boss->IsInCombat()) + { + tombResetTimer = TIMER_TOMB_RESET; + return false; // any boss in combat means we shouldn't reset. + } + } + } + if (!anyBossAlive) // no boss alive, put reset timer back up + tombResetTimer = TIMER_TOMB_RESET; + tombResetTimer -= diff; + return tombResetTimer < diff; + } + + void Update(uint32 diff) override + { + if ((GetData(TYPE_TOMB_OF_SEVEN) == IN_PROGRESS) && GhostKillCount < 7) + { + if (TombTimer <= diff) + { + TombTimer = TIMER_TOMBOFTHESEVEN; + TombOfSevenEvent(); + } + else + { + TombTimer -= diff; + } + + if (CheckTombReset(diff)) + TombOfSevenReset(); + } + } }; void AddSC_instance_blackrock_depths() { - new instance_blackrock_depths(); + RegisterInstanceScript(instance_blackrock_depths, MAP_BLACKROCK_DEPTHS); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h index 8b33f180b..4e8f43dad 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h @@ -155,5 +155,6 @@ inline AI* GetBlackrockSpireAI(T* obj) } #define RegisterBlackrockSpireCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackrockSpireAI) +#define RegisterBlackrockSpireGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackrockSpireAI) #endif diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp index d979336cb..a4f436277 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp @@ -40,98 +40,85 @@ enum Events EVENT_CHECK_CONFLAGRATION_TARGET }; -class boss_drakkisath : public CreatureScript +struct boss_drakkisath : public BossAI { -public: - boss_drakkisath() : CreatureScript("boss_drakkisath") { } - - struct boss_drakkisathAI : public BossAI + boss_drakkisath(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH) { - boss_drakkisathAI(Creature* creature) : BossAI(creature, DATA_GENERAL_DRAKKISATH) - { - _conflagrateThreat = 0.0f; - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s); - events.ScheduleEvent(EVENT_CLEAVE, 8s); - events.ScheduleEvent(EVENT_CONFLAGRATION, 15s); - events.ScheduleEvent(EVENT_THUNDERCLAP, 17s); - events.ScheduleEvent(EVENT_PIERCE_ARMOR, 5s); - events.ScheduleEvent(EVENT_RAGE, 1s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FLAMESTRIKE: - DoCastAOE(SPELL_FLAMESTRIKE); - events.ScheduleEvent(EVENT_FLAMESTRIKE, 10s); - break; - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, 8s); - break; - case EVENT_CONFLAGRATION: - DoCastVictim(SPELL_CONFLAGRATION); - - if (Unit* target = me->GetVictim()) - { - _conflagrateTarget = me->GetVictim()->GetGUID(); - _conflagrateThreat = me->GetThreatMgr().GetThreat(me->GetVictim()); - me->GetThreatMgr().ModifyThreatByPercent(target, -100); - } - events.ScheduleEvent(EVENT_CONFLAGRATION, 18s, 25s); - events.ScheduleEvent(EVENT_CHECK_CONFLAGRATION_TARGET, 10s); - break; - case EVENT_THUNDERCLAP: - DoCastVictim(SPELL_THUNDERCLAP); - events.ScheduleEvent(EVENT_THUNDERCLAP, 20s); - break; - case EVENT_PIERCE_ARMOR: - DoCastVictim(SPELL_PIERCE_ARMOR); - events.ScheduleEvent(EVENT_PIERCE_ARMOR, 40s); - break; - case EVENT_RAGE: - DoCastSelf(SPELL_RAGE); - events.ScheduleEvent(EVENT_RAGE, 35s); - break; - case EVENT_CHECK_CONFLAGRATION_TARGET: - if (Unit* target = ObjectAccessor::GetUnit(*me, _conflagrateTarget)) - { - me->GetThreatMgr().AddThreat(target, _conflagrateThreat); - } - break; - } - } - DoMeleeAttackIfReady(); - } - - private: - float _conflagrateThreat; - ObjectGuid _conflagrateTarget; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + _conflagrateThreat = 0.0f; } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 6s); + events.ScheduleEvent(EVENT_CLEAVE, 8s); + events.ScheduleEvent(EVENT_CONFLAGRATION, 15s); + events.ScheduleEvent(EVENT_THUNDERCLAP, 17s); + events.ScheduleEvent(EVENT_PIERCE_ARMOR, 5s); + events.ScheduleEvent(EVENT_RAGE, 1s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FLAMESTRIKE: + DoCastAOE(SPELL_FLAMESTRIKE); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 10s); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 8s); + break; + case EVENT_CONFLAGRATION: + DoCastVictim(SPELL_CONFLAGRATION); + + if (Unit* target = me->GetVictim()) + { + _conflagrateTarget = me->GetVictim()->GetGUID(); + _conflagrateThreat = me->GetThreatMgr().GetThreat(me->GetVictim()); + me->GetThreatMgr().ModifyThreatByPercent(target, -100); + } + events.ScheduleEvent(EVENT_CONFLAGRATION, 18s, 25s); + events.ScheduleEvent(EVENT_CHECK_CONFLAGRATION_TARGET, 10s); + break; + case EVENT_THUNDERCLAP: + DoCastVictim(SPELL_THUNDERCLAP); + events.ScheduleEvent(EVENT_THUNDERCLAP, 20s); + break; + case EVENT_PIERCE_ARMOR: + DoCastVictim(SPELL_PIERCE_ARMOR); + events.ScheduleEvent(EVENT_PIERCE_ARMOR, 40s); + break; + case EVENT_RAGE: + DoCastSelf(SPELL_RAGE); + events.ScheduleEvent(EVENT_RAGE, 35s); + break; + case EVENT_CHECK_CONFLAGRATION_TARGET: + if (Unit* target = ObjectAccessor::GetUnit(*me, _conflagrateTarget)) + me->GetThreatMgr().AddThreat(target, _conflagrateThreat); + break; + } + } + DoMeleeAttackIfReady(); + } + +private: + float _conflagrateThreat; + ObjectGuid _conflagrateTarget; }; void AddSC_boss_drakkisath() { - new boss_drakkisath(); + RegisterBlackrockSpireCreatureAI(boss_drakkisath); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp index f04431c5c..072ff592d 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp @@ -51,125 +51,114 @@ enum Events EVENT_SUMMONED_2 = 6 }; -class boss_gyth : public CreatureScript +struct boss_gyth : public BossAI { -public: - boss_gyth() : CreatureScript("boss_gyth") { } + boss_gyth(Creature* creature) : BossAI(creature, DATA_GYTH) { } - struct boss_gythAI : public BossAI + void Reset() override { - boss_gythAI(Creature* creature) : BossAI(creature, DATA_GYTH) { } - - void Reset() override + if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) { - if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) - { - instance->SetBossState(DATA_GYTH, NOT_STARTED); - summons.DespawnAll(); - me->DespawnOrUnsummon(); - } - - SetInvincibility(true); // Don't let boss die before summoning Rend. - - ScheduleHealthCheckEvent(25, [&] { - DoCastAOE(SPELL_SUMMON_REND, true); - me->RemoveAura(SPELL_REND_MOUNTS); - SetInvincibility(false); - }); + instance->SetBossState(DATA_GYTH, NOT_STARTED); + summons.DespawnAll(); + me->DespawnOrUnsummon(); } - void JustEngagedWith(Unit* /*who*/) override + SetInvincibility(true); // Don't let boss die before summoning Rend. + + ScheduleHealthCheckEvent(25, [&] { + DoCastAOE(SPELL_SUMMON_REND, true); + me->RemoveAura(SPELL_REND_MOUNTS); + SetInvincibility(false); + }); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + + events.ScheduleEvent(EVENT_CORROSIVE_ACID, 8s, 16s); + events.ScheduleEvent(EVENT_FREEZE, 8s, 16s); + events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 16s); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s, 18s); + } + + void EnterEvadeMode(EvadeReason why) override + { + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); + BossAI::EnterEvadeMode(why); + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + events.ScheduleEvent(EVENT_SUMMONED_1, 1s); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + summon->AI()->AttackStart(me->SelectVictim()); + } + + // Prevent clearing summon list, otherwise Rend despawns if the drake is killed first. + void JustDied(Unit* /*killer*/) override + { + instance->SetBossState(DATA_GYTH, DONE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) { - _JustEngagedWith(); - - events.ScheduleEvent(EVENT_CORROSIVE_ACID, 8s, 16s); - events.ScheduleEvent(EVENT_FREEZE, 8s, 16s); - events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 16s); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s, 18s); - } - - void EnterEvadeMode(EvadeReason why) override - { - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); - BossAI::EnterEvadeMode(why); - } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - events.ScheduleEvent(EVENT_SUMMONED_1, 1s); - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - summon->AI()->AttackStart(me->SelectVictim()); - } - - // Prevent clearing summon list, otherwise Rend despawns if the drake is killed first. - void JustDied(Unit* /*killer*/) override - { - instance->SetBossState(DATA_GYTH, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SUMMONED_1: - me->AddAura(SPELL_REND_MOUNTS, me); - if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 40.0f)) - portcullis->UseDoorOrButton(); - events.ScheduleEvent(EVENT_SUMMONED_2, 2s); - break; - case EVENT_SUMMONED_2: - me->GetMotionMaster()->MoveWaypoint(GYTH_PATH_1, false); - break; - default: - break; - } - } - return; - } - events.Update(diff); while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { - case EVENT_CORROSIVE_ACID: - DoCast(me, SPELL_CORROSIVE_ACID); - events.ScheduleEvent(EVENT_CORROSIVE_ACID, 10s, 16s); + case EVENT_SUMMONED_1: + me->AddAura(SPELL_REND_MOUNTS, me); + if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 40.0f)) + portcullis->UseDoorOrButton(); + events.ScheduleEvent(EVENT_SUMMONED_2, 2s); break; - case EVENT_FREEZE: - DoCast(me, SPELL_FREEZE); - events.ScheduleEvent(EVENT_FREEZE, 10s, 16s); - break; - case EVENT_FLAME_BREATH: - DoCast(me, SPELL_FLAMEBREATH); - events.ScheduleEvent(EVENT_FLAME_BREATH, 10s, 16s); - break; - case EVENT_KNOCK_AWAY: - DoCastVictim(SPELL_KNOCK_AWAY); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s, 20s); + case EVENT_SUMMONED_2: + me->GetMotionMaster()->MoveWaypoint(GYTH_PATH_1, false); break; default: break; } } - DoMeleeAttackIfReady(); + return; } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CORROSIVE_ACID: + DoCast(me, SPELL_CORROSIVE_ACID); + events.ScheduleEvent(EVENT_CORROSIVE_ACID, 10s, 16s); + break; + case EVENT_FREEZE: + DoCast(me, SPELL_FREEZE); + events.ScheduleEvent(EVENT_FREEZE, 10s, 16s); + break; + case EVENT_FLAME_BREATH: + DoCast(me, SPELL_FLAMEBREATH); + events.ScheduleEvent(EVENT_FLAME_BREATH, 10s, 16s); + break; + case EVENT_KNOCK_AWAY: + DoCastVictim(SPELL_KNOCK_AWAY); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s, 20s); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); } }; @@ -231,6 +220,6 @@ class spell_gyth_chromatic_protection : public AuraScript void AddSC_boss_gyth() { - new boss_gyth(); + RegisterBlackrockSpireCreatureAI(boss_gyth); RegisterSpellScript(spell_gyth_chromatic_protection); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp index bd2ffde13..93f1c2054 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp @@ -38,70 +38,59 @@ enum Events const Position SummonLocation = { -167.9561f, -411.7844f, 76.23057f, 1.53589f }; -class boss_halycon : public CreatureScript +struct boss_halycon : public BossAI { -public: - boss_halycon() : CreatureScript("boss_halycon") { } + boss_halycon(Creature* creature) : BossAI(creature, DATA_HALYCON) { } - struct boss_halyconAI : public BossAI + void Reset() override { - boss_halyconAI(Creature* creature) : BossAI(creature, DATA_HALYCON) { } + _Reset(); + } - void Reset() override + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + events.ScheduleEvent(EVENT_REND, 17s, 20s); + events.ScheduleEvent(EVENT_THRASH, 10s, 12s); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + me->SummonCreature(NPC_GIZRUL_THE_SLAVENER, SummonLocation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000); + Talk(EMOTE_DEATH); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_REND, 17s, 20s); - events.ScheduleEvent(EVENT_THRASH, 10s, 12s); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - me->SummonCreature(NPC_GIZRUL_THE_SLAVENER, SummonLocation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000); - Talk(EMOTE_DEATH); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) + switch (eventId) { - switch (eventId) - { - case EVENT_REND: - DoCastVictim(SPELL_REND); - events.ScheduleEvent(EVENT_REND, 8s, 10s); - break; - case EVENT_THRASH: - DoCast(me, SPELL_THRASH); - break; - default: - break; - } + case EVENT_REND: + DoCastVictim(SPELL_REND); + events.ScheduleEvent(EVENT_REND, 8s, 10s); + break; + case EVENT_THRASH: + DoCast(me, SPELL_THRASH); + break; + default: + break; } - DoMeleeAttackIfReady(); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + DoMeleeAttackIfReady(); } }; void AddSC_boss_halycon() { - new boss_halycon(); + RegisterBlackrockSpireCreatureAI(boss_halycon); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp index b7e03f34f..5de41fcf1 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp @@ -31,69 +31,58 @@ enum Events EVENT_KNOCK_AWAY = 2 }; -class boss_highlord_omokk : public CreatureScript +struct boss_highlord_omokk : public BossAI { -public: - boss_highlord_omokk() : CreatureScript("boss_highlord_omokk") { } + boss_highlord_omokk(Creature* creature) : BossAI(creature, DATA_HIGHLORD_OMOKK) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockSpireAI(creature); + _Reset(); } - struct boss_highlordomokkAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_highlordomokkAI(Creature* creature) : BossAI(creature, DATA_HIGHLORD_OMOKK) { } + _JustEngagedWith(); + events.ScheduleEvent(EVENT_FRENZY, 20s); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 18s); + } - void Reset() override + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - _Reset(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_FRENZY, 20s); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 18s); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) + switch (eventId) { - switch (eventId) - { - case EVENT_FRENZY: - DoCastVictim(SPELL_FRENZY); - events.ScheduleEvent(EVENT_FRENZY, 60s); - break; - case EVENT_KNOCK_AWAY: - DoCastVictim(SPELL_KNOCK_AWAY); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s); - break; - default: - break; - } + case EVENT_FRENZY: + DoCastVictim(SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 60s); + break; + case EVENT_KNOCK_AWAY: + DoCastVictim(SPELL_KNOCK_AWAY); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s); + break; + default: + break; } - DoMeleeAttackIfReady(); } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_highlordomokk() { - new boss_highlord_omokk(); + RegisterBlackrockSpireCreatureAI(boss_highlord_omokk); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp index 0eeab9e2a..6b0f31217 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp @@ -49,145 +49,130 @@ enum EventPhase EVENT_PHASE_FIGHT = 2 }; -class boss_lord_valthalak : public CreatureScript +struct boss_lord_valthalak : public BossAI { -public: - boss_lord_valthalak() : CreatureScript("boss_lord_valthalak") { } + boss_lord_valthalak(Creature* creature) : BossAI(creature, DATA_LORD_VALTHALAK) { } - struct boss_lord_valthalakAI : public BossAI + void Reset() override { - boss_lord_valthalakAI(Creature* creature) : BossAI(creature, DATA_LORD_VALTHALAK) { } + BossAI::Reset(); - void Reset() override - { - BossAI::Reset(); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - - frenzy40 = false; - frenzy15 = false; - } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - StartTalking(TALK_SUMMON, 8s); - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - Talk(TALK_AGGRO); - - events.SetPhase(EVENT_PHASE_FIGHT); - events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 6s, 8s, 0, EVENT_PHASE_FIGHT); - events.ScheduleEvent(EVENT_SHADOW_WRATH, 9s, 18s, 0, EVENT_PHASE_FIGHT); - } - - void JustDied(Unit* killer) override - { - BossAI::JustDied(killer); - - instance->SetData(DATA_LORD_VALTHALAK, DONE); - } - - void StartTalking(uint32 talkGroupId, Milliseconds timer) - { - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->AttackStop(); - - Talk(talkGroupId); - - events.SetPhase(EVENT_PHASE_TALK); - events.ScheduleEvent(EVENT_FIGHT, timer, 0, EVENT_PHASE_TALK); - } - - void StartFighting() - { - events.SetPhase(EVENT_PHASE_FIGHT); - - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - - DoZoneInCombat(); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override - { - if (!frenzy40 && me->HealthBelowPctDamaged(40, damage)) - { - frenzy40 = true; - DoCast(me, SPELL_FRENZY); - - events.CancelEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN); - - StartTalking(TALK_40_HP, 5s); - } - - if (!frenzy15 && me->HealthBelowPctDamaged(15, damage)) - { - frenzy15 = true; - - events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 12s, 19s, 0, EVENT_PHASE_FIGHT); - - StartTalking(TALK_15_HP, 5s); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !events.IsInPhase(EVENT_PHASE_TALK)) - { - return; - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FIGHT: - StartFighting(); - break; - case EVENT_SUMMON_SPECTRAL_ASSASSIN: - DoCast(me, SPELL_SUMMON_SPECTRAL_ASSASSIN); - events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 30s, 35s, 0, EVENT_PHASE_FIGHT); - break; - case EVENT_SHADOW_BOLT_VOLLEY: - DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY); - events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 4s, 6s, 0, EVENT_PHASE_FIGHT); - break; - case EVENT_SHADOW_WRATH: - DoCastVictim(SPELL_SHADOW_WRATH); - events.ScheduleEvent(EVENT_SHADOW_WRATH, 19s, 24s, 0, EVENT_PHASE_FIGHT); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - private: - bool frenzy40; - bool frenzy15; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + _frenzy40 = false; + _frenzy15 = false; } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + StartTalking(TALK_SUMMON, 8s); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + + Talk(TALK_AGGRO); + + events.SetPhase(EVENT_PHASE_FIGHT); + events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 6s, 8s, 0, EVENT_PHASE_FIGHT); + events.ScheduleEvent(EVENT_SHADOW_WRATH, 9s, 18s, 0, EVENT_PHASE_FIGHT); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + + instance->SetData(DATA_LORD_VALTHALAK, DONE); + } + + void StartTalking(uint32 talkGroupId, Milliseconds timer) + { + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->AttackStop(); + + Talk(talkGroupId); + + events.SetPhase(EVENT_PHASE_TALK); + events.ScheduleEvent(EVENT_FIGHT, timer, 0, EVENT_PHASE_TALK); + } + + void StartFighting() + { + events.SetPhase(EVENT_PHASE_FIGHT); + + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + + DoZoneInCombat(); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override + { + if (!_frenzy40 && me->HealthBelowPctDamaged(40, damage)) + { + _frenzy40 = true; + DoCast(me, SPELL_FRENZY); + + events.CancelEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN); + + StartTalking(TALK_40_HP, 5s); + } + + if (!_frenzy15 && me->HealthBelowPctDamaged(15, damage)) + { + _frenzy15 = true; + + events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 12s, 19s, 0, EVENT_PHASE_FIGHT); + + StartTalking(TALK_15_HP, 5s); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(EVENT_PHASE_TALK)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIGHT: + StartFighting(); + break; + case EVENT_SUMMON_SPECTRAL_ASSASSIN: + DoCast(me, SPELL_SUMMON_SPECTRAL_ASSASSIN); + events.ScheduleEvent(EVENT_SUMMON_SPECTRAL_ASSASSIN, 30s, 35s, 0, EVENT_PHASE_FIGHT); + break; + case EVENT_SHADOW_BOLT_VOLLEY: + DoCastVictim(SPELL_SHADOW_BOLT_VOLLEY); + events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 4s, 6s, 0, EVENT_PHASE_FIGHT); + break; + case EVENT_SHADOW_WRATH: + DoCastVictim(SPELL_SHADOW_WRATH); + events.ScheduleEvent(EVENT_SHADOW_WRATH, 19s, 24s, 0, EVENT_PHASE_FIGHT); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } +private: + bool _frenzy40; + bool _frenzy15; }; void AddSC_boss_lord_valthalak() { - new boss_lord_valthalak(); + RegisterBlackrockSpireCreatureAI(boss_lord_valthalak); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mor_grayhoof.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mor_grayhoof.cpp index 002047010..c772ed975 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mor_grayhoof.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mor_grayhoof.cpp @@ -96,13 +96,9 @@ struct boss_mor_grayhoof : public BossAI case PHASE_HUMAN: spell = Acore::Containers::SelectRandomContainerElement(humanSpells); if (spell == SPELL_REJUVENATION || spell == SPELL_HEALING_TOUCH) - { DoCastSelf(spell); - } else - { DoCastAOE(spell); - } break; case PHASE_BEAR: spell = Acore::Containers::SelectRandomContainerElement(bearSpells); @@ -155,9 +151,7 @@ struct boss_mor_grayhoof : public BossAI { CastRandomSpell(PHASE_BEAR); if (context.GetRepeatCounter() <= 3) - { context.Repeat(); - } }); } else if (_phase == PHASE_BEAR && me->HealthBelowPct(50.f)) @@ -170,9 +164,7 @@ struct boss_mor_grayhoof : public BossAI { CastRandomSpell(PHASE_CAT); if (context.GetRepeatCounter() <= 3) - { context.Repeat(); - } }); } else if (_phase == PHASE_CAT && me->HealthBelowPct(25.f)) @@ -203,9 +195,7 @@ struct boss_mor_grayhoof : public BossAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } _scheduler.Update(diff, [this] { diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp index 4f2b2511e..74a8227c7 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp @@ -46,93 +46,83 @@ constexpr uint32 CALL_HELP = 0; const Position SummonLocation1 = {-49.43f, -455.82f, 77.82f, 4.61f}; const Position SummonLocation2 = {-58.48f, -456.29f, 77.82f, 4.613f}; -class boss_overlord_wyrmthalak : public CreatureScript +struct boss_overlord_wyrmthalak : public BossAI { -public: - boss_overlord_wyrmthalak() : CreatureScript("boss_overlord_wyrmthalak") { } + boss_overlord_wyrmthalak(Creature* creature) : BossAI(creature, DATA_OVERLORD_WYRMTHALAK) { } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockSpireAI(creature); + _Reset(); + _summoned = false; } - struct boss_overlordwyrmthalakAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_overlordwyrmthalakAI(Creature* creature) : BossAI(creature, DATA_OVERLORD_WYRMTHALAK) { } + _JustEngagedWith(); + events.ScheduleEvent(EVENT_BLAST_WAVE, 20s); + events.ScheduleEvent(EVENT_SHOUT, 2s); + events.ScheduleEvent(EVENT_CLEAVE, 6s); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s); + } - bool Summoned; + void JustDied(Unit* /*killer*/) override + { + instance->SetBossState(DATA_OVERLORD_WYRMTHALAK, DONE); + } - void Reset() override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (!_summoned && HealthBelowPct(51)) { - _Reset(); - Summoned = false; - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_BLAST_WAVE, 20s); - events.ScheduleEvent(EVENT_SHOUT, 2s); - events.ScheduleEvent(EVENT_CLEAVE, 6s); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 12s); - } - - void JustDied(Unit* /*killer*/) override - { - instance->SetBossState(DATA_OVERLORD_WYRMTHALAK, DONE); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (!Summoned && HealthBelowPct(51)) + Talk(CALL_HELP); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) { - Talk(CALL_HELP); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - { - if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS)) - warlord->AI()->AttackStart(target); - if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS)) - berserker->AI()->AttackStart(target); - Summoned = true; - } + if (Creature* warlord = me->SummonCreature(NPC_SPIRESTONE_WARLORD, SummonLocation1, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS)) + warlord->AI()->AttackStart(target); + if (Creature* berserker = me->SummonCreature(NPC_SMOLDERTHORN_BERSERKER, SummonLocation2, TEMPSUMMON_TIMED_DESPAWN, 300 * IN_MILLISECONDS)) + berserker->AI()->AttackStart(target); + _summoned = true; } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BLAST_WAVE: - DoCastVictim(SPELL_BLASTWAVE); - events.ScheduleEvent(EVENT_BLAST_WAVE, 20s); - break; - case EVENT_SHOUT: - DoCastVictim(SPELL_SHOUT); - events.ScheduleEvent(EVENT_SHOUT, 10s); - break; - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, 7s); - break; - case EVENT_KNOCK_AWAY: - DoCastVictim(SPELL_KNOCKAWAY); - events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s); - break; - } - } - DoMeleeAttackIfReady(); } - }; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BLAST_WAVE: + DoCastVictim(SPELL_BLASTWAVE); + events.ScheduleEvent(EVENT_BLAST_WAVE, 20s); + break; + case EVENT_SHOUT: + DoCastVictim(SPELL_SHOUT); + events.ScheduleEvent(EVENT_SHOUT, 10s); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 7s); + break; + case EVENT_KNOCK_AWAY: + DoCastVictim(SPELL_KNOCKAWAY); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 14s); + break; + } + } + DoMeleeAttackIfReady(); + } + +private: + bool _summoned; }; void AddSC_boss_overlordwyrmthalak() { - new boss_overlord_wyrmthalak(); + RegisterBlackrockSpireCreatureAI(boss_overlord_wyrmthalak); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp index 55c171291..753dfcb99 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp @@ -68,241 +68,226 @@ enum Events EVENT_ENTER_COMBAT = 10 }; -class boss_pyroguard_emberseer : public CreatureScript +struct boss_pyroguard_emberseer : public BossAI { -public: - boss_pyroguard_emberseer() : CreatureScript("boss_pyroguard_emberseer") { } + boss_pyroguard_emberseer(Creature* creature) : BossAI(creature, DATA_PYROGAURD_EMBERSEER) { } - struct boss_pyroguard_emberseerAI : public BossAI + void Reset() override { - boss_pyroguard_emberseerAI(Creature* creature) : BossAI(creature, DATA_PYROGAURD_EMBERSEER) { } + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(true); + events.Reset(); + // Apply auras on spawn and reset + // DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); // Need to find this in old DBC if possible + me->RemoveAura(SPELL_EMBERSEER_FULL_STRENGTH); + me->RemoveAura(SPELL_EMBERSEER_GROWING); + me->RemoveAura(SPELL_EMBERSEER_GROWING_TRIGGER); + events.ScheduleEvent(EVENT_RESPAWN, 5s); + // Hack for missing trigger spell + events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); - void Reset() override + // Open doors on reset + if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS) + OpenDoors(false); // Opens 2 entrance doors + } + + void SetData(uint32 /*type*/, uint32 data) override + { + switch (data) { - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(true); - events.Reset(); - // Apply auras on spawn and reset - // DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); // Need to find this in old DBC if possible - me->RemoveAura(SPELL_EMBERSEER_FULL_STRENGTH); - me->RemoveAura(SPELL_EMBERSEER_GROWING); - me->RemoveAura(SPELL_EMBERSEER_GROWING_TRIGGER); - events.ScheduleEvent(EVENT_RESPAWN, 5s); - // Hack for missing trigger spell - events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); - - // Open doors on reset - if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS) - OpenDoors(false); // Opens 2 entrance doors + case 1: + events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s); + instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS); + break; + case 2: + // Close these two doors on Blackhand Incarcerators aggro + if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN))) + if (door1->GetGoState() == GO_STATE_ACTIVE) + door1->SetGoState(GO_STATE_READY); + if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS))) + if (door2->GetGoState() == GO_STATE_ACTIVE) + door2->SetGoState(GO_STATE_READY); + break; + case 3: + Reset(); + break; + default: + break; } + } - void SetData(uint32 /*type*/, uint32 data) override + void JustEngagedWith(Unit* /*who*/) override + { + // ### TODO Check combat timing ### + events.ScheduleEvent(EVENT_FIRENOVA, 6s); + events.ScheduleEvent(EVENT_FLAMEBUFFET, 3s); + events.ScheduleEvent(EVENT_PYROBLAST, 14s); + } + + void JustDied(Unit* /*killer*/) override + { + // Activate all the runes + UpdateRunes(GO_STATE_READY); + // Opens all 3 doors + OpenDoors(true); + // Complete encounter + instance->SetBossState(DATA_PYROGAURD_EMBERSEER, DONE); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_ENCAGE_EMBERSEER) + if (!me->GetAuraCount(SPELL_ENCAGED_EMBERSEER)) + me->CastSpell(me, SPELL_ENCAGED_EMBERSEER); + + if (spell->Id == SPELL_EMBERSEER_GROWING_TRIGGER) { - switch (data) + if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 10) + Talk(EMOTE_TEN_STACK); + + if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20) { - case 1: - events.ScheduleEvent(EVENT_PRE_FIGHT_1, 2s); - instance->SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS); - break; - case 2: - // Close these two doors on Blackhand Incarcerators aggro - if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN))) - if (door1->GetGoState() == GO_STATE_ACTIVE) - door1->SetGoState(GO_STATE_READY); - if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS))) - if (door2->GetGoState() == GO_STATE_ACTIVE) - door2->SetGoState(GO_STATE_READY); - break; - case 3: - Reset(); - break; - default: - break; + events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start + + // Schedule out the pre-combat scene + events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s); + events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s); + events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s); } } + } - void JustEngagedWith(Unit* /*who*/) override + void OpenDoors(bool Boss_Killed) + { + // These two doors reopen on reset or boss kill + if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN))) + door1->SetGoState(GO_STATE_ACTIVE); + if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS))) + door2->SetGoState(GO_STATE_ACTIVE); + + // This door opens on boss kill + if (Boss_Killed) + if (GameObject* door3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_OUT))) + door3->SetGoState(GO_STATE_ACTIVE); + } + + void UpdateRunes(GOState state) + { + // update all runes + if (GameObject* rune1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_1))) + rune1->SetGoState(state); + if (GameObject* rune2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_2))) + rune2->SetGoState(state); + if (GameObject* rune3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_3))) + rune3->SetGoState(state); + if (GameObject* rune4 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_4))) + rune4->SetGoState(state); + if (GameObject* rune5 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_5))) + rune5->SetGoState(state); + if (GameObject* rune6 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_6))) + rune6->SetGoState(state); + if (GameObject* rune7 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_7))) + rune7->SetGoState(state); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) { - // ### TODO Check combat timing ### - events.ScheduleEvent(EVENT_FIRENOVA, 6s); - events.ScheduleEvent(EVENT_FLAMEBUFFET, 3s); - events.ScheduleEvent(EVENT_PYROBLAST, 14s); - } - - void JustDied(Unit* /*killer*/) override - { - // Activate all the runes - UpdateRunes(GO_STATE_READY); - // Opens all 3 doors - OpenDoors(true); - // Complete encounter - instance->SetBossState(DATA_PYROGAURD_EMBERSEER, DONE); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_ENCAGE_EMBERSEER) - { - if (!me->GetAuraCount(SPELL_ENCAGED_EMBERSEER)) - me->CastSpell(me, SPELL_ENCAGED_EMBERSEER); - } - - if (spell->Id == SPELL_EMBERSEER_GROWING_TRIGGER) - { - if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 10) - Talk(EMOTE_TEN_STACK); - - if (me->GetAuraCount(SPELL_EMBERSEER_GROWING_TRIGGER) == 20) - { - events.CancelEvent(EVENT_FIRE_SHIELD); // temporarily cancel fire shield to keep it from interrupting combat start - - // Schedule out the pre-combat scene - events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_1, 0s); - events.ScheduleEvent(EVENT_PRE_ENTER_COMBAT_2, 2s); - events.ScheduleEvent(EVENT_ENTER_COMBAT, 5s); - } - } - } - - void OpenDoors(bool Boss_Killed) - { - // These two doors reopen on reset or boss kill - if (GameObject* door1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_IN))) - door1->SetGoState(GO_STATE_ACTIVE); - if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_DOORS))) - door2->SetGoState(GO_STATE_ACTIVE); - - // This door opens on boss kill - if (Boss_Killed) - if (GameObject* door3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_OUT))) - door3->SetGoState(GO_STATE_ACTIVE); - } - - void UpdateRunes(GOState state) - { - // update all runes - if (GameObject* rune1 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_1))) - rune1->SetGoState(state); - if (GameObject* rune2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_2))) - rune2->SetGoState(state); - if (GameObject* rune3 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_3))) - rune3->SetGoState(state); - if (GameObject* rune4 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_4))) - rune4->SetGoState(state); - if (GameObject* rune5 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_5))) - rune5->SetGoState(state); - if (GameObject* rune6 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_6))) - rune6->SetGoState(state); - if (GameObject* rune7 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_EMBERSEER_RUNE_7))) - rune7->SetGoState(state); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RESPAWN: - { - // Respawn all Blackhand Incarcerators - std::list creatureList; - GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f); - for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) - if (Creature* creature = *itr) - { - if (!creature->IsAlive()) - creature->Respawn(); - - creature->AI()->SetData(1, 2); - } - me->AddAura(SPELL_ENCAGED_EMBERSEER, me); - instance->SetBossState(DATA_PYROGAURD_EMBERSEER, NOT_STARTED); - break; - } - case EVENT_PRE_FIGHT_1: - { - // Set data on all Blackhand Incarcerators - std::list creatureList; - GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f); - for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) - { - if (Creature* creature = *itr) - creature->AI()->SetData(1, 1); - } - events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s); - break; - } - case EVENT_PRE_FIGHT_2: - me->CastSpell(me, SPELL_FREEZE_ANIM); - me->CastSpell(me, SPELL_EMBERSEER_GROWING); - Talk(EMOTE_ONE_STACK); - break; - case EVENT_FIRE_SHIELD: - // #### Spell isn't doing any damage ??? #### - DoCast(me, SPELL_FIRE_SHIELD); - events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); - break; - case EVENT_PRE_ENTER_COMBAT_1: - me->RemoveAura(SPELL_ENCAGED_EMBERSEER); - me->RemoveAura(SPELL_FREEZE_ANIM); - me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH); - Talk(EMOTE_FREE_OF_BONDS); - break; - case EVENT_PRE_ENTER_COMBAT_2: - Talk(YELL_FREE_OF_BONDS); - break; - case EVENT_ENTER_COMBAT: - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(false); - DoZoneInCombat(); - // re-enable fire shield - events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s); - break; - default: - break; - } - } - return; - } - events.Update(diff); while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { + case EVENT_RESPAWN: + { + // Respawn all Blackhand Incarcerators + std::list creatureList; + GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f); + for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + if (Creature* creature = *itr) + { + if (!creature->IsAlive()) + creature->Respawn(); + + creature->AI()->SetData(1, 2); + } + me->AddAura(SPELL_ENCAGED_EMBERSEER, me); + instance->SetBossState(DATA_PYROGAURD_EMBERSEER, NOT_STARTED); + break; + } + case EVENT_PRE_FIGHT_1: + { + // Set data on all Blackhand Incarcerators + std::list creatureList; + GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 35.0f); + for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + if (Creature* creature = *itr) + creature->AI()->SetData(1, 1); + events.ScheduleEvent(EVENT_PRE_FIGHT_2, 2s); + break; + } + case EVENT_PRE_FIGHT_2: + me->CastSpell(me, SPELL_FREEZE_ANIM); + me->CastSpell(me, SPELL_EMBERSEER_GROWING); + Talk(EMOTE_ONE_STACK); + break; case EVENT_FIRE_SHIELD: + // #### Spell isn't doing any damage ??? #### DoCast(me, SPELL_FIRE_SHIELD); events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); break; - case EVENT_FIRENOVA: - DoCast(me, SPELL_FIRENOVA); - events.ScheduleEvent(EVENT_FIRENOVA, 6s); + case EVENT_PRE_ENTER_COMBAT_1: + me->RemoveAura(SPELL_ENCAGED_EMBERSEER); + me->RemoveAura(SPELL_FREEZE_ANIM); + me->CastSpell(me, SPELL_EMBERSEER_FULL_STRENGTH); + Talk(EMOTE_FREE_OF_BONDS); break; - case EVENT_FLAMEBUFFET: - DoCast(me, SPELL_FLAMEBUFFET); - events.ScheduleEvent(EVENT_FLAMEBUFFET, 14s); + case EVENT_PRE_ENTER_COMBAT_2: + Talk(YELL_FREE_OF_BONDS); break; - case EVENT_PYROBLAST: - DoCastRandomTarget(SPELL_PYROBLAST, 0, 100.0f); - events.ScheduleEvent(EVENT_PYROBLAST, 15s); + case EVENT_ENTER_COMBAT: + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(false); + DoZoneInCombat(); + // re-enable fire shield + events.ScheduleEvent(EVENT_FIRE_SHIELD, 0s); break; default: break; } } - DoMeleeAttackIfReady(); + return; } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FIRE_SHIELD: + DoCast(me, SPELL_FIRE_SHIELD); + events.ScheduleEvent(EVENT_FIRE_SHIELD, 3s); + break; + case EVENT_FIRENOVA: + DoCast(me, SPELL_FIRENOVA); + events.ScheduleEvent(EVENT_FIRENOVA, 6s); + break; + case EVENT_FLAMEBUFFET: + DoCast(me, SPELL_FLAMEBUFFET); + events.ScheduleEvent(EVENT_FLAMEBUFFET, 14s); + break; + case EVENT_PYROBLAST: + DoCastRandomTarget(SPELL_PYROBLAST, 0, 100.0f); + events.ScheduleEvent(EVENT_PYROBLAST, 15s); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); } }; @@ -321,127 +306,114 @@ enum IncarceratorData EMOTE_FLEE = 0 }; -class npc_blackhand_incarcerator : public CreatureScript +struct npc_blackhand_incarcerator : public ScriptedAI { -public: - npc_blackhand_incarcerator() : CreatureScript("npc_blackhand_incarcerator") { } - - struct npc_blackhand_incarceratorAI : public ScriptedAI + npc_blackhand_incarcerator(Creature* creature) : ScriptedAI(creature) { - npc_blackhand_incarceratorAI(Creature* creature) : ScriptedAI(creature) + _fleedForAssistance = false; + } + + void Reset() override + { + me->SetImmuneToAll(true); + if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) + Emberseer->AI()->SetData(1, 3); + + _fleedForAssistance = false; + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override + { + if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage)) { - _fleedForAssistance = false; + _fleedForAssistance = true; + me->DoFleeToGetAssistance(); + Talk(EMOTE_FLEE); + } + } + + void SetData(uint32 data, uint32 value) override + { + if (data == 1 && value == 1) + { + me->SetImmuneToAll(false); + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + DoZoneInCombat(); + _events.CancelEvent(EVENT_ENCAGED_EMBERSEER); } - void Reset() override + if (data == 1 && value == 2) + _events.ScheduleEvent(EVENT_ENCAGED_EMBERSEER, 1s); + } + + void JustEngagedWith(Unit* /*who*/) override + { + // Used to close doors + if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) + Emberseer->AI()->SetData(1, 2); + + // Had to do this because CallForHelp will ignore any npcs without LOS + std::list creatureList; + GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 60.0f); + for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + if (Creature* creature = *itr) + creature->SetInCombatWithZone(); // AI()->AttackStart(me->GetVictim()); + + _events.ScheduleEvent(EVENT_STRIKE, 8s, 16s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) { - me->SetImmuneToAll(true); - if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) - Emberseer->AI()->SetData(1, 3); - - _fleedForAssistance = false; - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override - { - if (!_fleedForAssistance && me->HealthBelowPctDamaged(30, damage)) - { - _fleedForAssistance = true; - me->DoFleeToGetAssistance(); - Talk(EMOTE_FLEE); - } - } - - void SetData(uint32 data, uint32 value) override - { - if (data == 1 && value == 1) - { - me->SetImmuneToAll(false); - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - DoZoneInCombat(); - _events.CancelEvent(EVENT_ENCAGED_EMBERSEER); - } - - if (data == 1 && value == 2) - _events.ScheduleEvent(EVENT_ENCAGED_EMBERSEER, 1s); - } - - void JustEngagedWith(Unit* /*who*/) override - { - // Used to close doors - if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) - Emberseer->AI()->SetData(1, 2); - - // Had to do this because CallForHelp will ignore any npcs without LOS - std::list creatureList; - GetCreatureListWithEntryInGrid(creatureList, me, NPC_BLACKHAND_INCARCERATOR, 60.0f); - for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) - { - if (Creature* creature = *itr) - creature->SetInCombatWithZone(); // AI()->AttackStart(me->GetVictim()); - } - - _events.ScheduleEvent(EVENT_STRIKE, 8s, 16s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ENCAGED_EMBERSEER: - { - if (me->GetPositionX() == me->GetHomePosition().GetPositionX()) - if (!me->HasAura(SPELL_ENCAGE_EMBERSEER)) - if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) - DoCast(Emberseer, SPELL_ENCAGE_EMBERSEER); - break; - } - } - } - return; - } - _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { - case EVENT_STRIKE: - DoCastVictim(SPELL_STRIKE, true); - _events.ScheduleEvent(EVENT_STRIKE, 14s, 23s); - break; - case EVENT_ENCAGE: - DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), EVENT_ENCAGE, true); - _events.ScheduleEvent(EVENT_ENCAGE, 6s, 12s); - break; - default: - break; + case EVENT_ENCAGED_EMBERSEER: + { + if (me->GetPositionX() == me->GetHomePosition().GetPositionX()) + if (!me->HasAura(SPELL_ENCAGE_EMBERSEER)) + if (Creature* Emberseer = me->FindNearestCreature(NPC_PYROGAURD_EMBERSEER, 30.0f, true)) + DoCast(Emberseer, SPELL_ENCAGE_EMBERSEER); + break; + } } } - - DoMeleeAttackIfReady(); + return; } - private: - EventMap _events; - bool _fleedForAssistance; - }; + _events.Update(diff); - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STRIKE: + DoCastVictim(SPELL_STRIKE, true); + _events.ScheduleEvent(EVENT_STRIKE, 14s, 23s); + break; + case EVENT_ENCAGE: + DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), EVENT_ENCAGE, true); + _events.ScheduleEvent(EVENT_ENCAGE, 6s, 12s); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); } + +private: + EventMap _events; + bool _fleedForAssistance; }; void AddSC_boss_pyroguard_emberseer() { - new boss_pyroguard_emberseer(); - new npc_blackhand_incarcerator(); + RegisterBlackrockSpireCreatureAI(boss_pyroguard_emberseer); + RegisterBlackrockSpireCreatureAI(npc_blackhand_incarcerator); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp index 21145b294..1a1c8f0c6 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp @@ -87,16 +87,12 @@ struct boss_quartermaster_zigris : public BossAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } while (uint32 eventId = events.ExecuteEvent()) { @@ -135,9 +131,7 @@ struct boss_quartermaster_zigris : public BossAI } if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } } DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp index 5e6438422..6a26c7bf2 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp @@ -99,346 +99,327 @@ enum Events EVENT_MORTAL_STRIKE = 32, }; -class boss_rend_blackhand : public CreatureScript +struct boss_rend_blackhand : public BossAI { -public: - boss_rend_blackhand() : CreatureScript("boss_rend_blackhand") { } + boss_rend_blackhand(Creature* creature) : BossAI(creature, DATA_WARCHIEF_REND_BLACKHAND) { } - struct boss_rend_blackhandAI : public BossAI + void Reset() override { - boss_rend_blackhandAI(Creature* creature) : BossAI(creature, DATA_WARCHIEF_REND_BLACKHAND) { } + _Reset(); - void Reset() override + if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) { - _Reset(); - - if (instance->GetBossState(DATA_GYTH) == IN_PROGRESS) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION); - me->SetImmuneToAll(false); - return; - } - - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION); - me->SetImmuneToAll(true); - gythEvent = false; - victorGUID.Clear(); - waveDoorGUID.Clear(); - _currentWave = 0; - - summons.DespawnAll(); - - if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f, true)) - victor->Respawn(true); - - if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) - exitDoor->SetGoState(GO_STATE_ACTIVE); - - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, NOT_STARTED); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION); + me->SetImmuneToAll(false); + return; } - void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PREPARATION); + me->SetImmuneToAll(true); + _gythEvent = false; + _victorGUID.Clear(); + _waveDoorGUID.Clear(); + _currentWave = 0; + + summons.DespawnAll(); + + if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f, true)) + victor->Respawn(true); + + if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) + exitDoor->SetGoState(GO_STATE_ACTIVE); + + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, NOT_STARTED); + } + + void SummonedCreatureDies(Creature* /*creature*/, Unit* /*killer*/) override + { + if (!summons.IsAnyCreatureAlive()) + events.ScheduleEvent(EVENT_WAVES_TEXT_1 + _currentWave, 10s); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + + if (summon->GetEntry() == NPC_GYTH) { - if (!summons.IsAnyCreatureAlive()) - { - events.ScheduleEvent(EVENT_WAVES_TEXT_1 + _currentWave, 10s); - } - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - - if (summon->GetEntry() == NPC_GYTH) - { - me->DespawnOrUnsummon(); - return; - } - - summon->AI()->DoZoneInCombat(nullptr, 100.0f); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 15s); - events.ScheduleEvent(EVENT_CLEAVE, 15s, 17s); - events.ScheduleEvent(EVENT_MORTAL_STRIKE, 17s, 19s); - } - - void EnterEvadeMode(EvadeReason why) override - { - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); - instance->SetBossState(DATA_GYTH, FAIL); - BossAI::EnterEvadeMode(why); me->DespawnOrUnsummon(); + return; } - void IsSummonedBy(WorldObject* /*summoner*/) override + summon->AI()->DoZoneInCombat(nullptr, 100.0f); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 15s); + events.ScheduleEvent(EVENT_CLEAVE, 15s, 17s); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 17s, 19s); + } + + void EnterEvadeMode(EvadeReason why) override + { + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); + instance->SetBossState(DATA_GYTH, FAIL); + BossAI::EnterEvadeMode(why); + me->DespawnOrUnsummon(); + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + Talk(EMOTE_BLACKHAND_DISMOUNT); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true)) + victor->AI()->SetData(1, 2); + + if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) + exitDoor->SetGoState(GO_STATE_ACTIVE); + + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, DONE); + } + + void SummonedCreatureDespawn(Creature* creature) override + { + if (creature->IsAlive() && !summons.IsAnyCreatureInCombat()) + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); + + BossAI::SummonedCreatureDespawn(creature); + } + + void SetData(uint32 type, uint32 data) override + { + if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM) { - Talk(EMOTE_BLACKHAND_DISMOUNT); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 75.0f, true)) - victor->AI()->SetData(1, 2); - - if (GameObject* exitDoor = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) - exitDoor->SetGoState(GO_STATE_ACTIVE); - - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, DONE); - } - - void SummonedCreatureDespawn(Creature* creature) override - { - if (creature->IsAlive() && !summons.IsAnyCreatureInCombat()) + if (!_gythEvent) { - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, FAIL); - } + _gythEvent = true; - BossAI::SummonedCreatureDespawn(creature); - } - - void SetData(uint32 type, uint32 data) override - { - if (type == AREATRIGGER && data == AREATRIGGER_BLACKROCK_STADIUM) - { - if (!gythEvent) + if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f)) { - gythEvent = true; + if (!victor->IsAlive()) + victor->Respawn(true); - if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 5.0f)) - { - if (!victor->IsAlive()) - { - victor->Respawn(true); - } - - victorGUID = victor->GetGUID(); - } - - if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 50.0f)) - waveDoorGUID = portcullis->GetGUID(); - - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - events.ScheduleEvent(EVENT_START_1, 1s); + _victorGUID = victor->GetGUID(); } + + if (GameObject* portcullis = me->FindNearestGameObject(GO_DR_PORTCULLIS, 50.0f)) + _waveDoorGUID = portcullis->GetGUID(); + + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + events.ScheduleEvent(EVENT_START_1, 1s); } } + } - void MovementInform(uint32 type, uint32 id) override + void MovementInform(uint32 type, uint32 id) override + { + if (type == WAYPOINT_MOTION_TYPE) { - if (type == WAYPOINT_MOTION_TYPE) + switch (id) { - switch (id) - { - case 6: - events.ScheduleEvent(EVENT_TELEPORT_1, 2s); - break; - } + case 6: + events.ScheduleEvent(EVENT_TELEPORT_1, 2s); + break; } } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (_gythEvent) { - if (gythEvent) - { - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_START_1: - instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, IN_PROGRESS); - instance->SetData(DATA_VAELASTRASZ, NOT_STARTED); - - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_0); - - if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) - door2->SetGoState(GO_STATE_READY); - - events.ScheduleEvent(EVENT_START_2, 4s); - break; - case EVENT_START_2: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->HandleEmoteCommand(EMOTE_ONESHOT_POINT); - events.ScheduleEvent(EVENT_START_3, 4s); - break; - case EVENT_START_3: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_1); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 2s); - events.ScheduleEvent(EVENT_TURN_TO_REND, 4s); - break; - case EVENT_TURN_TO_REND: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - { - victor->SetFacingToObject(me); - victor->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - } - break; - case EVENT_TURN_TO_PLAYER: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - if (Unit* player = victor->SelectNearestPlayer(60.0f)) - victor->SetFacingToObject(player); - break; - case EVENT_TURN_TO_FACING_1: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->SetFacingTo(1.518436f); - break; - case EVENT_TURN_TO_FACING_2: - me->SetFacingTo(1.658063f); - break; - case EVENT_TURN_TO_FACING_3: - me->SetFacingTo(1.500983f); - break; - case EVENT_WAVES_EMOTE_1: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); - break; - case EVENT_WAVES_EMOTE_2: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - break; - case EVENT_WAVES_TEXT_1: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_2); - me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); - events.ScheduleEvent(EVENT_WAVES_EMOTE_1, 5s); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); - break; - case EVENT_WAVES_TEXT_2: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_3); - events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); - break; - case EVENT_WAVES_TEXT_3: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_4); - events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); - break; - case EVENT_WAVES_TEXT_4: - Talk(SAY_BLACKHAND_1); - events.ScheduleEvent(EVENT_WAVES_EMOTE_2, 4s); - events.ScheduleEvent(EVENT_TURN_TO_FACING_3, 8s); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); - break; - case EVENT_WAVES_TEXT_5: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_5); - events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); - events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); - break; - case EVENT_WAVES_COMPLETE_TEXT_1: - events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_6); - events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); - events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_2, 13s); - break; - case EVENT_WAVES_COMPLETE_TEXT_2: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_7); - Talk(SAY_BLACKHAND_2); - events.ScheduleEvent(EVENT_PATH_REND, 1s); - events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_3, 4s); - break; - case EVENT_WAVES_COMPLETE_TEXT_3: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->AI()->Talk(SAY_NEFARIUS_8); - events.ScheduleEvent(EVENT_PATH_NEFARIUS, 1s); - events.ScheduleEvent(EVENT_PATH_REND, 1s); - break; - case EVENT_PATH_NEFARIUS: - if (Creature* victor = ObjectAccessor::GetCreature(*me, victorGUID)) - victor->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_1, true); - break; - case EVENT_PATH_REND: - me->GetMotionMaster()->MoveWaypoint(REND_PATH_1, false); - break; - case EVENT_TELEPORT_1: - me->NearTeleportTo(194.2993f, -474.0814f, 121.4505f, -0.01225555f); - events.ScheduleEvent(EVENT_TELEPORT_2, 13s); - break; - case EVENT_TELEPORT_2: - me->NearTeleportTo(216.485f, -434.93f, 110.888f, -0.01225555f); - me->SummonCreature(NPC_GYTH, 211.762f, -397.5885f, 111.1817f, 4.747295f); - break; - case EVENT_SPAWN_WAVE: - SummonWave(); - break; - default: - break; - } - } - } - - if (!UpdateVictim()) - return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { - case EVENT_WHIRLWIND: - DoCast(SPELL_WHIRLWIND); - events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 18s); + case EVENT_START_1: + instance->SetBossState(DATA_WARCHIEF_REND_BLACKHAND, IN_PROGRESS); + instance->SetData(DATA_VAELASTRASZ, NOT_STARTED); + + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_0); + + if (GameObject* door2 = me->GetMap()->GetGameObject(instance->GetGuidData(GO_GYTH_ENTRY_DOOR))) + door2->SetGoState(GO_STATE_READY); + + events.ScheduleEvent(EVENT_START_2, 4s); break; - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, 10s, 14s); + case EVENT_START_2: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->HandleEmoteCommand(EMOTE_ONESHOT_POINT); + events.ScheduleEvent(EVENT_START_3, 4s); break; - case EVENT_MORTAL_STRIKE: - DoCastVictim(SPELL_MORTAL_STRIKE); - events.ScheduleEvent(EVENT_MORTAL_STRIKE, 14s, 18s); + case EVENT_START_3: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_1); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 2s); + events.ScheduleEvent(EVENT_TURN_TO_REND, 4s); + break; + case EVENT_TURN_TO_REND: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + { + victor->SetFacingToObject(me); + victor->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + } + break; + case EVENT_TURN_TO_PLAYER: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + if (Unit* player = victor->SelectNearestPlayer(60.0f)) + victor->SetFacingToObject(player); + break; + case EVENT_TURN_TO_FACING_1: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->SetFacingTo(1.518436f); + break; + case EVENT_TURN_TO_FACING_2: + me->SetFacingTo(1.658063f); + break; + case EVENT_TURN_TO_FACING_3: + me->SetFacingTo(1.500983f); + break; + case EVENT_WAVES_EMOTE_1: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); + break; + case EVENT_WAVES_EMOTE_2: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + break; + case EVENT_WAVES_TEXT_1: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_2); + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); + events.ScheduleEvent(EVENT_WAVES_EMOTE_1, 5s); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); + break; + case EVENT_WAVES_TEXT_2: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_3); + events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); + break; + case EVENT_WAVES_TEXT_3: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_4); + events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); + break; + case EVENT_WAVES_TEXT_4: + Talk(SAY_BLACKHAND_1); + events.ScheduleEvent(EVENT_WAVES_EMOTE_2, 4s); + events.ScheduleEvent(EVENT_TURN_TO_FACING_3, 8s); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); + break; + case EVENT_WAVES_TEXT_5: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_5); + events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); + events.ScheduleEvent(EVENT_SPAWN_WAVE, 3s); + break; + case EVENT_WAVES_COMPLETE_TEXT_1: + events.ScheduleEvent(EVENT_TURN_TO_PLAYER, 0ms); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_6); + events.ScheduleEvent(EVENT_TURN_TO_FACING_1, 4s); + events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_2, 13s); + break; + case EVENT_WAVES_COMPLETE_TEXT_2: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_7); + Talk(SAY_BLACKHAND_2); + events.ScheduleEvent(EVENT_PATH_REND, 1s); + events.ScheduleEvent(EVENT_WAVES_COMPLETE_TEXT_3, 4s); + break; + case EVENT_WAVES_COMPLETE_TEXT_3: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->AI()->Talk(SAY_NEFARIUS_8); + events.ScheduleEvent(EVENT_PATH_NEFARIUS, 1s); + events.ScheduleEvent(EVENT_PATH_REND, 1s); + break; + case EVENT_PATH_NEFARIUS: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + victor->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_1, true); + break; + case EVENT_PATH_REND: + me->GetMotionMaster()->MoveWaypoint(REND_PATH_1, false); + break; + case EVENT_TELEPORT_1: + me->NearTeleportTo(194.2993f, -474.0814f, 121.4505f, -0.01225555f); + events.ScheduleEvent(EVENT_TELEPORT_2, 13s); + break; + case EVENT_TELEPORT_2: + me->NearTeleportTo(216.485f, -434.93f, 110.888f, -0.01225555f); + me->SummonCreature(NPC_GYTH, 211.762f, -397.5885f, 111.1817f, 4.747295f); + break; + case EVENT_SPAWN_WAVE: + SummonWave(); + break; + default: break; } } - DoMeleeAttackIfReady(); } - void SummonWave() + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - me->SummonCreatureGroup(_currentWave); - - if (GameObject* waveDoor = me->GetMap()->GetGameObject(waveDoorGUID)) + switch (eventId) { - waveDoor->UseDoorOrButton(); + case EVENT_WHIRLWIND: + DoCast(SPELL_WHIRLWIND); + events.ScheduleEvent(EVENT_WHIRLWIND, 13s, 18s); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 10s, 14s); + break; + case EVENT_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTAL_STRIKE); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 14s, 18s); + break; } - - ++_currentWave; } - - private: - bool gythEvent; - uint8 _currentWave; - ObjectGuid victorGUID; - ObjectGuid waveDoorGUID; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + DoMeleeAttackIfReady(); } + + void SummonWave() + { + me->SummonCreatureGroup(_currentWave); + + if (GameObject* waveDoor = me->GetMap()->GetGameObject(_waveDoorGUID)) + waveDoor->UseDoorOrButton(); + + ++_currentWave; + } + +private: + bool _gythEvent; + uint8 _currentWave; + ObjectGuid _victorGUID; + ObjectGuid _waveDoorGUID; }; void AddSC_boss_rend_blackhand() { - new boss_rend_blackhand(); + RegisterBlackrockSpireCreatureAI(boss_rend_blackhand); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp index d96758ee7..4964a8ff3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_solakar_flamewreath.cpp @@ -38,211 +38,178 @@ enum Says SAY_SUMMON = 0, }; -class npc_rookery_hatcher : public CreatureScript +struct npc_rookery_hatcher : public CreatureAI { -public: - npc_rookery_hatcher() : CreatureScript("npc_rookery_hatcher") {} + npc_rookery_hatcher(Creature* creature) : CreatureAI(creature) {} - CreatureAI* GetAI(Creature* creature) const override + EventMap events; + GameObject* targetEgg; + Position targetPosition; + + void InitializeAI() override { - return GetBlackrockSpireAI(creature); + CreatureAI::InitializeAI(); + DoZoneInCombat(nullptr, 100.0f); + targetEgg = nullptr; } - struct npc_rookery_hatcherAI : public CreatureAI + void JustEngagedWith(Unit* /*who*/) override { - npc_rookery_hatcherAI(Creature* creature) : CreatureAI(creature) {} + events.ScheduleEvent(SPELL_HATCH_EGG, 1s); + } - EventMap events; + void UpdateAI(uint32 diff) override + { std::list nearbyEggs; - GameObject* targetEgg; - Position targetPosition; + float tempDist = 20; + float minDist = 25; + std::list nearbyWhelps; - void InitializeAI() override + if (!UpdateVictim()) + return; + + GetCreatureListWithEntryInGrid(nearbyWhelps, me, NPC_ROOKERY_WHELP, RANGE_WHELP_CALL_HELP); + for (auto const& whelp : nearbyWhelps) { - CreatureAI::InitializeAI(); - DoZoneInCombat(nullptr, 100.0f); - nearbyEggs.clear(); - targetEgg = nullptr; - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(SPELL_HATCH_EGG, 1s); - } - - void UpdateAI(uint32 diff) override - { - std::list nearbyEggs; - float tempDist = 20; - float minDist = 25; - std::list nearbyWhelps; - - if (!UpdateVictim()) + if (!whelp->IsInCombat()) { - return; + whelp->SetInCombatWith(me->GetVictim()); + whelp->AI()->AttackStart(me->GetVictim()); } - - GetCreatureListWithEntryInGrid(nearbyWhelps, me, NPC_ROOKERY_WHELP, RANGE_WHELP_CALL_HELP); - for (auto const& whelp : nearbyWhelps) - { - if (!whelp->IsInCombat()) - { - whelp->SetInCombatWith(me->GetVictim()); - whelp->AI()->AttackStart(me->GetVictim()); - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_HATCH_EGG: - if (!targetEgg) // no target, try to find one - { - minDist = 50; - tempDist = 50; - me->GetGameObjectListWithEntryInGrid(nearbyEggs, GO_ROOKERY_EGG, 40); - for (auto const& egg : nearbyEggs) - { - if (egg->isSpawned() && egg->getLootState() == GO_READY) - { - tempDist = me->GetDistance2d(egg); - if (tempDist < minDist) - { - minDist = tempDist; - targetEgg = egg; - } - } - } - } - - if (targetEgg) //have a target, go to it and cast it - { - me->GetMotionMaster()->MovePoint(0, targetEgg->GetPosition()); - } - break; - default: - break; - } - } - - // cast takes 1.5second, during which we don't have a target - if (targetEgg && targetEgg->getLootState() == GO_READY && me->GetDistance2d(targetEgg) < RANGE_SPELL_HATCH_EGG) - { - me->StopMovingOnCurrentPos(); - me->SetFacingToObject(targetEgg); - targetPosition = me->GetPosition(); - DoCast(SPELL_HATCH_EGG); - targetEgg = nullptr; - events.ScheduleEvent(SPELL_HATCH_EGG, 6s, 8s); - } - else if (!me->HasUnitState(UNIT_STATE_CASTING) && !targetEgg) - { - if (Unit* victim = me->GetVictim()) - { - AttackStart(victim); - } - - if (me->GetDistance2d(me->GetVictim()) > me->GetMeleeReach()) - { - me->GetMotionMaster()->MovePoint(0, me->GetVictim()->GetPosition()); // a bit hacky, but needed to start moving once we've summoned an egg - } - } - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_solakar_flamewreath : public CreatureScript -{ -public: - boss_solakar_flamewreath() : CreatureScript("boss_solakar_flamewreath") { } - - struct boss_solakar_flamewreathAI : public BossAI - { - boss_solakar_flamewreathAI(Creature* creature) : BossAI(creature, DATA_SOLAKAR_FLAMEWREATH) {} - - uint32 resetTimer; - - void Reset() override - { - _Reset(); - resetTimer = 10000; } - void InitializeAI() override - { - BossAI::InitializeAI(); - Talk(SAY_SUMMON); - DoZoneInCombat(nullptr, 100.0f); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + events.Update(diff); - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s); - resetTimer = 0; - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - instance->SetData(DATA_SOLAKAR_FLAMEWREATH, DONE); - } - - void ExecuteEvent(uint32 eventId) override + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { - case SPELL_WAR_STOMP: - DoCastVictim(SPELL_WAR_STOMP); - events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s); - break; + case SPELL_HATCH_EGG: + if (!targetEgg) // no target, try to find one + { + minDist = 50; + tempDist = 50; + me->GetGameObjectListWithEntryInGrid(nearbyEggs, GO_ROOKERY_EGG, 40); + for (auto const& egg : nearbyEggs) + { + if (egg->isSpawned() && egg->getLootState() == GO_READY) + { + tempDist = me->GetDistance2d(egg); + if (tempDist < minDist) + { + minDist = tempDist; + targetEgg = egg; + } + } + } + } + if (targetEgg) //have a target, go to it and cast it + me->GetMotionMaster()->MovePoint(0, targetEgg->GetPosition()); + break; default: break; } } - void UpdateAI(uint32 diff) override + // cast takes 1.5second, during which we don't have a target + if (targetEgg && targetEgg->getLootState() == GO_READY && me->GetDistance2d(targetEgg) < RANGE_SPELL_HATCH_EGG) { - if (!UpdateVictim()) - { - resetTimer -= diff; - if (resetTimer < diff) - { - instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL); - } - return; - } - resetTimer = 10000; - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - while (uint32 eventId = events.ExecuteEvent()) - { - ExecuteEvent(eventId); - } - - DoMeleeAttackIfReady(); + me->StopMovingOnCurrentPos(); + me->SetFacingToObject(targetEgg); + targetPosition = me->GetPosition(); + DoCast(SPELL_HATCH_EGG); + targetEgg = nullptr; + events.ScheduleEvent(SPELL_HATCH_EGG, 6s, 8s); } - }; + else if (!me->HasUnitState(UNIT_STATE_CASTING) && !targetEgg) + { + if (Unit* victim = me->GetVictim()) + AttackStart(victim); - CreatureAI* GetAI(Creature* creature) const override + if (me->GetDistance2d(me->GetVictim()) > me->GetMeleeReach()) + me->GetMotionMaster()->MovePoint(0, me->GetVictim()->GetPosition()); // a bit hacky, but needed to start moving once we've summoned an egg + } + DoMeleeAttackIfReady(); + } +}; + +struct boss_solakar_flamewreath : public BossAI +{ + boss_solakar_flamewreath(Creature* creature) : BossAI(creature, DATA_SOLAKAR_FLAMEWREATH) {} + + uint32 resetTimer; + + void Reset() override { - return GetBlackrockSpireAI(creature); + _Reset(); + resetTimer = 10000; + } + + void InitializeAI() override + { + BossAI::InitializeAI(); + Talk(SAY_SUMMON); + DoZoneInCombat(nullptr, 100.0f); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s); + resetTimer = 0; + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SetData(DATA_SOLAKAR_FLAMEWREATH, DONE); + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case SPELL_WAR_STOMP: + DoCastVictim(SPELL_WAR_STOMP); + events.ScheduleEvent(SPELL_WAR_STOMP, 17s, 20s); + break; + + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + if (resetTimer <= diff) + { + instance->SetData(DATA_SOLAKAR_FLAMEWREATH, FAIL); + return; + } + resetTimer -= diff; + return; + } + resetTimer = 10000; + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + while (uint32 eventId = events.ExecuteEvent()) + { + ExecuteEvent(eventId); + } + + DoMeleeAttackIfReady(); } }; void AddSC_boss_solakar_flamewreath() { - new boss_solakar_flamewreath(); - new npc_rookery_hatcher(); + RegisterBlackrockSpireCreatureAI(boss_solakar_flamewreath); + RegisterBlackrockSpireCreatureAI(npc_rookery_hatcher); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp index 366fb17b7..37d773328 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp @@ -90,185 +90,152 @@ private: // Used to make Hodir disengage whenever he leaves his room constexpr static float FirewalPositionY = -505.f; -class boss_the_beast : public CreatureScript +struct boss_the_beast : public BossAI { -public: - boss_the_beast() : CreatureScript("boss_the_beast") { } + boss_the_beast(Creature* creature) : BossAI(creature, DATA_THE_BEAST), _beastReached(false), _orcYelled(false) {} - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetBlackrockSpireAI(creature); + _Reset(); + + if (_beastReached) + me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true); } - struct boss_thebeastAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_thebeastAI(Creature* creature) : BossAI(creature, DATA_THE_BEAST), _beastReached(false), _orcYelled(false) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_FLAME_BREAK, 12s); + events.ScheduleEvent(EVENT_IMMOLATE, 3s); + events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 23s); + events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 2s); + events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s); + events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s); + } - void Reset() override + void SetData(uint32 type, uint32 /*data*/) override + { + switch (type) { - _Reset(); - - if (_beastReached) + case DATA_BEAST_ROOM: { - me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_FLAME_BREAK, 12s); - events.ScheduleEvent(EVENT_IMMOLATE, 3s); - events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 23s); - events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 2s); - events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s); - events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s); - } - - void SetData(uint32 type, uint32 /*data*/) override - { - switch (type) - { - case DATA_BEAST_ROOM: + if (!_orcYelled) { - if (!_orcYelled) + if (_nearbyOrcsGUIDs.empty()) + FindNearbyOrcs(); + + //! vector still empty, creatures are missing + if (_nearbyOrcsGUIDs.empty()) + return; + + _orcYelled = true; + + bool yelled = false; + for (ObjectGuid guid : _nearbyOrcsGUIDs) { - if (_nearbyOrcsGUIDs.empty()) + if (Creature* orc = ObjectAccessor::GetCreature(*me, guid)) { - FindNearbyOrcs(); - } - - //! vector still empty, creatures are missing - if (_nearbyOrcsGUIDs.empty()) - { - return; - } - - _orcYelled = true; - - bool yelled = false; - for (ObjectGuid guid : _nearbyOrcsGUIDs) - { - if (Creature* orc = ObjectAccessor::GetCreature(*me, guid)) + if (!yelled) { - if (!yelled) - { - yelled = true; - orc->AI()->Talk(SAY_BLACKHAND_DOOMED); - } - - orc->m_Events.AddEventAtOffset(new OrcMoveEvent(orc), 3s); - orc->m_Events.AddEventAtOffset(new OrcDeathEvent(orc), 9s); + yelled = true; + orc->AI()->Talk(SAY_BLACKHAND_DOOMED); } + + orc->m_Events.AddEventAtOffset(new OrcMoveEvent(orc), 3s); + orc->m_Events.AddEventAtOffset(new OrcDeathEvent(orc), 9s); } } - break; } - case DATA_BEAST_REACHED: + break; + } + case DATA_BEAST_REACHED: + { + if (!_beastReached) { - if (!_beastReached) - { - _beastReached = true; - me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true); + _beastReached = true; + me->GetMotionMaster()->MoveWaypoint(BEAST_MOVEMENT_ID, true); - // There is a chance player logged in between areatriggers (realm crash or restart) - // executing part of script which happens when player enters boss room - // otherwise we will see weird behaviour when someone steps on the previous areatrigger (dead mob yelling/moving) - SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM); - } - break; + // There is a chance player logged in between areatriggers (realm crash or restart) + // executing part of script which happens when player enters boss room + // otherwise we will see weird behaviour when someone steps on the previous areatrigger (dead mob yelling/moving) + SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM); } + break; } } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->GetPositionY() > FirewalPositionY) { - if (!UpdateVictim()) - { - return; - } + EnterEvadeMode(); + return; + } - if (me->GetPositionY() > FirewalPositionY) - { - EnterEvadeMode(); - return; - } + events.Update(diff); - events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FLAME_BREAK: + DoCastVictim(SPELL_FLAMEBREAK); + events.ScheduleEvent(EVENT_FLAME_BREAK, 10s); + break; + case EVENT_IMMOLATE: + DoCastRandomTarget(SPELL_IMMOLATE, 0, 100.0f); + events.ScheduleEvent(EVENT_IMMOLATE, 8s); + break; + case EVENT_TERRIFYING_ROAR: + DoCastVictim(SPELL_TERRIFYINGROAR); + events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 20s); + break; + case EVENT_BERSERKER_CHARGE: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 38.f, true)) + DoCast(target, SPELL_BERSERKER_CHARGE); + events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 15s, 23s); + break; + case EVENT_FIREBALL: + DoCastVictim(SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s); + if (events.GetTimeUntilEvent(EVENT_FIREBLAST) < 3s) + events.RescheduleEvent(EVENT_FIREBLAST, 3s); + break; + case EVENT_FIREBLAST: + DoCastVictim(SPELL_FIREBLAST); + events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s); + if (events.GetTimeUntilEvent(EVENT_FIREBALL) < 3s) + events.RescheduleEvent(EVENT_FIREBALL, 3s); + break; + } if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FLAME_BREAK: - DoCastVictim(SPELL_FLAMEBREAK); - events.ScheduleEvent(EVENT_FLAME_BREAK, 10s); - break; - case EVENT_IMMOLATE: - DoCastRandomTarget(SPELL_IMMOLATE, 0, 100.0f); - events.ScheduleEvent(EVENT_IMMOLATE, 8s); - break; - case EVENT_TERRIFYING_ROAR: - DoCastVictim(SPELL_TERRIFYINGROAR); - events.ScheduleEvent(EVENT_TERRIFYING_ROAR, 20s); - break; - case EVENT_BERSERKER_CHARGE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 38.f, true)) - { - DoCast(target, SPELL_BERSERKER_CHARGE); - } - events.ScheduleEvent(EVENT_BERSERKER_CHARGE, 15s, 23s); - break; - case EVENT_FIREBALL: - DoCastVictim(SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 8s, 21s); - if (events.GetTimeUntilEvent(EVENT_FIREBLAST) < 3s) - { - events.RescheduleEvent(EVENT_FIREBLAST, 3s); - } - break; - case EVENT_FIREBLAST: - DoCastVictim(SPELL_FIREBLAST); - events.ScheduleEvent(EVENT_FIREBLAST, 5s, 8s); - if (events.GetTimeUntilEvent(EVENT_FIREBALL) < 3s) - { - events.RescheduleEvent(EVENT_FIREBALL, 3s); - } - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - } - - DoMeleeAttackIfReady(); } - void FindNearbyOrcs() - { - std::list temp; - me->GetCreatureListWithEntryInGrid(temp, NPC_BLACKHAND_ELITE, 50.0f); - for (Creature* creature : temp) - { - if (creature->IsAlive()) - { - _nearbyOrcsGUIDs.push_back(creature->GetGUID()); - } - } - } + DoMeleeAttackIfReady(); + } - private: - bool _beastReached; - bool _orcYelled; - GuidVector _nearbyOrcsGUIDs; - }; + void FindNearbyOrcs() + { + std::list temp; + me->GetCreatureListWithEntryInGrid(temp, NPC_BLACKHAND_ELITE, 50.0f); + for (Creature* creature : temp) + if (creature->IsAlive()) + _nearbyOrcsGUIDs.push_back(creature->GetGUID()); + } + +private: + bool _beastReached; + bool _orcYelled; + GuidVector _nearbyOrcsGUIDs; }; //! The beast room areatrigger, this one triggers boss pathing. (AT Id 2066) @@ -280,16 +247,12 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override { if (player->IsGameMaster()) - { return false; - } if (InstanceScript* instance = player->GetInstanceScript()) { if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST))) - { beast->AI()->SetData(DATA_BEAST_REACHED, DATA_BEAST_REACHED); - } return true; } @@ -306,16 +269,12 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override { if (player->IsGameMaster()) - { return false; - } if (InstanceScript* instance = player->GetInstanceScript()) { if (Creature* beast = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THE_BEAST))) - { beast->AI()->SetData(DATA_BEAST_ROOM, DATA_BEAST_ROOM); - } return true; } @@ -326,7 +285,7 @@ public: void AddSC_boss_thebeast() { - new boss_the_beast(); + RegisterBlackrockSpireCreatureAI(boss_the_beast); new at_trigger_the_beast_movement(); new at_the_beast_room(); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp index bdebc9ff9..ff9b0f2a0 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp @@ -40,82 +40,67 @@ enum Events EVENT_INTIMIDATING_ROAR = 3 }; -class boss_urok_doomhowl : public CreatureScript +struct boss_urok_doomhowl : public BossAI { -public: - boss_urok_doomhowl() : CreatureScript("boss_urok_doomhowl") { } + boss_urok_doomhowl(Creature* creature) : BossAI(creature, DATA_UROK_DOOMHOWL) {} - struct boss_urok_doomhowlAI : public BossAI + void InitializeAI() override { - boss_urok_doomhowlAI(Creature* creature) : BossAI(creature, DATA_UROK_DOOMHOWL) {} + me->CastSpell(me, SPELL_UROK_SPAWN, true); + BossAI::InitializeAI(); + Talk(SAY_SUMMON); + DoZoneInCombat(nullptr, 100.0f); - void InitializeAI() override - { - me->CastSpell(me, SPELL_UROK_SPAWN, true); - BossAI::InitializeAI(); - Talk(SAY_SUMMON); - DoZoneInCombat(nullptr, 100.0f); + if (GameObject* challenge = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_CHALLENGE))) + challenge->Delete(); - if (GameObject* challenge = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_CHALLENGE))) - { - challenge->Delete(); - } + if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE))) + pile->DespawnOrUnsummon(0ms, Seconds(MONTH)); + } - if (GameObject* pile = instance->instance->GetGameObject(instance->GetGuidData(GO_UROK_PILE))) - { - pile->DespawnOrUnsummon(0ms, Seconds(MONTH)); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(SPELL_REND, 17s, 20s); - events.ScheduleEvent(SPELL_STRIKE, 10s, 12s); - events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 25s, 30s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case SPELL_REND: - DoCastVictim(SPELL_REND); - events.ScheduleEvent(SPELL_REND, 8s, 10s); - break; - case SPELL_STRIKE: - DoCastVictim(SPELL_STRIKE); - events.ScheduleEvent(SPELL_STRIKE, 8s, 10s); - break; - case SPELL_INTIMIDATING_ROAR: - DoCastVictim(SPELL_INTIMIDATING_ROAR); - events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 40s, 45s); - break; - default: - break; - } - } - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetBlackrockSpireAI(creature); + _JustEngagedWith(); + events.ScheduleEvent(SPELL_REND, 17s, 20s); + events.ScheduleEvent(SPELL_STRIKE, 10s, 12s); + events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 25s, 30s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case SPELL_REND: + DoCastVictim(SPELL_REND); + events.ScheduleEvent(SPELL_REND, 8s, 10s); + break; + case SPELL_STRIKE: + DoCastVictim(SPELL_STRIKE); + events.ScheduleEvent(SPELL_STRIKE, 8s, 10s); + break; + case SPELL_INTIMIDATING_ROAR: + DoCastVictim(SPELL_INTIMIDATING_ROAR); + events.ScheduleEvent(SPELL_INTIMIDATING_ROAR, 40s, 45s); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); } }; void AddSC_boss_urok_doomhowl() { - new boss_urok_doomhowl(); + RegisterBlackrockSpireCreatureAI(boss_urok_doomhowl); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp index 3240cadd2..339944fd3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp @@ -55,86 +55,75 @@ enum EventGroups GROUP_WARMASTER }; -class boss_warmaster_voone : public CreatureScript +struct boss_warmaster_voone : public BossAI { -public: - boss_warmaster_voone() : CreatureScript("boss_warmaster_voone") { } + boss_warmaster_voone(Creature* creature) : BossAI(creature, DATA_WARMASTER_VOONE) { } - struct boss_warmastervooneAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_warmastervooneAI(Creature* creature) : BossAI(creature, DATA_WARMASTER_VOONE) { } + _JustEngagedWith(); - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); + events.SetPhase(PHASE_BRAWLER); + events.ScheduleEvent(EVENT_THRASH, 3s, GROUP_BRAWLER, PHASE_BRAWLER); + events.ScheduleEvent(EVENT_THROW_AXE, 1s, GROUP_BRAWLER, PHASE_BRAWLER); + } - events.SetPhase(PHASE_BRAWLER); - events.ScheduleEvent(EVENT_THRASH, 3s, GROUP_BRAWLER, PHASE_BRAWLER); - events.ScheduleEvent(EVENT_THROW_AXE, 1s, GROUP_BRAWLER, PHASE_BRAWLER); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override - { - if (me->HealthBelowPctDamaged(65, damage) && events.IsInPhase(PHASE_BRAWLER)) - { - events.SetPhase(PHASE_THRASHER); - events.CancelEventGroup(GROUP_BRAWLER); - events.ScheduleEvent(EVENT_CLEAVE, 14s, GROUP_THRASHER, PHASE_THRASHER); - events.ScheduleEvent(EVENT_MORTAL_STRIKE, 12s, GROUP_THRASHER, PHASE_THRASHER); - } - else if (me->HealthBelowPctDamaged(40, damage) && events.IsInPhase(PHASE_THRASHER)) - { - events.SetPhase(PHASE_WARMASTER); - events.CancelEventGroup(GROUP_THRASHER); - events.ScheduleEvent(EVENT_SNAP_KICK, 8s, GROUP_WARMASTER, PHASE_WARMASTER); - events.ScheduleEvent(EVENT_UPPERCUT, 20s, GROUP_WARMASTER, PHASE_WARMASTER); - events.ScheduleEvent(EVENT_PUMMEL, 32s, GROUP_WARMASTER, PHASE_WARMASTER); - } - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_SNAP_KICK: - DoCastVictim(SPELL_SNAPKICK); - events.Repeat(6s); - break; - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.Repeat(12s); - break; - case EVENT_UPPERCUT: - DoCastVictim(SPELL_UPPERCUT); - events.Repeat(14s); - break; - case EVENT_MORTAL_STRIKE: - DoCastVictim(SPELL_MORTALSTRIKE); - events.Repeat(10s); - break; - case EVENT_PUMMEL: - DoCastVictim(SPELL_PUMMEL); - events.Repeat(16s); - break; - case EVENT_THROW_AXE: - DoCastRandomTarget(SPELL_THROWAXE); - events.Repeat(8s); - break; - case EVENT_THRASH: - DoCastSelf(SPELL_THRASH); - events.Repeat(10s); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override { - return GetBlackrockSpireAI(creature); + if (me->HealthBelowPctDamaged(65, damage) && events.IsInPhase(PHASE_BRAWLER)) + { + events.SetPhase(PHASE_THRASHER); + events.CancelEventGroup(GROUP_BRAWLER); + events.ScheduleEvent(EVENT_CLEAVE, 14s, GROUP_THRASHER, PHASE_THRASHER); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 12s, GROUP_THRASHER, PHASE_THRASHER); + } + else if (me->HealthBelowPctDamaged(40, damage) && events.IsInPhase(PHASE_THRASHER)) + { + events.SetPhase(PHASE_WARMASTER); + events.CancelEventGroup(GROUP_THRASHER); + events.ScheduleEvent(EVENT_SNAP_KICK, 8s, GROUP_WARMASTER, PHASE_WARMASTER); + events.ScheduleEvent(EVENT_UPPERCUT, 20s, GROUP_WARMASTER, PHASE_WARMASTER); + events.ScheduleEvent(EVENT_PUMMEL, 32s, GROUP_WARMASTER, PHASE_WARMASTER); + } + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_SNAP_KICK: + DoCastVictim(SPELL_SNAPKICK); + events.Repeat(6s); + break; + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.Repeat(12s); + break; + case EVENT_UPPERCUT: + DoCastVictim(SPELL_UPPERCUT); + events.Repeat(14s); + break; + case EVENT_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTALSTRIKE); + events.Repeat(10s); + break; + case EVENT_PUMMEL: + DoCastVictim(SPELL_PUMMEL); + events.Repeat(16s); + break; + case EVENT_THROW_AXE: + DoCastRandomTarget(SPELL_THROWAXE); + events.Repeat(8s); + break; + case EVENT_THRASH: + DoCastSelf(SPELL_THRASH); + events.Repeat(10s); + break; + } } }; void AddSC_boss_warmastervoone() { - new boss_warmaster_voone(); + RegisterBlackrockSpireCreatureAI(boss_warmaster_voone); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp index dc7cf3d41..62beba867 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp @@ -19,6 +19,7 @@ #include "Cell.h" #include "CellImpl.h" #include "CreatureScript.h" +#include "GameObjectAI.h" #include "GameObjectScript.h" #include "GridNotifiers.h" #include "InstanceMapScript.h" @@ -71,506 +72,534 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM, } // END }; -class instance_blackrock_spire : public InstanceMapScript +struct instance_blackrock_spire : public InstanceScript { -public: - instance_blackrock_spire() : InstanceMapScript(BRSScriptName, MAP_BLACKROCK_SPIRE) { } + uint32 CurrentSolakarWave = 0; + uint32 SolakarState = NOT_STARTED; // there should be a global instance encounter state, where is it? + GuidVector SolakarSummons; + uint32 VaelastraszState = NOT_STARTED; - struct instance_blackrock_spireMapScript : public InstanceScript + instance_blackrock_spire(InstanceMap* map) : InstanceScript(map) { - uint32 CurrentSolakarWave = 0; - uint32 SolakarState = NOT_STARTED; // there should be a global instance encounter state, where is it? - GuidVector SolakarSummons; - uint32 VaelastraszState = NOT_STARTED; + SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadMinionData(minionData); + LoadDoorData(doorData); + CurrentSolakarWave = 0; + SolakarState = NOT_STARTED; + SolakarSummons.clear(); + VaelastraszState = NOT_STARTED; + } - instance_blackrock_spireMapScript(InstanceMap* map) : InstanceScript(map) + void CreatureLooted(Creature* creature, LootType loot) override + { + switch (creature->GetEntry()) { - SetHeaders(DataHeader); - SetBossNumber(EncounterCount); - LoadMinionData(minionData); - LoadDoorData(doorData); - CurrentSolakarWave = 0; - SolakarState = NOT_STARTED; - SolakarSummons.clear(); - VaelastraszState = NOT_STARTED; + case NPC_THE_BEAST: + if (loot == LOOT_SKINNING) + creature->CastSpell(creature, SPELL_FINKLE_IS_EINHORN, true); + break; + } + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_UROK_MAGUS: + [[fallthrough]]; + case NPC_UROK_ENFORCER: + UrokMobs.push_back(creature->GetGUID()); + break; + case NPC_HIGHLORD_OMOKK: + HighlordOmokk = creature->GetGUID(); + break; + case NPC_SHADOW_HUNTER_VOSHGAJIN: + ShadowHunterVoshgajin = creature->GetGUID(); + break; + case NPC_WARMASTER_VOONE: + WarMasterVoone = creature->GetGUID(); + break; + case NPC_MOTHER_SMOLDERWEB: + MotherSmolderweb = creature->GetGUID(); + break; + case NPC_UROK_DOOMHOWL: + UrokDoomhowl = creature->GetGUID(); + break; + case NPC_QUARTERMASTER_ZIGRIS: + QuartermasterZigris = creature->GetGUID(); + break; + case NPC_GIZRUL_THE_SLAVENER: + GizrultheSlavener = creature->GetGUID(); + break; + case NPC_HALYCON: + Halycon = creature->GetGUID(); + break; + case NPC_OVERLORD_WYRMTHALAK: + OverlordWyrmthalak = creature->GetGUID(); + break; + case NPC_PYROGAURD_EMBERSEER: + PyroguardEmberseer = creature->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + creature->DisappearAndDie(); + break; + case NPC_WARCHIEF_REND_BLACKHAND: + if (GetBossState(DATA_GYTH) != IN_PROGRESS) + WarchiefRendBlackhand = creature->GetGUID(); + + if (GetBossState(DATA_GYTH) == DONE) + creature->DisappearAndDie(); + break; + case NPC_GYTH: + Gyth = creature->GetGUID(); + break; + case NPC_THE_BEAST: + TheBeast = creature->GetGUID(); + break; + case NPC_GENERAL_DRAKKISATH: + GeneralDrakkisath = creature->GetGUID(); + break; + case NPC_LORD_VICTOR_NEFARIUS: + LordVictorNefarius = creature->GetGUID(); + if (GetBossState(DATA_GYTH) == DONE) + creature->DisappearAndDie(); + break; + case NPC_FINKLE_EINHORN: + creature->AI()->Talk(SAY_FINKLE_GANG); + break; + case NPC_CHROMATIC_ELITE_GUARD: + AddMinion(creature); + break; + } + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_EMBERSEER_IN: + go_emberseerin = go->GetGUID(); + HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE, go); + break; + case GO_DOORS: + go_doors = go->GetGUID(); + if (GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE) + HandleGameObject(ObjectGuid::Empty, true, go); + break; + case GO_EMBERSEER_OUT: + go_emberseerout = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, true, go); + break; + case GO_HALL_RUNE_1: + go_roomrunes[0] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_1) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_2: + go_roomrunes[1] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_2) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_3: + go_roomrunes[2] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_3) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_4: + go_roomrunes[3] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_4) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_5: + go_roomrunes[4] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_5) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_6: + go_roomrunes[5] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_6) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_HALL_RUNE_7: + go_roomrunes[6] = go->GetGUID(); + if (GetBossState(DATA_HALL_RUNE_7) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_1: + go_emberseerrunes[0] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_2: + go_emberseerrunes[1] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_3: + go_emberseerrunes[2] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_4: + go_emberseerrunes[3] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_5: + go_emberseerrunes[4] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_6: + go_emberseerrunes[5] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_EMBERSEER_RUNE_7: + go_emberseerrunes[6] = go->GetGUID(); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) + HandleGameObject(ObjectGuid::Empty, false, go); + break; + case GO_PORTCULLIS_ACTIVE: + go_portcullis_active = go->GetGUID(); + if (GetBossState(DATA_GYTH) == DONE) + HandleGameObject(ObjectGuid::Empty, true, go); + break; + case GO_UROK_PILE: + go_urokPile = go->GetGUID(); + break; + case GO_UROK_CIRCLE: + go_urokOgreCirles.push_back(go->GetGUID()); + break; + case GO_UROK_CHALLENGE: + go_urokChallenge = go->GetGUID(); + break; + default: + break; } - void CreatureLooted(Creature* creature, LootType loot) override + InstanceScript::OnGameObjectCreate(go); + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) { - switch (creature->GetEntry()) - { - case NPC_THE_BEAST: - if (loot == LOOT_SKINNING) + case DATA_WARCHIEF_REND_BLACKHAND: + if (state == FAIL) + { + if (Creature* rend = instance->GetCreature(WarchiefRendBlackhand)) + rend->Respawn(true); + + if (Creature* nefarius = instance->GetCreature(LordVictorNefarius)) + nefarius->AI()->Talk(SAY_NEFARIUS_REND_WIPE); + } + break; + default: + break; + } + + return true; + } + + void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override + { + switch (eventId) + { + case EVENT_PYROGUARD_EMBERSEER: + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == NOT_STARTED) + if (Creature* Emberseer = instance->GetCreature(PyroguardEmberseer)) + Emberseer->AI()->SetData(1, 1); + break; + case EVENT_UROK_DOOMHOWL: + if (GetBossState(DATA_UROK_DOOMHOWL) == NOT_STARTED) + { + SetBossState(DATA_UROK_DOOMHOWL, IN_PROGRESS); + if (GameObject* pile = instance->GetGameObject(go_urokPile)) + pile->SetLootState(GO_JUST_DEACTIVATED); + } + break; + default: + break; + } + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case AREATRIGGER: + if (data == AREATRIGGER_DRAGONSPIRE_HALL) + { + if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE) + Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_STORE, 1s); + } + break; + case DATA_SOLAKAR_FLAMEWREATH: + switch (data) + { + case IN_PROGRESS: + if (SolakarState == NOT_STARTED) + Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, 500ms); + break; + case FAIL: + for (ObjectGuid const& guid : SolakarSummons) + if (Creature* creature = instance->GetCreature(guid)) + creature->DespawnOrUnsummon(); + SolakarSummons.clear(); + CurrentSolakarWave = 0; + SetData(DATA_SOLAKAR_FLAMEWREATH, NOT_STARTED); + break; + case DONE: + break; + } + SolakarState = data; + break; + case DATA_VAELASTRASZ: + VaelastraszState = data; + break; + case DATA_UROK_DOOMHOWL: + if (data == FAIL) + { + if (GetBossState(DATA_UROK_DOOMHOWL) != NOT_STARTED) { - creature->CastSpell(creature, SPELL_FINKLE_IS_EINHORN, true); - } - break; - } - } - - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_UROK_MAGUS: - [[fallthrough]]; - case NPC_UROK_ENFORCER: - UrokMobs.push_back(creature->GetGUID()); - break; - case NPC_HIGHLORD_OMOKK: - HighlordOmokk = creature->GetGUID(); - break; - case NPC_SHADOW_HUNTER_VOSHGAJIN: - ShadowHunterVoshgajin = creature->GetGUID(); - break; - case NPC_WARMASTER_VOONE: - WarMasterVoone = creature->GetGUID(); - break; - case NPC_MOTHER_SMOLDERWEB: - MotherSmolderweb = creature->GetGUID(); - break; - case NPC_UROK_DOOMHOWL: - UrokDoomhowl = creature->GetGUID(); - break; - case NPC_QUARTERMASTER_ZIGRIS: - QuartermasterZigris = creature->GetGUID(); - break; - case NPC_GIZRUL_THE_SLAVENER: - GizrultheSlavener = creature->GetGUID(); - break; - case NPC_HALYCON: - Halycon = creature->GetGUID(); - break; - case NPC_OVERLORD_WYRMTHALAK: - OverlordWyrmthalak = creature->GetGUID(); - break; - case NPC_PYROGAURD_EMBERSEER: - PyroguardEmberseer = creature->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - creature->DisappearAndDie(); - break; - case NPC_WARCHIEF_REND_BLACKHAND: - if (GetBossState(DATA_GYTH) != IN_PROGRESS) - { - WarchiefRendBlackhand = creature->GetGUID(); - } - - if (GetBossState(DATA_GYTH) == DONE) - creature->DisappearAndDie(); - break; - case NPC_GYTH: - Gyth = creature->GetGUID(); - break; - case NPC_THE_BEAST: - TheBeast = creature->GetGUID(); - break; - case NPC_GENERAL_DRAKKISATH: - GeneralDrakkisath = creature->GetGUID(); - break; - case NPC_LORD_VICTOR_NEFARIUS: - LordVictorNefarius = creature->GetGUID(); - if (GetBossState(DATA_GYTH) == DONE) - creature->DisappearAndDie(); - break; - case NPC_FINKLE_EINHORN: - creature->AI()->Talk(SAY_FINKLE_GANG); - break; - case NPC_CHROMATIC_ELITE_GUARD: - AddMinion(creature); - break; - } - } - - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_EMBERSEER_IN: - go_emberseerin = go->GetGUID(); - HandleGameObject(ObjectGuid::Empty, GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE, go); - break; - case GO_DOORS: - go_doors = go->GetGUID(); - if (GetBossState(DATA_DRAGONSPIRE_ROOM) == DONE) - HandleGameObject(ObjectGuid::Empty, true, go); - break; - case GO_EMBERSEER_OUT: - go_emberseerout = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, true, go); - break; - case GO_HALL_RUNE_1: - go_roomrunes[0] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_1) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_2: - go_roomrunes[1] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_2) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_3: - go_roomrunes[2] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_3) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_4: - go_roomrunes[3] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_4) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_5: - go_roomrunes[4] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_5) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_6: - go_roomrunes[5] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_6) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_HALL_RUNE_7: - go_roomrunes[6] = go->GetGUID(); - if (GetBossState(DATA_HALL_RUNE_7) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_1: - go_emberseerrunes[0] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_2: - go_emberseerrunes[1] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_3: - go_emberseerrunes[2] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_4: - go_emberseerrunes[3] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_5: - go_emberseerrunes[4] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_6: - go_emberseerrunes[5] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_EMBERSEER_RUNE_7: - go_emberseerrunes[6] = go->GetGUID(); - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == DONE) - HandleGameObject(ObjectGuid::Empty, false, go); - break; - case GO_PORTCULLIS_ACTIVE: - go_portcullis_active = go->GetGUID(); - if (GetBossState(DATA_GYTH) == DONE) - HandleGameObject(ObjectGuid::Empty, true, go); - break; - case GO_UROK_PILE: - go_urokPile = go->GetGUID(); - break; - case GO_UROK_CIRCLE: - go_urokOgreCirles.push_back(go->GetGUID()); - break; - case GO_UROK_CHALLENGE: - go_urokChallenge = go->GetGUID(); - break; - default: - break; - } - - InstanceScript::OnGameObjectCreate(go); - } - - bool SetBossState(uint32 type, EncounterState state) override - { - if (!InstanceScript::SetBossState(type, state)) - return false; - - switch (type) - { - case DATA_WARCHIEF_REND_BLACKHAND: - if (state == FAIL) - { - if (Creature* rend = instance->GetCreature(WarchiefRendBlackhand)) + SetBossState(DATA_UROK_DOOMHOWL, NOT_STARTED); + if (GameObject* challenge = instance->GetGameObject(go_urokChallenge)) + challenge->Delete(); + if (GameObject* pile = instance->GetGameObject(go_urokPile)) { - rend->Respawn(true); - } - - if (Creature* nefarius = instance->GetCreature(LordVictorNefarius)) - { - nefarius->AI()->Talk(SAY_NEFARIUS_REND_WIPE); + pile->SetLootState(GO_READY); + pile->Respawn(); } + for (auto const& circleGUID : go_urokOgreCirles) + if (GameObject* circle = instance->GetGameObject(circleGUID)) + circle->Delete(); + for (auto const& mobGUID : UrokMobs) + if (Creature* mob = instance->GetCreature(mobGUID)) + mob->DespawnOrUnsummon(); } - break; - default: - break; - } + } + break; + default: + break; + } + } - return true; + uint32 GetData(uint32 type) const override + { + if (type == DATA_SOLAKAR_FLAMEWREATH) + return SolakarState; + else if (type == DATA_VAELASTRASZ) + return VaelastraszState; + else + return InstanceScript::GetData(type); + } + + void SummonSolakarWave(uint8 number) + { + if (number < MAX_WAVE_COUNT) + { + if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_GUARDIAN, SolakarPosLeft)) + SolakarSummons.push_back(summon->GetGUID()); + + if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_HATCHER, SolakarPosRight)) + SolakarSummons.push_back(summon->GetGUID()); + + if (number == 0) + if (Creature* FirstHatcher = instance->GetCreature(SolakarSummons.back())) // works because we spawned a hatcher second + FirstHatcher->AI()->Talk(SAY_SOLAKAR_FIRST_HATCHER); + } + else if (number == MAX_WAVE_COUNT) + { + if (Creature* summon = instance->SummonCreature(NPC_SOLAKAR, SolakarPosBoss)) + SolakarSummons.push_back(summon->GetGUID()); + } + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_HIGHLORD_OMOKK: + return HighlordOmokk; + case DATA_SHADOW_HUNTER_VOSHGAJIN: + return ShadowHunterVoshgajin; + case DATA_WARMASTER_VOONE: + return WarMasterVoone; + case DATA_MOTHER_SMOLDERWEB: + return MotherSmolderweb; + case DATA_UROK_DOOMHOWL: + return UrokDoomhowl; + case DATA_QUARTERMASTER_ZIGRIS: + return QuartermasterZigris; + case DATA_GIZRUL_THE_SLAVENER: + return GizrultheSlavener; + case DATA_HALYCON: + return Halycon; + case DATA_OVERLORD_WYRMTHALAK: + return OverlordWyrmthalak; + case DATA_PYROGAURD_EMBERSEER: + return PyroguardEmberseer; + case DATA_WARCHIEF_REND_BLACKHAND: + return WarchiefRendBlackhand; + case DATA_GYTH: + return Gyth; + case DATA_THE_BEAST: + return TheBeast; + case DATA_GENERAL_DRAKKISATH: + return GeneralDrakkisath; + case GO_EMBERSEER_IN: + return go_emberseerin; + case GO_DOORS: + return go_doors; + case GO_EMBERSEER_OUT: + return go_emberseerout; + case GO_HALL_RUNE_1: + return go_roomrunes[0]; + case GO_HALL_RUNE_2: + return go_roomrunes[1]; + case GO_HALL_RUNE_3: + return go_roomrunes[2]; + case GO_HALL_RUNE_4: + return go_roomrunes[3]; + case GO_HALL_RUNE_5: + return go_roomrunes[4]; + case GO_HALL_RUNE_6: + return go_roomrunes[5]; + case GO_HALL_RUNE_7: + return go_roomrunes[6]; + case GO_EMBERSEER_RUNE_1: + return go_emberseerrunes[0]; + case GO_EMBERSEER_RUNE_2: + return go_emberseerrunes[1]; + case GO_EMBERSEER_RUNE_3: + return go_emberseerrunes[2]; + case GO_EMBERSEER_RUNE_4: + return go_emberseerrunes[3]; + case GO_EMBERSEER_RUNE_5: + return go_emberseerrunes[4]; + case GO_EMBERSEER_RUNE_6: + return go_emberseerrunes[5]; + case GO_EMBERSEER_RUNE_7: + return go_emberseerrunes[6]; + case GO_PORTCULLIS_ACTIVE: + return go_portcullis_active; + case GO_UROK_PILE: + return go_urokPile; + case GO_UROK_CHALLENGE: + return go_urokChallenge; + default: + break; } - void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override + return ObjectGuid::Empty; + } + + void Update(uint32 diff) override + { + Events.Update(diff); + + while (uint32 eventId = Events.ExecuteEvent()) { switch (eventId) { - case EVENT_PYROGUARD_EMBERSEER: - if (GetBossState(DATA_PYROGAURD_EMBERSEER) == NOT_STARTED) - { - if (Creature* Emberseer = instance->GetCreature(PyroguardEmberseer)) - Emberseer->AI()->SetData(1, 1); - } + case EVENT_DRAGONSPIRE_ROOM_STORE: + Dragonspireroomstore(); + Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s); break; - case EVENT_UROK_DOOMHOWL: - if (GetBossState(DATA_UROK_DOOMHOWL) == NOT_STARTED) - { - SetBossState(DATA_UROK_DOOMHOWL, IN_PROGRESS); - if (GameObject* pile = instance->GetGameObject(go_urokPile)) - { - pile->SetLootState(GO_JUST_DEACTIVATED); - } - } - break; - default: - break; - } - } - - void SetData(uint32 type, uint32 data) override - { - switch (type) - { - case AREATRIGGER: - if (data == AREATRIGGER_DRAGONSPIRE_HALL) - { - if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE) - Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_STORE, 1s); - } - break; - case DATA_SOLAKAR_FLAMEWREATH: - switch (data) - { - case IN_PROGRESS: - if (SolakarState == NOT_STARTED) - { - Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, 500ms); - } - break; - case FAIL: - for (ObjectGuid const& guid : SolakarSummons) - { - if (Creature* creature = instance->GetCreature(guid)) - { - creature->DespawnOrUnsummon(); - } - } - SolakarSummons.clear(); - CurrentSolakarWave = 0; - SetData(DATA_SOLAKAR_FLAMEWREATH, NOT_STARTED); - break; - case DONE: - break; - } - SolakarState = data; - break; - case DATA_VAELASTRASZ: - VaelastraszState = data; - break; - case DATA_UROK_DOOMHOWL: - if (data == FAIL) - { - if (GetBossState(DATA_UROK_DOOMHOWL) != NOT_STARTED) - { - SetBossState(DATA_UROK_DOOMHOWL, NOT_STARTED); - if (GameObject* challenge = instance->GetGameObject(go_urokChallenge)) - { - challenge->Delete(); - } - if (GameObject* pile = instance->GetGameObject(go_urokPile)) - { - pile->SetLootState(GO_READY); - pile->Respawn(); - } - for (auto const& circleGUID : go_urokOgreCirles) - { - if (GameObject* circle = instance->GetGameObject(circleGUID)) - { - circle->Delete(); - } - } - for (auto const& mobGUID : UrokMobs) - { - if (Creature* mob = instance->GetCreature(mobGUID)) - { - mob->DespawnOrUnsummon(); - } - } - } - } - break; - default: - break; - } - } - - uint32 GetData(uint32 type) const override - { - if (type == DATA_SOLAKAR_FLAMEWREATH) - { - return SolakarState; - } - else if (type == DATA_VAELASTRASZ) - { - return VaelastraszState; - } - else - { - return InstanceScript::GetData(type); - } - } - - void SummonSolakarWave(uint8 number) - { - if (number < MAX_WAVE_COUNT) - { - if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_GUARDIAN, SolakarPosLeft)) - { - SolakarSummons.push_back(summon->GetGUID()); - } - - if (Creature* summon = instance->SummonCreature(NPC_ROOKERY_HATCHER, SolakarPosRight)) - { - SolakarSummons.push_back(summon->GetGUID()); - } - - if (number == 0) - { - if (Creature* FirstHatcher = instance->GetCreature(SolakarSummons.back())) // works because we spawned a hatcher second - { - FirstHatcher->AI()->Talk(SAY_SOLAKAR_FIRST_HATCHER); - } - } - } - else if (number == MAX_WAVE_COUNT) - { - if (Creature* summon = instance->SummonCreature(NPC_SOLAKAR, SolakarPosBoss)) - { - SolakarSummons.push_back(summon->GetGUID()); - } - } - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case DATA_HIGHLORD_OMOKK: - return HighlordOmokk; - case DATA_SHADOW_HUNTER_VOSHGAJIN: - return ShadowHunterVoshgajin; - case DATA_WARMASTER_VOONE: - return WarMasterVoone; - case DATA_MOTHER_SMOLDERWEB: - return MotherSmolderweb; - case DATA_UROK_DOOMHOWL: - return UrokDoomhowl; - case DATA_QUARTERMASTER_ZIGRIS: - return QuartermasterZigris; - case DATA_GIZRUL_THE_SLAVENER: - return GizrultheSlavener; - case DATA_HALYCON: - return Halycon; - case DATA_OVERLORD_WYRMTHALAK: - return OverlordWyrmthalak; - case DATA_PYROGAURD_EMBERSEER: - return PyroguardEmberseer; - case DATA_WARCHIEF_REND_BLACKHAND: - return WarchiefRendBlackhand; - case DATA_GYTH: - return Gyth; - case DATA_THE_BEAST: - return TheBeast; - case DATA_GENERAL_DRAKKISATH: - return GeneralDrakkisath; - case GO_EMBERSEER_IN: - return go_emberseerin; - case GO_DOORS: - return go_doors; - case GO_EMBERSEER_OUT: - return go_emberseerout; - case GO_HALL_RUNE_1: - return go_roomrunes[0]; - case GO_HALL_RUNE_2: - return go_roomrunes[1]; - case GO_HALL_RUNE_3: - return go_roomrunes[2]; - case GO_HALL_RUNE_4: - return go_roomrunes[3]; - case GO_HALL_RUNE_5: - return go_roomrunes[4]; - case GO_HALL_RUNE_6: - return go_roomrunes[5]; - case GO_HALL_RUNE_7: - return go_roomrunes[6]; - case GO_EMBERSEER_RUNE_1: - return go_emberseerrunes[0]; - case GO_EMBERSEER_RUNE_2: - return go_emberseerrunes[1]; - case GO_EMBERSEER_RUNE_3: - return go_emberseerrunes[2]; - case GO_EMBERSEER_RUNE_4: - return go_emberseerrunes[3]; - case GO_EMBERSEER_RUNE_5: - return go_emberseerrunes[4]; - case GO_EMBERSEER_RUNE_6: - return go_emberseerrunes[5]; - case GO_EMBERSEER_RUNE_7: - return go_emberseerrunes[6]; - case GO_PORTCULLIS_ACTIVE: - return go_portcullis_active; - case GO_UROK_PILE: - return go_urokPile; - case GO_UROK_CHALLENGE: - return go_urokChallenge; - default: - break; - } - - return ObjectGuid::Empty; - } - - void Update(uint32 diff) override - { - Events.Update(diff); - - while (uint32 eventId = Events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DRAGONSPIRE_ROOM_STORE: - Dragonspireroomstore(); + case EVENT_DRAGONSPIRE_ROOM_CHECK: + Dragonspireroomcheck(); + if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)) Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s); + break; + case EVENT_SOLAKAR_WAVE: + SummonSolakarWave(CurrentSolakarWave); + if (CurrentSolakarWave < MAX_WAVE_COUNT) + { + Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, TIMER_SOLAKAR_WAVE); + CurrentSolakarWave++; + } + break; + default: + break; + } + } + } + + void Dragonspireroomstore() + { + + for (uint8 i = 0; i < 7; ++i) + { + // Refresh the creature list + runecreaturelist[i].clear(); + + if (GameObject* rune = instance->GetGameObject(go_roomrunes[i])) + { + for (uint8 j = 0; j < 3; ++j) + { + std::list creatureList; + GetCreatureListWithEntryInGrid(creatureList, rune, DragonspireMobs[j], 15.0f); + for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + if (Creature* creature = *itr) + runecreaturelist[i].push_back(creature->GetGUID()); + } + } + } + } + + void Dragonspireroomcheck() + { + Creature* mob = nullptr; + GameObject* rune = nullptr; + + for (uint8 i = 0; i < 7; ++i) + { + bool _mobAlive = false; + rune = instance->GetGameObject(go_roomrunes[i]); + if (!rune) + continue; + + if (rune->GetGoState() == GO_STATE_ACTIVE) + { + for (ObjectGuid const& guid : runecreaturelist[i]) + { + mob = instance->GetCreature(guid); + if (mob && mob->IsAlive()) + _mobAlive = true; + } + } + + if (!_mobAlive && rune->GetGoState() == GO_STATE_ACTIVE) + { + HandleGameObject(ObjectGuid::Empty, false, rune); + + switch (rune->GetEntry()) + { + case GO_HALL_RUNE_1: + SetBossState(DATA_HALL_RUNE_1, DONE); break; - case EVENT_DRAGONSPIRE_ROOM_CHECK: - Dragonspireroomcheck(); - if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)) - Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s); + case GO_HALL_RUNE_2: + SetBossState(DATA_HALL_RUNE_2, DONE); break; - case EVENT_SOLAKAR_WAVE: - SummonSolakarWave(CurrentSolakarWave); - if (CurrentSolakarWave < MAX_WAVE_COUNT) - { - Events.ScheduleEvent(EVENT_SOLAKAR_WAVE, TIMER_SOLAKAR_WAVE); - CurrentSolakarWave++; - } + case GO_HALL_RUNE_3: + SetBossState(DATA_HALL_RUNE_3, DONE); + break; + case GO_HALL_RUNE_4: + SetBossState(DATA_HALL_RUNE_4, DONE); + break; + case GO_HALL_RUNE_5: + SetBossState(DATA_HALL_RUNE_5, DONE); + break; + case GO_HALL_RUNE_6: + SetBossState(DATA_HALL_RUNE_6, DONE); + break; + case GO_HALL_RUNE_7: + SetBossState(DATA_HALL_RUNE_7, DONE); break; default: break; @@ -578,136 +607,49 @@ public: } } - void Dragonspireroomstore() + if (GetBossState(DATA_HALL_RUNE_1) == DONE && GetBossState(DATA_HALL_RUNE_2) == DONE && GetBossState(DATA_HALL_RUNE_3) == DONE && + GetBossState(DATA_HALL_RUNE_4) == DONE && GetBossState(DATA_HALL_RUNE_5) == DONE && GetBossState(DATA_HALL_RUNE_6) == DONE && + GetBossState(DATA_HALL_RUNE_7) == DONE) { - - for (uint8 i = 0; i < 7; ++i) - { - // Refresh the creature list - runecreaturelist[i].clear(); - - if (GameObject* rune = instance->GetGameObject(go_roomrunes[i])) - { - for (uint8 j = 0; j < 3; ++j) - { - std::list creatureList; - GetCreatureListWithEntryInGrid(creatureList, rune, DragonspireMobs[j], 15.0f); - for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) - { - if (Creature* creature = *itr) - { - runecreaturelist[i].push_back(creature->GetGUID()); - } - } - } - } - } + SetBossState(DATA_DRAGONSPIRE_ROOM, DONE); + if (GameObject* door1 = instance->GetGameObject(go_emberseerin)) + HandleGameObject(ObjectGuid::Empty, true, door1); + if (GameObject* door2 = instance->GetGameObject(go_doors)) + HandleGameObject(ObjectGuid::Empty, true, door2); + if (GameObject* door3 = instance->GetGameObject(go_emberseerin)) + HandleGameObject(ObjectGuid::Empty, true, door3); } - - void Dragonspireroomcheck() - { - Creature* mob = nullptr; - GameObject* rune = nullptr; - - for (uint8 i = 0; i < 7; ++i) - { - bool _mobAlive = false; - rune = instance->GetGameObject(go_roomrunes[i]); - if (!rune) - continue; - - if (rune->GetGoState() == GO_STATE_ACTIVE) - { - for (ObjectGuid const& guid : runecreaturelist[i]) - { - mob = instance->GetCreature(guid); - if (mob && mob->IsAlive()) - _mobAlive = true; - } - } - - if (!_mobAlive && rune->GetGoState() == GO_STATE_ACTIVE) - { - HandleGameObject(ObjectGuid::Empty, false, rune); - - switch (rune->GetEntry()) - { - case GO_HALL_RUNE_1: - SetBossState(DATA_HALL_RUNE_1, DONE); - break; - case GO_HALL_RUNE_2: - SetBossState(DATA_HALL_RUNE_2, DONE); - break; - case GO_HALL_RUNE_3: - SetBossState(DATA_HALL_RUNE_3, DONE); - break; - case GO_HALL_RUNE_4: - SetBossState(DATA_HALL_RUNE_4, DONE); - break; - case GO_HALL_RUNE_5: - SetBossState(DATA_HALL_RUNE_5, DONE); - break; - case GO_HALL_RUNE_6: - SetBossState(DATA_HALL_RUNE_6, DONE); - break; - case GO_HALL_RUNE_7: - SetBossState(DATA_HALL_RUNE_7, DONE); - break; - default: - break; - } - } - } - - if (GetBossState(DATA_HALL_RUNE_1) == DONE && GetBossState(DATA_HALL_RUNE_2) == DONE && GetBossState(DATA_HALL_RUNE_3) == DONE && - GetBossState(DATA_HALL_RUNE_4) == DONE && GetBossState(DATA_HALL_RUNE_5) == DONE && GetBossState(DATA_HALL_RUNE_6) == DONE && - GetBossState(DATA_HALL_RUNE_7) == DONE) - { - SetBossState(DATA_DRAGONSPIRE_ROOM, DONE); - if (GameObject* door1 = instance->GetGameObject(go_emberseerin)) - HandleGameObject(ObjectGuid::Empty, true, door1); - if (GameObject* door2 = instance->GetGameObject(go_doors)) - HandleGameObject(ObjectGuid::Empty, true, door2); - if (GameObject* door3 = instance->GetGameObject(go_emberseerin)) - HandleGameObject(ObjectGuid::Empty, true, door3); - } - } - - protected: - EventMap Events; - ObjectGuid HighlordOmokk; - ObjectGuid ShadowHunterVoshgajin; - ObjectGuid WarMasterVoone; - ObjectGuid MotherSmolderweb; - ObjectGuid UrokDoomhowl; - ObjectGuid QuartermasterZigris; - ObjectGuid GizrultheSlavener; - ObjectGuid Halycon; - ObjectGuid OverlordWyrmthalak; - ObjectGuid PyroguardEmberseer; - ObjectGuid WarchiefRendBlackhand; - ObjectGuid Gyth; - ObjectGuid LordVictorNefarius; - ObjectGuid TheBeast; - ObjectGuid GeneralDrakkisath; - ObjectGuid go_emberseerin; - ObjectGuid go_doors; - ObjectGuid go_emberseerout; - ObjectGuid go_blackrockaltar; - ObjectGuid go_roomrunes[7]; - ObjectGuid go_emberseerrunes[7]; - GuidVector runecreaturelist[7]; - ObjectGuid go_portcullis_active; - ObjectGuid go_urokPile; - ObjectGuid go_urokChallenge; - std::vector go_urokOgreCirles; - std::vector UrokMobs; - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_blackrock_spireMapScript(map); } + +protected: + EventMap Events; + ObjectGuid HighlordOmokk; + ObjectGuid ShadowHunterVoshgajin; + ObjectGuid WarMasterVoone; + ObjectGuid MotherSmolderweb; + ObjectGuid UrokDoomhowl; + ObjectGuid QuartermasterZigris; + ObjectGuid GizrultheSlavener; + ObjectGuid Halycon; + ObjectGuid OverlordWyrmthalak; + ObjectGuid PyroguardEmberseer; + ObjectGuid WarchiefRendBlackhand; + ObjectGuid Gyth; + ObjectGuid LordVictorNefarius; + ObjectGuid TheBeast; + ObjectGuid GeneralDrakkisath; + ObjectGuid go_emberseerin; + ObjectGuid go_doors; + ObjectGuid go_emberseerout; + ObjectGuid go_blackrockaltar; + ObjectGuid go_roomrunes[7]; + ObjectGuid go_emberseerrunes[7]; + GuidVector runecreaturelist[7]; + ObjectGuid go_portcullis_active; + ObjectGuid go_urokPile; + ObjectGuid go_urokChallenge; + std::vector go_urokOgreCirles; + std::vector UrokMobs; }; /*##### @@ -769,25 +711,20 @@ public: } }; -class go_father_flame : public GameObjectScript +struct go_father_flame : public GameObjectAI { -public: - go_father_flame() : GameObjectScript("go_father_flame") {} + go_father_flame(GameObject* go) : GameObjectAI(go) {} - void OnLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override + void OnStateChanged(uint32 state, Unit* /*unit*/) override { - if (InstanceScript* instance = go->GetInstanceScript()) - { + if (InstanceScript* instance = me->GetInstanceScript()) if (state == GO_ACTIVATED) { if (instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == IN_PROGRESS || instance->GetData(DATA_SOLAKAR_FLAMEWREATH) == DONE) - { return; - } instance->SetData(DATA_SOLAKAR_FLAMEWREATH, IN_PROGRESS); } - } } }; @@ -861,7 +798,6 @@ class spell_blackrock_spire_call_of_vaelastrasz : public SpellScript void OnEffect(SpellEffIndex /*effIndex*/) { if (Unit* caster = GetCaster()) - { if (InstanceScript* instance = caster->GetInstanceScript()) { instance->SetData(DATA_VAELASTRASZ, IN_PROGRESS); @@ -871,7 +807,6 @@ class spell_blackrock_spire_call_of_vaelastrasz : public SpellScript // despawn is called by the CreatureAI caster->SummonCreature(NPC_VAELASTRASZ_THE_RED, spawnPosition, TEMPSUMMON_TIMED_DESPAWN, 60 * IN_MILLISECONDS); } - } } void Register() override @@ -929,170 +864,153 @@ enum Events EVENT_FLAME_BREATH, }; -class npc_vaelastrasz_the_red : public CreatureScript +struct npc_vaelastrasz_the_red : public CreatureAI { -public: - npc_vaelastrasz_the_red() : CreatureScript("npc_vaelastrasz_the_red") { } + npc_vaelastrasz_the_red(Creature* creature) : CreatureAI(creature) { } - struct npc_vaelastrasz_the_redAI : public CreatureAI + void IsSummonedBy(WorldObject* summoner) override { - npc_vaelastrasz_the_redAI(Creature* creature) : CreatureAI(creature) { } + if (!summoner) + return; + _combatEnabled = false; + me->CastSpell(me, SPELL_VAELAN_SPAWNS, false); + me->SetFacingToObject(summoner); + Talk(SAY_RED_SUMMONED); + if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 100.0f)) + _victorGUID = victor->GetGUID(); + events.ScheduleEvent(EVENT_RED_1_TALK_BEFORE_TRANSFORM, 3s); + } - void IsSummonedBy(WorldObject* summoner) override + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - if (!summoner) + switch (eventId) { - return; - } - _combatEnabled = false; - me->CastSpell(me, SPELL_VAELAN_SPAWNS, false); - me->SetFacingToObject(summoner); - Talk(SAY_RED_SUMMONED); - if (Creature* victor = me->FindNearestCreature(NPC_LORD_VICTOR_NEFARIUS, 100.0f)) - { - _victorGUID = victor->GetGUID(); - } - events.ScheduleEvent(EVENT_RED_1_TALK_BEFORE_TRANSFORM, 3s); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RED_1_TALK_BEFORE_TRANSFORM: - Talk(SAY_RED_BEFORE_TRANSFORM); - events.ScheduleEvent(EVENT_RED_2_TRANSFORM, 2s); - break; - case EVENT_RED_2_TRANSFORM: - me->CastSpell(me, SPELL_TOUCH_OF_VAELASTRASZ, false); - me->SetEntry(NPC_VAELASTRASZ_UBRS); - me->SetDisplayId(MODEL_VAELASTRASZ_UBRS); - events.ScheduleEvent(EVENT_VAEL_TALK_SUMMON, 1s); - events.ScheduleEvent(EVENT_VAEL_1_START_COMBAT, 5s); - break; - case EVENT_VAEL_TALK_SUMMON: - Talk(SAY_VAEL_SUMMONED); - break; - case EVENT_VAEL_1_START_COMBAT: - _combatEnabled = true; - me->SetImmuneToNPC(false); - if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 100.0f, true)) + case EVENT_RED_1_TALK_BEFORE_TRANSFORM: + Talk(SAY_RED_BEFORE_TRANSFORM); + events.ScheduleEvent(EVENT_RED_2_TRANSFORM, 2s); + break; + case EVENT_RED_2_TRANSFORM: + me->CastSpell(me, SPELL_TOUCH_OF_VAELASTRASZ, false); + me->SetEntry(NPC_VAELASTRASZ_UBRS); + me->SetDisplayId(MODEL_VAELASTRASZ_UBRS); + events.ScheduleEvent(EVENT_VAEL_TALK_SUMMON, 1s); + events.ScheduleEvent(EVENT_VAEL_1_START_COMBAT, 5s); + break; + case EVENT_VAEL_TALK_SUMMON: + Talk(SAY_VAEL_SUMMONED); + break; + case EVENT_VAEL_1_START_COMBAT: + _combatEnabled = true; + me->SetImmuneToNPC(false); + if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 100.0f, true)) + { + me->AddThreat(gyth, 1000000.f); + me->AI()->AttackStart(gyth); + } + if (Creature* rend = me->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 100.0f, true)) + { + if (!rend->IsImmuneToNPC() && rend->isTargetableForAttack()) { - me->AddThreat(gyth, 1000000.f); - me->AI()->AttackStart(gyth); - } - if (Creature* rend = me->FindNearestCreature(NPC_WARCHIEF_REND_BLACKHAND, 100.0f, true)) - { - if (!rend->IsImmuneToNPC() && rend->isTargetableForAttack()) + me->AddThreat(rend, 100000.f); + if (!me->FindNearestCreature(NPC_GYTH, 100.0f, true)) { - me->AddThreat(rend, 100000.f); - if (!me->FindNearestCreature(NPC_GYTH, 100.0f, true)) - { - me->AI()->AttackStart(rend); - } + me->AI()->AttackStart(rend); } } - _events2.ScheduleEvent(EVENT_FLAME_BREATH, 5s); - events.ScheduleEvent(EVENT_NEFARIUS_TALK_1, 500ms); - break; - case EVENT_NEFARIUS_TALK_1: - if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) - { - victor->GetMotionMaster()->Clear(); // stop pacing - victor->GetMotionMaster()->MoveIdle(); - victor->StopMovingOnCurrentPos(); - victor->SetFacingToObject(me); - victor->AI()->Talk(SAY_NEFARIUS_15); - } - events.ScheduleEvent(EVENT_NEFARIUS_TALK_2, 6s); - break; - case EVENT_NEFARIUS_TALK_2: - if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) - { - victor->SetFacingToObject(me); - victor->AI()->Talk(SAY_NEFARIUS_16); - } - events.ScheduleEvent(EVENT_NEFARIUS_TALK_3, 5s); - break; - case EVENT_NEFARIUS_TALK_3: - if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) - { - victor->SetFacingToObject(me); - victor->AI()->Talk(SAY_NEFARIUS_17); - } - events.ScheduleEvent(EVENT_NEFARIUS_CORRUPTION, 5s); - break; - case EVENT_NEFARIUS_CORRUPTION: - _combatEnabled = false; - me->AttackStop(); - me->RemoveAllAuras(); - me->StopMovingOnCurrentPos(); - me->SetFaction(FACTION_FRIENDLY); - if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) - { - victor->SetFacingToObject(me); - victor->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY); - } - events.ScheduleEvent(EVENT_VAEL_2_TRANSFORM, 1s); - break; - case EVENT_VAEL_2_TRANSFORM: - Talk(SAY_VAEL_STOP_COMBAT); - me->SetDisplayId(MODEL_VAELASTRASZ_THE_RED); - events.ScheduleEvent(EVENT_VAEL_3_DESPAWN, 500ms); - break; - case EVENT_VAEL_3_DESPAWN: - DoCast(me, SPELL_VAELASTRASZ_SPAWN); - me->DespawnOrUnsummon(1500ms); - break; - default: - break; - } - } - - if (!_combatEnabled || !UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - _events2.Update(diff); - - switch (_events2.ExecuteEvent()) - { - case EVENT_FLAME_BREATH: - me->CastSpell(me, SPELL_FLAMEBREATH, false); + } + _events2.ScheduleEvent(EVENT_FLAME_BREATH, 5s); + events.ScheduleEvent(EVENT_NEFARIUS_TALK_1, 500ms); + break; + case EVENT_NEFARIUS_TALK_1: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + { + victor->GetMotionMaster()->Clear(); // stop pacing + victor->GetMotionMaster()->MoveIdle(); + victor->StopMovingOnCurrentPos(); + victor->SetFacingToObject(me); + victor->AI()->Talk(SAY_NEFARIUS_15); + } + events.ScheduleEvent(EVENT_NEFARIUS_TALK_2, 6s); + break; + case EVENT_NEFARIUS_TALK_2: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + { + victor->SetFacingToObject(me); + victor->AI()->Talk(SAY_NEFARIUS_16); + } + events.ScheduleEvent(EVENT_NEFARIUS_TALK_3, 5s); + break; + case EVENT_NEFARIUS_TALK_3: + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + { + victor->SetFacingToObject(me); + victor->AI()->Talk(SAY_NEFARIUS_17); + } + events.ScheduleEvent(EVENT_NEFARIUS_CORRUPTION, 5s); + break; + case EVENT_NEFARIUS_CORRUPTION: + _combatEnabled = false; + me->AttackStop(); + me->RemoveAllAuras(); + me->StopMovingOnCurrentPos(); + me->SetFaction(FACTION_FRIENDLY); + if (Creature* victor = ObjectAccessor::GetCreature(*me, _victorGUID)) + { + victor->SetFacingToObject(me); + victor->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY); + } + events.ScheduleEvent(EVENT_VAEL_2_TRANSFORM, 1s); + break; + case EVENT_VAEL_2_TRANSFORM: + Talk(SAY_VAEL_STOP_COMBAT); + me->SetDisplayId(MODEL_VAELASTRASZ_THE_RED); + events.ScheduleEvent(EVENT_VAEL_3_DESPAWN, 500ms); + break; + case EVENT_VAEL_3_DESPAWN: + DoCast(me, SPELL_VAELASTRASZ_SPAWN); + me->DespawnOrUnsummon(1500ms); break; default: break; } - - DoMeleeAttackIfReady(); - return; } - private: - ObjectGuid _victorGUID; - bool _combatEnabled; - EventMap _events2; - }; + if (!_combatEnabled || !UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) + return; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackrockSpireAI(creature); + _events2.Update(diff); + + switch (_events2.ExecuteEvent()) + { + case EVENT_FLAME_BREATH: + me->CastSpell(me, SPELL_FLAMEBREATH, false); + break; + default: + break; + } + + DoMeleeAttackIfReady(); + return; } + +private: + ObjectGuid _victorGUID; + bool _combatEnabled; + EventMap _events2; }; void AddSC_instance_blackrock_spire() { - new instance_blackrock_spire(); + RegisterInstanceScript(instance_blackrock_spire, MAP_BLACKROCK_SPIRE); new at_dragonspire_hall(); new at_blackrock_stadium(); - new go_father_flame(); + RegisterBlackrockSpireGameObjectAI(go_father_flame); new near_scarshield_infiltrator(); new at_scarshield_infiltrator(); RegisterSpellScript(spell_blackrock_spire_call_of_vaelastrasz); - new npc_vaelastrasz_the_red(); + RegisterBlackrockSpireCreatureAI(npc_vaelastrasz_the_red); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h index f2a1aed32..b90747508 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h @@ -127,5 +127,6 @@ inline AI* GetBlackwingLairAI(T* obj) } #define RegisterBlackwingLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackwingLairAI) +#define RegisterBlackwingLairGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetBlackwingLairAI) #endif diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp index 55c5c7a94..467b2f96b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -58,196 +58,157 @@ enum Actions ACTION_DISARMED = 1 }; -class boss_broodlord : public CreatureScript +struct boss_broodlord : public BossAI { -public: - boss_broodlord() : CreatureScript("boss_broodlord") { } + boss_broodlord(Creature* creature) : BossAI(creature, DATA_BROODLORD_LASHLAYER) { } - struct boss_broodlordAI : public BossAI + void JustEngagedWith(Unit* who) override { - boss_broodlordAI(Creature* creature) : BossAI(creature, DATA_BROODLORD_LASHLAYER) { } + BossAI::JustEngagedWith(who); + Talk(SAY_AGGRO); - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - Talk(SAY_AGGRO); - - events.ScheduleEvent(EVENT_CLEAVE, 8s); - events.ScheduleEvent(EVENT_BLASTWAVE, 12s); - events.ScheduleEvent(EVENT_MORTALSTRIKE, 20s); - events.ScheduleEvent(EVENT_KNOCKBACK, 30s); - events.ScheduleEvent(EVENT_CHECK, 1s); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - - std::list _goList; - GetGameObjectListWithEntryInGrid(_goList, me, GO_SUPPRESSION_DEVICE, 200.0f); - for (std::list::const_iterator itr = _goList.begin(); itr != _goList.end(); itr++) - { - ((*itr)->AI()->DoAction(ACTION_DEACTIVATE)); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, 7s); - break; - case EVENT_BLASTWAVE: - DoCastVictim(SPELL_BLASTWAVE); - events.ScheduleEvent(EVENT_BLASTWAVE, 20s, 35s); - break; - case EVENT_MORTALSTRIKE: - DoCastVictim(SPELL_MORTALSTRIKE); - events.ScheduleEvent(EVENT_MORTALSTRIKE, 25s, 35s); - break; - case EVENT_KNOCKBACK: - DoCastVictim(SPELL_KNOCKBACK); - if (DoGetThreat(me->GetVictim())) - DoModifyThreatByPercent(me->GetVictim(), -50); - events.ScheduleEvent(EVENT_KNOCKBACK, 15s, 30s); - break; - case EVENT_CHECK: - if (me->GetDistance(me->GetHomePosition()) > 150.0f) - { - Talk(SAY_LEASH); - EnterEvadeMode(); - } - events.ScheduleEvent(EVENT_CHECK, 1s); - break; - } - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + events.ScheduleEvent(EVENT_CLEAVE, 8s); + events.ScheduleEvent(EVENT_BLASTWAVE, 12s); + events.ScheduleEvent(EVENT_MORTALSTRIKE, 20s); + events.ScheduleEvent(EVENT_KNOCKBACK, 30s); + events.ScheduleEvent(EVENT_CHECK, 1s); } -}; -class go_suppression_device : public GameObjectScript -{ - public: - go_suppression_device() : GameObjectScript("go_suppression_device") { } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); - void OnLootStateChanged(GameObject* go, uint32 state, Unit* /*unit*/) override + std::list _goList; + GetGameObjectListWithEntryInGrid(_goList, me, GO_SUPPRESSION_DEVICE, 200.0f); + for (std::list::const_iterator itr = _goList.begin(); itr != _goList.end(); itr++) + ((*itr)->AI()->DoAction(ACTION_DEACTIVATE)); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) { - switch (state) + switch (eventId) { - case GO_JUST_DEACTIVATED: // This case prevents the Gameobject despawn by Disarm Trap - go->SetLootState(GO_READY); - [[fallthrough]]; - case GO_ACTIVATED: - go->AI()->DoAction(ACTION_DISARMED); + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 7s); + break; + case EVENT_BLASTWAVE: + DoCastVictim(SPELL_BLASTWAVE); + events.ScheduleEvent(EVENT_BLASTWAVE, 20s, 35s); + break; + case EVENT_MORTALSTRIKE: + DoCastVictim(SPELL_MORTALSTRIKE); + events.ScheduleEvent(EVENT_MORTALSTRIKE, 25s, 35s); + break; + case EVENT_KNOCKBACK: + DoCastVictim(SPELL_KNOCKBACK); + if (DoGetThreat(me->GetVictim())) + DoModifyThreatByPercent(me->GetVictim(), -50); + events.ScheduleEvent(EVENT_KNOCKBACK, 15s, 30s); + break; + case EVENT_CHECK: + if (me->GetDistance(me->GetHomePosition()) > 150.0f) + { + Talk(SAY_LEASH); + EnterEvadeMode(); + } + events.ScheduleEvent(EVENT_CHECK, 1s); break; } } - struct go_suppression_deviceAI : public GameObjectAI + DoMeleeAttackIfReady(); + } +}; + +struct go_suppression_device : public GameObjectAI +{ + go_suppression_device(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()), _active(true) { } + + void InitializeAI() override + { + if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) == DONE) { - go_suppression_deviceAI(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()), _active(true) { } - - void InitializeAI() override - { - if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) == DONE) - { - Deactivate(); - return; - } - - _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SUPPRESSION_CAST: - if (me->GetGoState() == GO_STATE_READY) - { - me->CastSpell(nullptr, SPELL_SUPPRESSION_AURA); - me->SendCustomAnim(0); - } - _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); - break; - case EVENT_SUPPRESSION_RESET: - Activate(); - break; - } - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_DEACTIVATE) - { - _events.CancelEvent(EVENT_SUPPRESSION_RESET); - } - else if (action == ACTION_DISARMED) - { - Deactivate(); - _events.CancelEvent(EVENT_SUPPRESSION_CAST); - - if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) != DONE) - { - _events.ScheduleEvent(EVENT_SUPPRESSION_RESET, 30s, 120s); - } - } - } - - void Activate() - { - if (_active) - return; - _active = true; - if (me->GetGoState() == GO_STATE_ACTIVE) - me->SetGoState(GO_STATE_READY); - me->SetLootState(GO_READY); - me->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); - me->Respawn(); - } - - void Deactivate() - { - if (!_active) - return; - _active = false; - me->SetGoState(GO_STATE_ACTIVE); - me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - _events.CancelEvent(EVENT_SUPPRESSION_CAST); - } - - private: - InstanceScript* _instance; - EventMap _events; - bool _active; - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return new go_suppression_deviceAI(go); + Deactivate(); + return; } + + _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUPPRESSION_CAST: + if (me->GetGoState() == GO_STATE_READY) + { + me->CastSpell(nullptr, SPELL_SUPPRESSION_AURA); + me->SendCustomAnim(0); + } + _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); + break; + case EVENT_SUPPRESSION_RESET: + Activate(); + break; + } + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_DEACTIVATE) + { + _events.CancelEvent(EVENT_SUPPRESSION_RESET); + } + else if (action == ACTION_DISARMED) + { + Deactivate(); + _events.CancelEvent(EVENT_SUPPRESSION_CAST); + + if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) != DONE) + _events.ScheduleEvent(EVENT_SUPPRESSION_RESET, 30s, 120s); + } + } + + void Activate() + { + if (_active) + return; + _active = true; + if (me->GetGoState() == GO_STATE_ACTIVE) + me->SetGoState(GO_STATE_READY); + me->SetLootState(GO_READY); + me->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + _events.ScheduleEvent(EVENT_SUPPRESSION_CAST, 5s); + me->Respawn(); + } + + void Deactivate() + { + if (!_active) + return; + _active = false; + me->SetGoState(GO_STATE_ACTIVE); + me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + _events.CancelEvent(EVENT_SUPPRESSION_CAST); + } + +private: + InstanceScript* _instance; + EventMap _events; + bool _active; }; class spell_suppression_aura : public SpellScript @@ -271,7 +232,7 @@ class spell_suppression_aura : public SpellScript void AddSC_boss_broodlord() { - new boss_broodlord(); - new go_suppression_device(); + RegisterBlackwingLairCreatureAI(boss_broodlord); + RegisterBlackwingLairGameObjectAI(go_suppression_device); RegisterSpellScript(spell_suppression_aura); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp index 64d23aa43..e645a2c22 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp @@ -70,203 +70,171 @@ enum Misc Position const homePos = { -7491.1587f, -1069.718f, 476.59094, 476.59094f }; -class boss_chromaggus : public CreatureScript +struct boss_chromaggus : public BossAI { -public: - boss_chromaggus() : CreatureScript("boss_chromaggus") { } - - struct boss_chromaggusAI : public BossAI + boss_chromaggus(Creature* creature) : BossAI(creature, DATA_CHROMAGGUS) { - boss_chromaggusAI(Creature* creature) : BossAI(creature, DATA_CHROMAGGUS) + Initialize(); + + // Select the 2 breaths that we are going to use until despawned so we don't end up casting 2 of the same breath. + _breathSpells = { SPELL_INCINERATE, SPELL_TIMELAPSE, SPELL_CORROSIVEACID, SPELL_IGNITEFLESH, SPELL_FROSTBURN }; + + Acore::Containers::RandomResize(_breathSpells, 2); + + // Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed. + creature->SetImmuneToAll(true); + } + + void Initialize() + { + Enraged = false; + } + + void Reset() override + { + _Reset(); + + Initialize(); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + + events.ScheduleEvent(EVENT_SHIMMER, 1s); + events.ScheduleEvent(EVENT_BREATH, 30s); + events.ScheduleEvent(EVENT_BREATH, 60s); + events.ScheduleEvent(EVENT_AFFLICTION, 10s); + events.ScheduleEvent(EVENT_FRENZY, 15s); + } + + bool CanAIAttack(Unit const* victim) const override + { + return !victim->HasAura(SPELL_TIMELAPSE); + } + + void SetGUID(ObjectGuid const& guid, int32 id) override + { + if (id == GUID_LEVER_USER) { - Initialize(); - - // Select the 2 breaths that we are going to use until despawned so we don't end up casting 2 of the same breath. - _breathSpells = { SPELL_INCINERATE, SPELL_TIMELAPSE, SPELL_CORROSIVEACID, SPELL_IGNITEFLESH, SPELL_FROSTBURN }; - - Acore::Containers::RandomResize(_breathSpells, 2); - + _playerGUID = guid; // Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed. - creature->SetImmuneToAll(true); + me->SetImmuneToAll(false); } + } - void Initialize() + void PathEndReached(uint32 /*pathId*/) override + { + if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID)) + me->SetInCombatWith(player); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - Enraged = false; - } - - void Reset() override - { - _Reset(); - - Initialize(); - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - events.ScheduleEvent(EVENT_SHIMMER, 1s); - events.ScheduleEvent(EVENT_BREATH, 30s); - events.ScheduleEvent(EVENT_BREATH, 60s); - events.ScheduleEvent(EVENT_AFFLICTION, 10s); - events.ScheduleEvent(EVENT_FRENZY, 15s); - } - - bool CanAIAttack(Unit const* victim) const override - { - return !victim->HasAura(SPELL_TIMELAPSE); - } - - void SetGUID(ObjectGuid const& guid, int32 id) override - { - if (id == GUID_LEVER_USER) + switch (eventId) { - _playerGUID = guid; - // Hack fix: This is here to prevent him from being pulled from the floor underneath, remove it once maps are fixed. - me->SetImmuneToAll(false); + case EVENT_SHIMMER: + { + // Cast new random vulnerabilty on self + DoCast(me, SPELL_ELEMENTAL_SHIELD); + Talk(EMOTE_SHIMMER); + events.ScheduleEvent(EVENT_SHIMMER, 17s, 25s); + break; + } + case EVENT_BREATH: + DoCastVictim(_breathSpells.front()); + _breathSpells.reverse(); + events.ScheduleEvent(EVENT_BREATH, 60s); + break; + case EVENT_AFFLICTION: + { + uint32 afflictionSpellID = RAND(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN); + std::vector playerTargets; + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()->ToPlayer()) + if (!player->IsGameMaster() && !player->IsSpectator() && player->IsAlive()) + playerTargets.push_back(player); + + if (playerTargets.size() > 12) + Acore::Containers::RandomResize(playerTargets, 12); + + for (Player* player : playerTargets) + { + DoCast(player, afflictionSpellID, true); + + if (player->HasAllAuras(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN)) + DoCast(player, SPELL_CHROMATIC_MUT_1); + } + } + events.ScheduleEvent(EVENT_AFFLICTION, 10s); + break; + case EVENT_FRENZY: + DoCast(me, SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 10s, 15s); + break; } - } - - void PathEndReached(uint32 /*pathId*/) override - { - if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID)) - { - me->SetInCombatWith(player); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHIMMER: - { - // Cast new random vulnerabilty on self - DoCast(me, SPELL_ELEMENTAL_SHIELD); - Talk(EMOTE_SHIMMER); - events.ScheduleEvent(EVENT_SHIMMER, 17s, 25s); - break; - } - case EVENT_BREATH: - DoCastVictim(_breathSpells.front()); - _breathSpells.reverse(); - events.ScheduleEvent(EVENT_BREATH, 60s); - break; - case EVENT_AFFLICTION: - { - uint32 afflictionSpellID = RAND(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN); - std::vector playerTargets; - Map::PlayerList const& players = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* player = itr->GetSource()->ToPlayer()) - { - if (!player->IsGameMaster() && !player->IsSpectator() && player->IsAlive()) - { - playerTargets.push_back(player); - } - } - } - - if (playerTargets.size() > 12) - { - Acore::Containers::RandomResize(playerTargets, 12); - } - - for (Player* player : playerTargets) - { - DoCast(player, afflictionSpellID, true); - - if (player->HasAllAuras(SPELL_BROODAF_BLUE, SPELL_BROODAF_BLACK, SPELL_BROODAF_RED, SPELL_BROODAF_BRONZE, SPELL_BROODAF_GREEN)) - DoCast(player, SPELL_CHROMATIC_MUT_1); - } - } - events.ScheduleEvent(EVENT_AFFLICTION, 10s); - break; - case EVENT_FRENZY: - DoCast(me, SPELL_FRENZY); - events.ScheduleEvent(EVENT_FRENZY, 10s, 15s); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - // Enrage if not already enraged and below 20% - if (!Enraged && HealthBelowPct(20)) - { - DoCast(me, SPELL_ENRAGE); - Enraged = true; - } - - DoMeleeAttackIfReady(); } - private: - std::list _breathSpells; - bool Enraged; - ObjectGuid _playerGUID; - }; + // Enrage if not already enraged and below 20% + if (!Enraged && HealthBelowPct(20)) + { + DoCast(me, SPELL_ENRAGE); + Enraged = true; + } - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + DoMeleeAttackIfReady(); } + +private: + std::list _breathSpells; + bool Enraged; + ObjectGuid _playerGUID; }; -class go_chromaggus_lever : public GameObjectScript +struct go_chromaggus_lever : public GameObjectAI { - public: - go_chromaggus_lever() : GameObjectScript("go_chromaggus_lever") { } + go_chromaggus_lever(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { } - struct go_chromaggus_leverAI : public GameObjectAI + bool GossipHello(Player* player, bool reportUse) override + { + if (reportUse) { - go_chromaggus_leverAI(GameObject* go) : GameObjectAI(go), _instance(go->GetInstanceScript()) { } - - bool GossipHello(Player* player, bool reportUse) override + if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS) { - if (reportUse) + if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS)) { - if (_instance->GetBossState(DATA_CHROMAGGUS) != DONE && _instance->GetBossState(DATA_CHROMAGGUS) != IN_PROGRESS) - { - if (Creature* creature = _instance->GetCreature(DATA_CHROMAGGUS)) - { - creature->SetHomePosition(homePos); - creature->GetMotionMaster()->MoveWaypoint(creature->GetEntry() * 10, false); - creature->AI()->SetGUID(player->GetGUID(), GUID_LEVER_USER); - } - - if (GameObject* go = _instance->GetGameObject(DATA_GO_CHROMAGGUS_DOOR)) - _instance->HandleGameObject(ObjectGuid::Empty, true, go); - } - - me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_IN_USE); - me->SetGoState(GO_STATE_ACTIVE); + creature->SetHomePosition(homePos); + creature->GetMotionMaster()->MoveWaypoint(creature->GetEntry() * 10, false); + creature->AI()->SetGUID(player->GetGUID(), GUID_LEVER_USER); } - return true; + if (GameObject* go = _instance->GetGameObject(DATA_GO_CHROMAGGUS_DOOR)) + _instance->HandleGameObject(ObjectGuid::Empty, true, go); } - private: - InstanceScript* _instance; - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetBlackwingLairAI(go); + me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE | GO_FLAG_IN_USE); + me->SetGoState(GO_STATE_ACTIVE); } + + return true; + } + +private: + InstanceScript* _instance; }; enum ElementalShieldSpells @@ -306,9 +274,7 @@ class spell_gen_elemental_shield : public SpellScript if (Unit* caster = GetCaster()) { for (uint32 spell = SPELL_FIRE_ELEMENTAL_SHIELD; spell <= SPELL_ARCANE_ELEMENTAL_SHIELD; ++spell) - { caster->RemoveAurasDueToSpell(spell); - } caster->CastSpell(caster, SPELL_FIRE_ELEMENTAL_SHIELD + urand(0, 4), true); } @@ -341,9 +307,7 @@ class spell_gen_brood_power : public SpellScript if (Unit* caster = GetCaster()) { for (uint32 spell = SPELL_RED_BROOD_POWER; spell <= SPELL_GREEN_BROOD_POWER; ++spell) - { caster->RemoveAurasDueToSpell(spell); - } caster->CastSpell(caster, RAND(SPELL_RED_BROOD_POWER, SPELL_BLUE_BROOD_POWER, SPELL_BRONZE_BROOD_POWER, SPELL_BLACK_BROOD_POWER, SPELL_GREEN_BROOD_POWER), true); } @@ -357,8 +321,8 @@ class spell_gen_brood_power : public SpellScript void AddSC_boss_chromaggus() { - new boss_chromaggus(); - new go_chromaggus_lever(); + RegisterBlackwingLairCreatureAI(boss_chromaggus); + RegisterBlackwingLairGameObjectAI(go_chromaggus_lever); RegisterSpellScript(spell_gen_elemental_shield); RegisterSpellScript(spell_gen_brood_power); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp index 832642ef1..0edd68587 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp @@ -33,82 +33,69 @@ enum Events EVENT_SHADOWOFEBONROC = 3 }; -class boss_ebonroc : public CreatureScript +struct boss_ebonroc : public BossAI { -public: - boss_ebonroc() : CreatureScript("boss_ebonroc") { } + boss_ebonroc(Creature* creature) : BossAI(creature, DATA_EBONROC) { } - struct boss_ebonrocAI : public BossAI + void MovementInform(uint32 type, uint32 id) override { - boss_ebonrocAI(Creature* creature) : BossAI(creature, DATA_EBONROC) { } + if (type != WAYPOINT_MOTION_TYPE || id != 13) + return; - void MovementInform(uint32 type, uint32 id) override + me->GetMotionMaster()->MoveRandom(10.f); + + me->m_Events.AddEventAtOffset([this]() { - if (type != WAYPOINT_MOTION_TYPE || id != 13) + me->GetMotionMaster()->Initialize(); + }, 15s); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + + events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - return; + case EVENT_SHADOWFLAME: + DoCastVictim(SPELL_SHADOWFLAME); + events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); + break; + case EVENT_WINGBUFFET: + DoCastVictim(SPELL_WINGBUFFET); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + break; + case EVENT_SHADOWOFEBONROC: + DoCastVictim(SPELL_SHADOWOFEBONROC); + events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s); + break; } - me->GetMotionMaster()->MoveRandom(10.f); - - me->m_Events.AddEventAtOffset([this]() - { - me->GetMotionMaster()->Initialize(); - }, 15s); - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADOWFLAME: - DoCastVictim(SPELL_SHADOWFLAME); - events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); - break; - case EVENT_WINGBUFFET: - DoCastVictim(SPELL_WINGBUFFET); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - break; - case EVENT_SHADOWOFEBONROC: - DoCastVictim(SPELL_SHADOWOFEBONROC); - events.ScheduleEvent(EVENT_SHADOWOFEBONROC, 8s, 10s); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + DoMeleeAttackIfReady(); } }; void AddSC_boss_ebonroc() { - new boss_ebonroc(); + RegisterBlackwingLairCreatureAI(boss_ebonroc); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp index 197b1d843..7d5f217fd 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp @@ -33,69 +33,58 @@ enum Events EVENT_FLAMEBUFFET = 3 }; -class boss_firemaw : public CreatureScript +struct boss_firemaw : public BossAI { -public: - boss_firemaw() : CreatureScript("boss_firemaw") { } + boss_firemaw(Creature* creature) : BossAI(creature, DATA_FIREMAW) { } - struct boss_firemawAI : public BossAI + void JustEngagedWith(Unit* who) override { - boss_firemawAI(Creature* creature) : BossAI(creature, DATA_FIREMAW) { } + BossAI::JustEngagedWith(who); - void JustEngagedWith(Unit* who) override + events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - BossAI::JustEngagedWith(who); - - events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); + switch (eventId) + { + case EVENT_SHADOWFLAME: + DoCastVictim(SPELL_SHADOWFLAME); + events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); + break; + case EVENT_WINGBUFFET: + DoCastVictim(SPELL_WINGBUFFET); + if (DoGetThreat(me->GetVictim())) + DoModifyThreatByPercent(me->GetVictim(), -75); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + break; + case EVENT_FLAMEBUFFET: + DoCastVictim(SPELL_FLAMEBUFFET); + events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s); + break; + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADOWFLAME: - DoCastVictim(SPELL_SHADOWFLAME); - events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); - break; - case EVENT_WINGBUFFET: - DoCastVictim(SPELL_WINGBUFFET); - if (DoGetThreat(me->GetVictim())) - DoModifyThreatByPercent(me->GetVictim(), -75); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - break; - case EVENT_FLAMEBUFFET: - DoCastVictim(SPELL_FLAMEBUFFET); - events.ScheduleEvent(EVENT_FLAMEBUFFET, 5s); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + DoMeleeAttackIfReady(); } }; void AddSC_boss_firemaw() { - new boss_firemaw(); + RegisterBlackwingLairCreatureAI(boss_firemaw); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp index ce1028fe7..4933a0b63 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp @@ -38,70 +38,59 @@ enum Events EVENT_FRENZY = 3 }; -class boss_flamegor : public CreatureScript +struct boss_flamegor : public BossAI { -public: - boss_flamegor() : CreatureScript("boss_flamegor") { } + boss_flamegor(Creature* creature) : BossAI(creature, DATA_FLAMEGOR) { } - struct boss_flamegorAI : public BossAI + void JustEngagedWith(Unit* who) override { - boss_flamegorAI(Creature* creature) : BossAI(creature, DATA_FLAMEGOR) { } + BossAI::JustEngagedWith(who); - void JustEngagedWith(Unit* who) override + events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + events.ScheduleEvent(EVENT_FRENZY, 10s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - BossAI::JustEngagedWith(who); - - events.ScheduleEvent(EVENT_SHADOWFLAME, 18s); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - events.ScheduleEvent(EVENT_FRENZY, 10s); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); + switch (eventId) + { + case EVENT_SHADOWFLAME: + DoCastVictim(SPELL_SHADOWFLAME); + events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); + break; + case EVENT_WINGBUFFET: + DoCastVictim(SPELL_WINGBUFFET); + if (DoGetThreat(me->GetVictim())) + DoModifyThreatByPercent(me->GetVictim(), -75); + events.ScheduleEvent(EVENT_WINGBUFFET, 30s); + break; + case EVENT_FRENZY: + Talk(EMOTE_FRENZY); + DoCast(me, SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 8s, 10s); + break; + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADOWFLAME: - DoCastVictim(SPELL_SHADOWFLAME); - events.ScheduleEvent(EVENT_SHADOWFLAME, 15s, 25s); - break; - case EVENT_WINGBUFFET: - DoCastVictim(SPELL_WINGBUFFET); - if (DoGetThreat(me->GetVictim())) - DoModifyThreatByPercent(me->GetVictim(), -75); - events.ScheduleEvent(EVENT_WINGBUFFET, 30s); - break; - case EVENT_FRENZY: - Talk(EMOTE_FRENZY); - DoCast(me, SPELL_FRENZY); - events.ScheduleEvent(EVENT_FRENZY, 8s, 10s); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + DoMeleeAttackIfReady(); } }; void AddSC_boss_flamegor() { - new boss_flamegor(); + RegisterBlackwingLairCreatureAI(boss_flamegor); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp index 55d3d818e..b3eec7834 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp @@ -214,14 +214,10 @@ struct ClassCallSelector : public Acore::unary_function bool operator()(Unit const* target) const { if (!_me || !target || !target->IsPlayer()) - { return false; - } if (target->getClass() != _targetClass) - { return false; - } return true; } @@ -231,304 +227,291 @@ private: uint8 _targetClass; }; -class boss_victor_nefarius : public CreatureScript +struct boss_victor_nefarius : public BossAI { -public: - boss_victor_nefarius() : CreatureScript("boss_victor_nefarius") { } - - struct boss_victor_nefariusAI : public BossAI + boss_victor_nefarius(Creature* creature) : BossAI(creature, DATA_NEFARIAN) { - boss_victor_nefariusAI(Creature* creature) : BossAI(creature, DATA_NEFARIAN) + Initialize(); + + _nefarianLeftTunnel = instance->GetData(DATA_NEFARIAN_LEFT_TUNNEL); + _nefarianRightTunnel = instance->GetData(DATA_NEFARIAN_RIGHT_TUNNEL); + + if (!_nefarianLeftTunnel || !_nefarianRightTunnel) { - Initialize(); + // Victor Nefarius weekly mechanic drakonid spawn + // Pick 2 drakonids and keep them for the whole save duration (the drakonids can't be repeated). + std::vector nefarianDrakonidSpawners = { NPC_BLACK_SPAWNER, NPC_BLUE_SPAWNER, NPC_BRONZE_SPAWNER, NPC_GREEN_SPAWNER, NPC_RED_SPAWNER }; + Acore::Containers::RandomResize(nefarianDrakonidSpawners, 2); - _nefarianLeftTunnel = instance->GetData(DATA_NEFARIAN_LEFT_TUNNEL); - _nefarianRightTunnel = instance->GetData(DATA_NEFARIAN_RIGHT_TUNNEL); + _nefarianRightTunnel = nefarianDrakonidSpawners[0]; + _nefarianLeftTunnel = nefarianDrakonidSpawners[1]; - if (!_nefarianLeftTunnel || !_nefarianRightTunnel) - { - // Victor Nefarius weekly mechanic drakonid spawn - // Pick 2 drakonids and keep them for the whole save duration (the drakonids can't be repeated). - std::vector nefarianDrakonidSpawners = { NPC_BLACK_SPAWNER, NPC_BLUE_SPAWNER, NPC_BRONZE_SPAWNER, NPC_GREEN_SPAWNER, NPC_RED_SPAWNER }; - Acore::Containers::RandomResize(nefarianDrakonidSpawners, 2); - - _nefarianRightTunnel = nefarianDrakonidSpawners[0]; - _nefarianLeftTunnel = nefarianDrakonidSpawners[1]; - - // save it to instance - instance->SetData(DATA_NEFARIAN_LEFT_TUNNEL, _nefarianLeftTunnel); - instance->SetData(DATA_NEFARIAN_RIGHT_TUNNEL, _nefarianRightTunnel); - } + // save it to instance + instance->SetData(DATA_NEFARIAN_LEFT_TUNNEL, _nefarianLeftTunnel); + instance->SetData(DATA_NEFARIAN_RIGHT_TUNNEL, _nefarianRightTunnel); } + } - void Initialize() + void Initialize() + { + _killedAdds = 0; + } + + void Reset() override + { + Initialize(); + + if (me->GetMapId() == MAP_BLACKWING_LAIR) { - KilledAdds = 0; - } - - void Reset() override - { - Initialize(); - - if (me->GetMapId() == MAP_BLACKWING_LAIR) + if (Creature* nefarian = me->FindNearestCreature(NPC_NEFARIAN, 1000.0f, true)) { - if (Creature* nefarian = me->FindNearestCreature(NPC_NEFARIAN, 1000.0f, true)) + // Nefarian is spawned and he didn't finish his intro path yet, despawn it manually. + if (nefarian->GetMotionMaster()->GetCurrentMovementGeneratorType() == MovementGeneratorType::WAYPOINT_MOTION_TYPE) { - // Nefarian is spawned and he didn't finish his intro path yet, despawn it manually. - if (nefarian->GetMotionMaster()->GetCurrentMovementGeneratorType() == MovementGeneratorType::WAYPOINT_MOTION_TYPE) - { - nefarian->DespawnOrUnsummon(); - } - std::list drakonidBones; - me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE); - for (auto const& bones : drakonidBones) - { - bones->DespawnOrUnsummon(); - } + nefarian->DespawnOrUnsummon(); } - else + std::list drakonidBones; + me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE); + for (auto const& bones : drakonidBones) { - _Reset(); - } - - me->SetVisible(true); - me->SetPhaseMask(1, true); - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->SetFaction(FACTION_FRIENDLY); - me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR); - me->RemoveAura(SPELL_NEFARIANS_BARRIER); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - } - - void JustReachedHome() override - { - Reset(); - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() != NPC_NEFARIAN) - { - BossAI::JustSummoned(summon); - } - } - - void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override - { - if (summon->GetEntry() == NPC_NEFARIAN) - { - summons.DespawnEntry(_nefarianLeftTunnel); - summons.DespawnEntry(_nefarianRightTunnel); - me->KillSelf(); - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_RESET) - { - me->RemoveAura(SPELL_ROOT_SELF); - summons.DespawnAll(); - } - - if (action == ACTION_ADD_KILLED) - { - KilledAdds++; - - if (KilledAdds == MAX_DRAKONID_KILLED) - { - if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn)) - { - nefarian->setActive(true); - nefarian->SetCanFly(true); - nefarian->SetDisableGravity(true); - nefarian->GetMotionMaster()->MoveWaypoint(NEFARIAN_PATH, false); - } - - events.Reset(); - DoCastSelf(SPELL_ROOT_SELF, true); - me->SetVisible(false); - // Stop spawning adds - EntryCheckPredicate pred(_nefarianRightTunnel); - summons.DoAction(ACTION_SPAWNER_STOP, pred); - EntryCheckPredicate pred2(_nefarianLeftTunnel); - summons.DoAction(ACTION_SPAWNER_STOP, pred2); + bones->DespawnOrUnsummon(); } } - } - - void JustDied(Unit* /*killer*/) override - { - instance->SetBossState(DATA_NEFARIAN, DONE); - instance->SaveToDB(); - } - - void BeginEvent() - { - _JustEngagedWith(); - - Talk(SAY_GAMESBEGIN_2); - - DoCast(me, SPELL_NEFARIANS_BARRIER); - me->SetCombatMovement(false); - me->SetImmuneToPC(false); - AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true)); - events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms); - events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s); - events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 13s, 15s); - events.ScheduleEvent(EVENT_FEAR, 10s, 20s); - events.ScheduleEvent(EVENT_SILENCE, 20s, 25s); - events.ScheduleEvent(EVENT_MIND_CONTROL, 30s, 35s); - events.ScheduleEvent(EVENT_SPAWN_ADDS, 10s); - } - - void SetData(uint32 type, uint32 data) override - { - if (type == 1 && data == 1) + else { - me->StopMoving(); - events.ScheduleEvent(EVENT_PATH_2, 9s); + _Reset(); } - if (type == 1 && data == 2) - events.ScheduleEvent(EVENT_SUCCESS_1, 5s); + me->SetVisible(true); + me->SetPhaseMask(1, true); + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetFaction(FACTION_FRIENDLY); + me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR); + me->RemoveAura(SPELL_NEFARIANS_BARRIER); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + } + + void JustReachedHome() override + { + Reset(); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_NEFARIAN) + BossAI::JustSummoned(summon); + } + + void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override + { + if (summon->GetEntry() == NPC_NEFARIAN) + { + summons.DespawnEntry(_nefarianLeftTunnel); + summons.DespawnEntry(_nefarianRightTunnel); + me->KillSelf(); + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_RESET) + { + me->RemoveAura(SPELL_ROOT_SELF); + summons.DespawnAll(); } - void UpdateAI(uint32 diff) override + if (action == ACTION_ADD_KILLED) { - if (!UpdateVictim()) - { - events.Update(diff); + _killedAdds++; - while (uint32 eventId = events.ExecuteEvent()) + if (_killedAdds == MAX_DRAKONID_KILLED) + { + if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn)) { - switch (eventId) - { - case EVENT_PATH_2: - me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_2, false); - events.ScheduleEvent(EVENT_CHAOS_1, 7s); - break; - case EVENT_CHAOS_1: - if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 75.0f, true)) - { - me->SetFacingToObject(gyth); - Talk(SAY_CHAOS_SPELL); - } - events.ScheduleEvent(EVENT_CHAOS_2, 2s); - break; - case EVENT_CHAOS_2: - DoCast(SPELL_CHROMATIC_CHAOS); - me->SetFacingTo(1.570796f); - break; - case EVENT_SUCCESS_1: - if (Unit* player = me->SelectNearestPlayer(60.0f)) - { - me->SetFacingToObject(player); - Talk(SAY_SUCCESS); - if (GameObject* portcullis1 = me->FindNearestGameObject(GO_PORTCULLIS_ACTIVE, 65.0f)) - portcullis1->SetGoState(GO_STATE_ACTIVE); - if (GameObject* portcullis2 = me->FindNearestGameObject(GO_PORTCULLIS_TOBOSSROOMS, 80.0f)) - portcullis2->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_SUCCESS_2, 4s); - break; - case EVENT_SUCCESS_2: - DoCast(me, SPELL_VAELASTRASZZ_SPAWN); - me->DespawnOrUnsummon(1s); - break; - case EVENT_PATH_3: - me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_3, false); - break; - case EVENT_START_EVENT: - BeginEvent(); - break; - default: - break; - } + nefarian->setActive(true); + nefarian->SetCanFly(true); + nefarian->SetDisableGravity(true); + nefarian->GetMotionMaster()->MoveWaypoint(NEFARIAN_PATH, false); } + + events.Reset(); + DoCastSelf(SPELL_ROOT_SELF, true); + me->SetVisible(false); + // Stop spawning adds + EntryCheckPredicate pred(_nefarianRightTunnel); + summons.DoAction(ACTION_SPAWNER_STOP, pred); + EntryCheckPredicate pred2(_nefarianLeftTunnel); + summons.DoAction(ACTION_SPAWNER_STOP, pred2); + } + } + } + + void JustDied(Unit* /*killer*/) override + { + instance->SetBossState(DATA_NEFARIAN, DONE); + instance->SaveToDB(); + } + + void BeginEvent() + { + _JustEngagedWith(); + + Talk(SAY_GAMESBEGIN_2); + + DoCast(me, SPELL_NEFARIANS_BARRIER); + me->SetCombatMovement(false); + me->SetImmuneToPC(false); + AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true)); + events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms); + events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s); + events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 13s, 15s); + events.ScheduleEvent(EVENT_FEAR, 10s, 20s); + events.ScheduleEvent(EVENT_SILENCE, 20s, 25s); + events.ScheduleEvent(EVENT_MIND_CONTROL, 30s, 35s); + events.ScheduleEvent(EVENT_SPAWN_ADDS, 10s); + } + + void SetData(uint32 type, uint32 data) override + { + if (type == 1 && data == 1) + { + me->StopMoving(); + events.ScheduleEvent(EVENT_PATH_2, 9s); + } + + if (type == 1 && data == 2) + events.ScheduleEvent(EVENT_SUCCESS_1, 5s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PATH_2: + me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_2, false); + events.ScheduleEvent(EVENT_CHAOS_1, 7s); + break; + case EVENT_CHAOS_1: + if (Creature* gyth = me->FindNearestCreature(NPC_GYTH, 75.0f, true)) + { + me->SetFacingToObject(gyth); + Talk(SAY_CHAOS_SPELL); + } + events.ScheduleEvent(EVENT_CHAOS_2, 2s); + break; + case EVENT_CHAOS_2: + DoCast(SPELL_CHROMATIC_CHAOS); + me->SetFacingTo(1.570796f); + break; + case EVENT_SUCCESS_1: + if (Unit* player = me->SelectNearestPlayer(60.0f)) + { + me->SetFacingToObject(player); + Talk(SAY_SUCCESS); + if (GameObject* portcullis1 = me->FindNearestGameObject(GO_PORTCULLIS_ACTIVE, 65.0f)) + portcullis1->SetGoState(GO_STATE_ACTIVE); + if (GameObject* portcullis2 = me->FindNearestGameObject(GO_PORTCULLIS_TOBOSSROOMS, 80.0f)) + portcullis2->SetGoState(GO_STATE_ACTIVE); + } + events.ScheduleEvent(EVENT_SUCCESS_2, 4s); + break; + case EVENT_SUCCESS_2: + DoCast(me, SPELL_VAELASTRASZZ_SPAWN); + me->DespawnOrUnsummon(1s); + break; + case EVENT_PATH_3: + me->GetMotionMaster()->MoveWaypoint(NEFARIUS_PATH_3, false); + break; + case EVENT_START_EVENT: + BeginEvent(); + break; + default: + break; + } + } + return; + } + + // Only do this if we haven't spawned nefarian yet + if (UpdateVictim() && _killedAdds <= MAX_DRAKONID_KILLED) + { + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - } - // Only do this if we haven't spawned nefarian yet - if (UpdateVictim() && KilledAdds <= MAX_DRAKONID_KILLED) + while (uint32 eventId = events.ExecuteEvent()) { - events.Update(diff); + switch (eventId) + { + case EVENT_SHADOW_BOLT: + DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f); + events.ScheduleEvent(EVENT_SHADOW_BOLT, 2s, 4s); + break; + case EVENT_SHADOW_BOLT_VOLLEY: + DoCastAOE(SPELL_SHADOWBOLT_VOLLEY); + events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 19s, 25s); + break; + case EVENT_FEAR: + DoCastRandomTarget(SPELL_FEAR, 0, 40.0f); + events.ScheduleEvent(EVENT_FEAR, 10s, 20s); + break; + case EVENT_SILENCE: + DoCastRandomTarget(SPELL_SILENCE, 0, 150.f); + events.ScheduleEvent(EVENT_SILENCE, 14s,23s); + break; + case EVENT_MIND_CONTROL: + DoCastRandomTarget(SPELL_SHADOW_COMMAND, 0, 40.0f); + events.ScheduleEvent(EVENT_MIND_CONTROL, 24s, 30s); + break; + case EVENT_SHADOWBLINK: + DoCastSelf(SPELL_SHADOWBLINK); + events.ScheduleEvent(EVENT_SHADOWBLINK, 30s, 40s); + break; + case EVENT_SPAWN_ADDS: + // Spawn the spawners. + me->SummonCreature(_nefarianLeftTunnel, spawnerPositions[0]); + me->SummonCreature(_nefarianRightTunnel, spawnerPositions[1]); + break; + } if (me->HasUnitState(UNIT_STATE_CASTING)) return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHADOW_BOLT: - DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f); - events.ScheduleEvent(EVENT_SHADOW_BOLT, 2s, 4s); - break; - case EVENT_SHADOW_BOLT_VOLLEY: - DoCastAOE(SPELL_SHADOWBOLT_VOLLEY); - events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 19s, 25s); - break; - case EVENT_FEAR: - DoCastRandomTarget(SPELL_FEAR, 0, 40.0f); - events.ScheduleEvent(EVENT_FEAR, 10s, 20s); - break; - case EVENT_SILENCE: - DoCastRandomTarget(SPELL_SILENCE, 0, 150.f); - events.ScheduleEvent(EVENT_SILENCE, 14s,23s); - break; - case EVENT_MIND_CONTROL: - DoCastRandomTarget(SPELL_SHADOW_COMMAND, 0, 40.0f); - events.ScheduleEvent(EVENT_MIND_CONTROL, 24s, 30s); - break; - case EVENT_SHADOWBLINK: - DoCastSelf(SPELL_SHADOWBLINK); - events.ScheduleEvent(EVENT_SHADOWBLINK, 30s, 40s); - break; - case EVENT_SPAWN_ADDS: - // Spawn the spawners. - me->SummonCreature(_nefarianLeftTunnel, spawnerPositions[0]); - me->SummonCreature(_nefarianRightTunnel, spawnerPositions[1]); - break; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } } } - - void sGossipSelect(Player* player, uint32 sender, uint32 action) override - { - if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID) - { - // pussywizard: - InstanceScript* instance = player->GetInstanceScript(); - if (!instance || instance->GetBossState(DATA_NEFARIAN) == DONE) - return; - - CloseGossipMenuFor(player); - Talk(SAY_GAMESBEGIN_1); - events.ScheduleEvent(EVENT_START_EVENT, 4s); - me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(true); - } - } - - private: - uint32 KilledAdds; - uint32 _nefarianRightTunnel; - uint32 _nefarianLeftTunnel; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); } + + void sGossipSelect(Player* player, uint32 sender, uint32 action) override + { + if (sender == GOSSIP_ID && action == GOSSIP_OPTION_ID) + { + // pussywizard: + InstanceScript* instance = player->GetInstanceScript(); + if (!instance || instance->GetBossState(DATA_NEFARIAN) == DONE) + return; + + CloseGossipMenuFor(player); + Talk(SAY_GAMESBEGIN_1); + events.ScheduleEvent(EVENT_START_EVENT, 4s); + me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(true); + } + } + +private: + uint32 _killedAdds; + uint32 _nefarianRightTunnel; + uint32 _nefarianLeftTunnel; }; struct boss_nefarian : public BossAI @@ -545,12 +528,8 @@ struct boss_nefarian : public BossAI { _Reset(); if (Creature* victor = me->FindNearestCreature(NPC_VICTOR_NEFARIUS, 200.f, true)) - { if (victor->AI()) - { victor->AI()->DoAction(ACTION_RESET); - } - } me->DespawnOrUnsummon(); } @@ -578,9 +557,7 @@ struct boss_nefarian : public BossAI void KilledUnit(Unit* victim) override { if (rand32() % 5) - { return; - } Talk(SAY_SLAY, victim); } @@ -588,14 +565,10 @@ struct boss_nefarian : public BossAI void MovementInform(uint32 type, uint32 id) override { if (type != WAYPOINT_MOTION_TYPE) - { return; - } if (id == 4) - { Talk(SAY_INTRO); - } if (id == 6) { @@ -617,9 +590,7 @@ struct boss_nefarian : public BossAI me->SetReactState(REACT_AGGRESSIVE); DoZoneInCombat(); if (me->GetVictim()) - { AttackStart(me->GetVictim()); - } events.ScheduleEvent(EVENT_SHADOWFLAME, 12s); events.ScheduleEvent(EVENT_FEAR, 25s, 35s); @@ -633,16 +604,12 @@ struct boss_nefarian : public BossAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } while (uint32 eventId = events.ExecuteEvent()) { @@ -671,16 +638,10 @@ struct boss_nefarian : public BossAI break; case EVENT_CLASSCALL: if (classesPresent.empty()) - { for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList()) - { if (Unit* victim = ref->GetVictim()) - { if (victim->IsPlayer()) classesPresent.insert(victim->getClass()); - } - } - } uint8 targetClass = Acore::Containers::SelectRandomContainerElement(classesPresent); @@ -731,9 +692,7 @@ struct boss_nefarian : public BossAI me->GetMap()->DoForAllPlayers([&](Player* p) { if (!p->IsGameMaster()) - { me->CastSpell(p, SPELL_DEATH_KNIGHT, true); - } }); break; default: @@ -745,9 +704,7 @@ struct boss_nefarian : public BossAI } if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } } DoMeleeAttackIfReady(); @@ -783,9 +740,7 @@ struct npc_corrupted_totem : public ScriptedAI { me->AddUnitState(UNIT_STATE_ROOT); if (!me->HasAura(SPELL_ROOT_SELF)) - { me->AddAura(SPELL_ROOT_SELF, me); - } me->AddAura(AURA_AVOIDANCE, me); scheduler.CancelAll(); @@ -809,9 +764,7 @@ struct npc_corrupted_totem : public ScriptedAI } if (!spellId) - { return; - } std::vector mobsEntries = { @@ -835,25 +788,19 @@ struct npc_corrupted_totem : public ScriptedAI tmpMobList.pop_front(); if (!curr->IsAlive()) - { continue; - } if (apply && me->IsAlive()) { if (me->IsWithinDistInMap(curr, 40.f)) { if (!curr->HasAura(spellId)) - { curr->AddAura(spellId, curr); - } } else { if (curr->HasAura(spellId)) - { curr->RemoveAurasDueToSpell(spellId); - } } } else @@ -899,9 +846,7 @@ struct npc_corrupted_totem : public ScriptedAI void JustDied(Unit* /*killer*/) override { if (me->GetEntry() != NPC_TOTEM_C_FIRE_NOVA) - { SetAura(false); - } scheduler.CancelAll(); } @@ -909,9 +854,7 @@ struct npc_corrupted_totem : public ScriptedAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } scheduler.Update(diff); } @@ -952,9 +895,7 @@ struct npc_drakonid_spawner : public ScriptedAI void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override { if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner)) - { victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED); - } ObjectGuid summonGuid = summon->GetGUID(); @@ -1002,15 +943,11 @@ class spell_class_call_handler : public SpellScript { Player const* player = target->ToPlayer(); if (!player || player->IsClass(CLASS_DEATH_KNIGHT)) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x - { return true; - } auto it = classCallSpells.find(spellInfo->Id); if (it != classCallSpells.end()) // should never happen but only to be sure. - { return target->ToPlayer()->getClass() != it->second; - } return false; }); @@ -1022,9 +959,7 @@ class spell_class_call_handler : public SpellScript Unit* caster = GetCaster(); Unit* target = GetHitUnit(); if (!caster || !target) - { return; - } Position tp = caster->GetFirstCollisionPosition(5.f, 0.f); target->NearTeleportTo(tp.GetPositionX(), tp.GetPositionY(), tp.GetPositionZ(), tp.GetOrientation()); @@ -1033,9 +968,7 @@ class spell_class_call_handler : public SpellScript void HandleOnHitWarlock() { if (Unit* target = GetHitUnit()) - { target->CastSpell(target, SPELL_SUMMON_INFERNALS, true); - } } void Register() override @@ -1065,9 +998,7 @@ class aura_class_call_wild_magic : public AuraScript void HandlePeriodic(AuraEffect const* /*aurEff*/) { if (!GetTarget()) - { return; - } GetTarget()->CastSpell(GetTarget(), SPELL_POLYMORPH, true); } @@ -1092,12 +1023,8 @@ class aura_class_call_siphon_blessing : public AuraScript PreventDefaultAction(); if (Unit* target = GetTarget()) - { if (Unit* nefarian = target->FindNearestCreature(NPC_NEFARIAN, 100.f)) - { target->CastSpell(nefarian, SPELL_BLESSING_PROTECTION, true); - } - } } void Register() override @@ -1154,9 +1081,7 @@ class spell_corrupted_totems : public SpellScript { PreventHitDefaultEffect(effIndex); if (!GetCaster()) - { return; - } std::list spellList = { SPELL_CORRUPTED_FIRE_NOVA_TOTEM, SPELL_CORRUPTED_HEALING_TOTEM, SPELL_CORRUPTED_STONESKIN_TOTEM, SPELL_CORRUPTED_WINDFURY_TOTEM }; uint32 spellId = Acore::Containers::SelectRandomContainerElement(spellList); @@ -1207,15 +1132,11 @@ class spell_shadowblink : public SpellScript { Unit* caster = GetCaster(); if (!caster || !caster->ToCreature() || !caster->ToCreature()->AI()) - { return; - } Unit* target = caster->ToCreature()->AI()->SelectTarget(SelectTargetMethod::Random, 0, 200.f, true); if (!target) - { return; - } for (auto& itr : spellPos) { @@ -1252,9 +1173,7 @@ class spell_spawn_drakonid : public SpellScript { Unit* caster = GetCaster(); if (!caster) - { return; - } caster->CastSpell(caster, spawnerSpells[caster->GetEntry()], true); } @@ -1267,7 +1186,7 @@ class spell_spawn_drakonid : public SpellScript void AddSC_boss_nefarian() { - new boss_victor_nefarius(); + RegisterBlackwingLairCreatureAI(boss_victor_nefarius); RegisterCreatureAI(boss_nefarian); RegisterCreatureAI(npc_corrupted_totem); RegisterCreatureAI(npc_drakonid_spawner); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp index c17fd24f2..40d801ae0 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp @@ -16,6 +16,8 @@ */ #include "CreatureScript.h" +#include "GameObject.h" +#include "GameObjectAI.h" #include "GameObjectScript.h" #include "Player.h" #include "ScriptedCreature.h" @@ -70,214 +72,190 @@ enum EVENTS EVENT_CONFLAGRATION = 4 }; -class boss_razorgore : public CreatureScript +struct boss_razorgore : public BossAI { -public: - boss_razorgore() : CreatureScript("boss_razorgore") { } + boss_razorgore(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { } - struct boss_razorgoreAI : public BossAI + void Reset() override { - boss_razorgoreAI(Creature* creature) : BossAI(creature, DATA_RAZORGORE_THE_UNTAMED) { } - - void Reset() override - { - _Reset(); - _charmerGUID.Clear(); - secondPhase = false; - summons.DespawnAll(); - instance->SetData(DATA_EGG_EVENT, NOT_STARTED); - } - - void JustDied(Unit* /*killer*/) override - { - if (secondPhase) - { - _JustDied(); - } - else - { - // Respawn shorty in case of failure during phase 1. - me->SetCorpseRemoveTime(25); - me->SetRespawnTime(30); - me->SaveRespawnTime(); - - // Might not be required, safe measure. - me->SetLootRecipient(nullptr); - - instance->SetData(DATA_EGG_EVENT, FAIL); - } - } - - bool CanAIAttack(Unit const* target) const override - { - return !(target->IsCreature() && !secondPhase); - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - - events.ScheduleEvent(EVENT_CLEAVE, 15s); - events.ScheduleEvent(EVENT_STOMP, 35s); - events.ScheduleEvent(EVENT_FIREBALL, 7s); - events.ScheduleEvent(EVENT_CONFLAGRATION, 12s); - - instance->SetData(DATA_EGG_EVENT, IN_PROGRESS); - } - - void DoChangePhase() - { - secondPhase = true; - _charmerGUID.Clear(); - me->RemoveAllAuras(); - - DoCastSelf(SPELL_WARMING_FLAMES, true); - - if (Creature* troops = instance->GetCreature(DATA_NEFARIAN_TROOPS)) - { - troops->AI()->Talk(EMOTE_TROOPS_RETREAT); - } - - for (ObjectGuid const& guid : _summonGUIDS) - { - if (Creature* creature = ObjectAccessor::GetCreature(*me, guid)) - { - if (creature->IsAlive()) - { - creature->CombatStop(true); - creature->SetReactState(REACT_PASSIVE); - creature->GetMotionMaster()->MovePoint(0, Position(-7560.568848f, -1028.553345f, 408.491211f, 0.523858f)); - } - } - } - } - - void SetGUID(ObjectGuid const& guid, int32 /*id*/) override - { - _charmerGUID = guid; - } - - void OnCharmed(bool apply) override - { - if (apply) - { - if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) - { - charmer->CastSpell(charmer, SPELL_MIND_EXHAUSTION, true); - charmer->CastSpell(me, SPELL_MINDCONTROL_VISUAL, false); - } - } - else - { - if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) - { - charmer->RemoveAurasDueToSpell(SPELL_MINDCONTROL_VISUAL); - me->EngageWithTarget(charmer); - me->AddThreat(charmer, 100.0f); - me->AI()->AttackStart(charmer); - } - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_PHASE_TWO) - { - DoChangePhase(); - } - - if (action == TALK_EGG_BROKEN_RAND) - { - Talk(urand(SAY_EGGS_BROKEN1, SAY_EGGS_BROKEN3)); - } - } - - void JustSummoned(Creature* summon) override - { - _summonGUIDS.push_back(summon->GetGUID()); - summon->SetOwnerGUID(me->GetGUID()); - summons.Summon(summon); - } - - void SummonMovementInform(Creature* summon, uint32 movementType, uint32 /*pathId*/) override - { - if (movementType == POINT_MOTION_TYPE) - { - summon->DespawnOrUnsummon(); - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (!secondPhase && damage >= me->GetHealth()) - { - Talk(SAY_DEATH); - DoCastAOE(SPELL_EXPLODE_ORB); - DoCastAOE(SPELL_EXPLOSION); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (!me->IsCharmed()) - { - events.Update(diff); - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_CLEAVE: - DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, 7s, 10s); - break; - case EVENT_STOMP: - DoCastVictim(SPELL_WARSTOMP); - events.ScheduleEvent(EVENT_STOMP, 15s, 25s); - break; - case EVENT_FIREBALL: - DoCastVictim(SPELL_FIREBALLVOLLEY); - events.ScheduleEvent(EVENT_FIREBALL, 12s, 15s); - break; - case EVENT_CONFLAGRATION: - DoCastVictim(SPELL_CONFLAGRATION); - events.ScheduleEvent(EVENT_CONFLAGRATION, 30s); - break; - } - } - - DoMeleeAttackIfReady(); - } - - private: - bool secondPhase; - ObjectGuid _charmerGUID; - GuidVector _summonGUIDS; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + _Reset(); + _charmerGUID.Clear(); + secondPhase = false; + summons.DespawnAll(); + instance->SetData(DATA_EGG_EVENT, NOT_STARTED); } + + void JustDied(Unit* /*killer*/) override + { + if (secondPhase) + { + _JustDied(); + } + else + { + // Respawn shorty in case of failure during phase 1. + me->SetCorpseRemoveTime(25); + me->SetRespawnTime(30); + me->SaveRespawnTime(); + + // Might not be required, safe measure. + me->SetLootRecipient(nullptr); + + instance->SetData(DATA_EGG_EVENT, FAIL); + } + } + + bool CanAIAttack(Unit const* target) const override + { + return !(target->IsCreature() && !secondPhase); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + + events.ScheduleEvent(EVENT_CLEAVE, 15s); + events.ScheduleEvent(EVENT_STOMP, 35s); + events.ScheduleEvent(EVENT_FIREBALL, 7s); + events.ScheduleEvent(EVENT_CONFLAGRATION, 12s); + + instance->SetData(DATA_EGG_EVENT, IN_PROGRESS); + } + + void DoChangePhase() + { + secondPhase = true; + _charmerGUID.Clear(); + me->RemoveAllAuras(); + + DoCastSelf(SPELL_WARMING_FLAMES, true); + + if (Creature* troops = instance->GetCreature(DATA_NEFARIAN_TROOPS)) + troops->AI()->Talk(EMOTE_TROOPS_RETREAT); + + for (ObjectGuid const& guid : _summonGUIDS) + { + if (Creature* creature = ObjectAccessor::GetCreature(*me, guid)) + if (creature->IsAlive()) + { + creature->CombatStop(true); + creature->SetReactState(REACT_PASSIVE); + creature->GetMotionMaster()->MovePoint(0, Position(-7560.568848f, -1028.553345f, 408.491211f, 0.523858f)); + } + } + } + + void SetGUID(ObjectGuid const& guid, int32 /*id*/) override + { + _charmerGUID = guid; + } + + void OnCharmed(bool apply) override + { + if (apply) + { + if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) + { + charmer->CastSpell(charmer, SPELL_MIND_EXHAUSTION, true); + charmer->CastSpell(me, SPELL_MINDCONTROL_VISUAL, false); + } + } + else + { + if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID)) + { + charmer->RemoveAurasDueToSpell(SPELL_MINDCONTROL_VISUAL); + me->EngageWithTarget(charmer); + me->AddThreat(charmer, 100.0f); + me->AI()->AttackStart(charmer); + } + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_PHASE_TWO) + DoChangePhase(); + + if (action == TALK_EGG_BROKEN_RAND) + Talk(urand(SAY_EGGS_BROKEN1, SAY_EGGS_BROKEN3)); + } + + void JustSummoned(Creature* summon) override + { + _summonGUIDS.push_back(summon->GetGUID()); + summon->SetOwnerGUID(me->GetGUID()); + summons.Summon(summon); + } + + void SummonMovementInform(Creature* summon, uint32 movementType, uint32 /*pathId*/) override + { + if (movementType == POINT_MOTION_TYPE) + summon->DespawnOrUnsummon(); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!secondPhase && damage >= me->GetHealth()) + { + Talk(SAY_DEATH); + DoCastAOE(SPELL_EXPLODE_ORB); + DoCastAOE(SPELL_EXPLOSION); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (!me->IsCharmed()) + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 7s, 10s); + break; + case EVENT_STOMP: + DoCastVictim(SPELL_WARSTOMP); + events.ScheduleEvent(EVENT_STOMP, 15s, 25s); + break; + case EVENT_FIREBALL: + DoCastVictim(SPELL_FIREBALLVOLLEY); + events.ScheduleEvent(EVENT_FIREBALL, 12s, 15s); + break; + case EVENT_CONFLAGRATION: + DoCastVictim(SPELL_CONFLAGRATION); + events.ScheduleEvent(EVENT_CONFLAGRATION, 30s); + break; + } + } + + DoMeleeAttackIfReady(); + } + +private: + bool secondPhase; + ObjectGuid _charmerGUID; + GuidVector _summonGUIDS; }; -class go_orb_of_domination : public GameObjectScript +struct go_orb_of_domination : public GameObjectAI { -public: - go_orb_of_domination() : GameObjectScript("go_orb_of_domination") { } + go_orb_of_domination(GameObject* go) : GameObjectAI(go) { } - bool OnGossipHello(Player* player, GameObject* go) override + bool GossipHello(Player* player, bool /*reportUse*/) override { - if (InstanceScript* instance = go->GetInstanceScript()) + if (InstanceScript* instance = me->GetInstanceScript()) if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION) && !player->GetPet()) - if (Creature* razor = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED))) + if (Creature* razor = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED))) { razor->AI()->SetGUID(player->GetGUID()); razor->Attack(player, true); @@ -294,12 +272,9 @@ class spell_egg_event : public SpellScript void HandleOnHit() { if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - { instance->SetData(DATA_EGG_EVENT, SPECIAL); - } if (Creature* razorgore = GetCaster()->ToCreature()) - { if (GameObject* egg = GetHitGObj()) { razorgore->AI()->DoAction(TALK_EGG_BROKEN_RAND); @@ -307,7 +282,6 @@ class spell_egg_event : public SpellScript egg->UseDoorOrButton(10000); egg->SetRespawnTime(WEEK); } - } } void Register() override @@ -318,7 +292,7 @@ class spell_egg_event : public SpellScript void AddSC_boss_razorgore() { - new boss_razorgore(); - new go_orb_of_domination(); + RegisterBlackwingLairCreatureAI(boss_razorgore); + RegisterBlackwingLairGameObjectAI(go_orb_of_domination); RegisterSpellScript(spell_egg_event); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp index 3cfbf13e4..1980d0ba9 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp @@ -72,227 +72,214 @@ enum Events EVENT_BURNING_ADRENALINE = 12, }; -class boss_vaelastrasz : public CreatureScript +struct boss_vaelastrasz : public BossAI { -public: - boss_vaelastrasz() : CreatureScript("boss_vaelastrasz") { } - - struct boss_vaelAI : public BossAI + boss_vaelastrasz(Creature* creature) : BossAI(creature, DATA_VAELASTRAZ_THE_CORRUPT) { - boss_vaelAI(Creature* creature) : BossAI(creature, DATA_VAELASTRAZ_THE_CORRUPT) + Initialize(); + } + + void Initialize() + { + PlayerGUID.Clear(); + HasYelled = false; + _introDone = false; + _burningAdrenalineCast = 0; + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); + me->SetFaction(FACTION_FRIENDLY); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + + void Reset() override + { + _Reset(); + me->SetHealth(me->CountPctFromMaxHealth(30)); + + if (!_introDone) { + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetReactState(REACT_PASSIVE); Initialize(); + _eventsIntro.Reset(); } - - void Initialize() + else { - PlayerGUID.Clear(); HasYelled = false; - _introDone = false; _burningAdrenalineCast = 0; - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); - me->SetFaction(FACTION_FRIENDLY); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); } + } - void Reset() override + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + + DoCastAOE(SPELL_ESSENCE_OF_THE_RED); + // now drop damage requirement to be able to take loot + me->ResetPlayerDamageReq(); + + events.ScheduleEvent(EVENT_CLEAVE, 10s); + events.ScheduleEvent(EVENT_FLAME_BREATH, 15s); + events.ScheduleEvent(EVENT_FIRE_NOVA, 5s); + events.ScheduleEvent(EVENT_TAIL_SWEEP, 11s); + events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s); + } + + void BeginSpeech(Unit* target) + { + PlayerGUID = target->GetGUID(); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_1, 1s); + } + + void KilledUnit(Unit* victim) override + { + if (rand32() % 5) + return; + + Talk(SAY_KILLTARGET, victim); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + _eventsIntro.Update(diff); + + // Speech + if (!_introDone) { - _Reset(); - me->SetHealth(me->CountPctFromMaxHealth(30)); - - if (!_introDone) - { - me->SetStandState(UNIT_STAND_STATE_DEAD); - me->SetReactState(REACT_PASSIVE); - Initialize(); - _eventsIntro.Reset(); - } - else - { - HasYelled = false; - _burningAdrenalineCast = 0; - } - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - - DoCastAOE(SPELL_ESSENCE_OF_THE_RED); - // now drop damage requirement to be able to take loot - me->ResetPlayerDamageReq(); - - events.ScheduleEvent(EVENT_CLEAVE, 10s); - events.ScheduleEvent(EVENT_FLAME_BREATH, 15s); - events.ScheduleEvent(EVENT_FIRE_NOVA, 5s); - events.ScheduleEvent(EVENT_TAIL_SWEEP, 11s); - events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s); - } - - void BeginSpeech(Unit* target) - { - PlayerGUID = target->GetGUID(); - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_1, 1s); - } - - void KilledUnit(Unit* victim) override - { - if (rand32() % 5) - return; - - Talk(SAY_KILLTARGET, victim); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - _eventsIntro.Update(diff); - - // Speech - if (!_introDone) - { - while (uint32 eventId = _eventsIntro.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SPEECH_1: - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SummonCreature(NPC_VICTOR_NEFARIUS, aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], aNefariusSpawnLoc[2], aNefariusSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 26000); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_2, 1s); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_SPEECH_2: - if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid)) - { - nefarius->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY); - nefarius->Yell(SAY_NEFARIAN_VAEL_INTRO); - nefarius->SetStandState(UNIT_STAND_STATE_STAND); - } - _eventsIntro.ScheduleEvent(EVENT_SPEECH_3, 18s); - break; - case EVENT_SPEECH_3: - if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid)) - nefarius->CastSpell(me, SPELL_RED_LIGHTNING, TRIGGERED_NONE); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_4, 2s); - break; - case EVENT_SPEECH_4: - Talk(SAY_LINE1); - me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_5, 12s); - break; - case EVENT_SPEECH_5: - Talk(SAY_LINE2); - me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_6, 12s); - break; - case EVENT_SPEECH_6: - Talk(SAY_LINE3); - me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - _eventsIntro.ScheduleEvent(EVENT_SPEECH_7, 17s); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_SPEECH_7: - me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); - if (PlayerGUID && ObjectAccessor::GetUnit(*me, PlayerGUID)) - AttackStart(ObjectAccessor::GetUnit(*me, PlayerGUID)); - me->SetReactState(REACT_AGGRESSIVE); - _introDone = true; - break; - } - } - } - - if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) + while (uint32 eventId = _eventsIntro.ExecuteEvent()) { switch (eventId) { - case EVENT_CLEAVE: - events.ScheduleEvent(EVENT_CLEAVE, 15s); - DoCastVictim(SPELL_CLEAVE); + case EVENT_SPEECH_1: + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SummonCreature(NPC_VICTOR_NEFARIUS, aNefariusSpawnLoc[0], aNefariusSpawnLoc[1], aNefariusSpawnLoc[2], aNefariusSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 26000); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_2, 1s); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); break; - case EVENT_FLAME_BREATH: - DoCastVictim(SPELL_FLAME_BREATH); - events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 14s); - break; - case EVENT_FIRE_NOVA: - DoCastVictim(SPELL_FIRE_NOVA); - events.ScheduleEvent(EVENT_FIRE_NOVA, 3s, 5s); - break; - case EVENT_TAIL_SWEEP: - DoCastAOE(SPELL_TAIL_SWEEP); - events.ScheduleEvent(EVENT_TAIL_SWEEP, 15s); - break; - case EVENT_BURNING_ADRENALINE: - { - if (_burningAdrenalineCast < 2) // It's better to use TaskScheduler for this, but zzz + case EVENT_SPEECH_2: + if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid)) { - //selects a random target that isn't the current victim and is a mana user (selects mana users) but not pets - //it also ignores targets who have the aura. We don't want to place the debuff on the same target twice. - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA && !u->HasAura(SPELL_BURNING_ADRENALINE) && u != me->GetVictim(); })) - { - me->CastSpell(target, SPELL_BURNING_ADRENALINE, true); - } - - _burningAdrenalineCast++; + nefarius->CastSpell(me, SPELL_NEFARIUS_CORRUPTION, TRIGGERED_CAST_DIRECTLY); + nefarius->Yell(SAY_NEFARIAN_VAEL_INTRO); + nefarius->SetStandState(UNIT_STAND_STATE_STAND); } - else - { - me->CastSpell(me->GetVictim(), SPELL_BURNING_ADRENALINE, true); - _burningAdrenalineCast = 0; - } - events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_3, 18s); + break; + case EVENT_SPEECH_3: + if (Creature* nefarius = me->GetMap()->GetCreature(m_nefariusGuid)) + nefarius->CastSpell(me, SPELL_RED_LIGHTNING, TRIGGERED_NONE); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_4, 2s); + break; + case EVENT_SPEECH_4: + Talk(SAY_LINE1); + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_5, 12s); + break; + case EVENT_SPEECH_5: + Talk(SAY_LINE2); + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_6, 12s); + break; + case EVENT_SPEECH_6: + Talk(SAY_LINE3); + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + _eventsIntro.ScheduleEvent(EVENT_SPEECH_7, 17s); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_SPEECH_7: + me->SetFaction(FACTION_DRAGONFLIGHT_BLACK); + if (PlayerGUID && ObjectAccessor::GetUnit(*me, PlayerGUID)) + AttackStart(ObjectAccessor::GetUnit(*me, PlayerGUID)); + me->SetReactState(REACT_AGGRESSIVE); + _introDone = true; break; - } } } - - // Yell if hp lower than 15% - if (HealthBelowPct(15) && !HasYelled) - { - Talk(SAY_HALFLIFE); - HasYelled = true; - } - - DoMeleeAttackIfReady(); } - void JustSummoned(Creature* summoned) override + if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) { - if (summoned->GetEntry() == NPC_VICTOR_NEFARIUS) + switch (eventId) { - // Set not selectable, so players won't interact with it - summoned->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - m_nefariusGuid = summoned->GetGUID(); + case EVENT_CLEAVE: + events.ScheduleEvent(EVENT_CLEAVE, 15s); + DoCastVictim(SPELL_CLEAVE); + break; + case EVENT_FLAME_BREATH: + DoCastVictim(SPELL_FLAME_BREATH); + events.ScheduleEvent(EVENT_FLAME_BREATH, 8s, 14s); + break; + case EVENT_FIRE_NOVA: + DoCastVictim(SPELL_FIRE_NOVA); + events.ScheduleEvent(EVENT_FIRE_NOVA, 3s, 5s); + break; + case EVENT_TAIL_SWEEP: + DoCastAOE(SPELL_TAIL_SWEEP); + events.ScheduleEvent(EVENT_TAIL_SWEEP, 15s); + break; + case EVENT_BURNING_ADRENALINE: + { + if (_burningAdrenalineCast < 2) // It's better to use TaskScheduler for this, but zzz + { + //selects a random target that isn't the current victim and is a mana user (selects mana users) but not pets + //it also ignores targets who have the aura. We don't want to place the debuff on the same target twice. + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA && !u->HasAura(SPELL_BURNING_ADRENALINE) && u != me->GetVictim(); })) + me->CastSpell(target, SPELL_BURNING_ADRENALINE, true); + + _burningAdrenalineCast++; + } + else + { + me->CastSpell(me->GetVictim(), SPELL_BURNING_ADRENALINE, true); + _burningAdrenalineCast = 0; + } + events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15s); + break; + } } } - void sGossipSelect(Player* player, uint32 sender, uint32 action) override + // Yell if hp lower than 15% + if (HealthBelowPct(15) && !HasYelled) { - if (sender == GOSSIP_ID && action == 0) - { - CloseGossipMenuFor(player); - BeginSpeech(player); - } + Talk(SAY_HALFLIFE); + HasYelled = true; } - private: - ObjectGuid PlayerGUID; - ObjectGuid m_nefariusGuid; - bool HasYelled; - bool _introDone; - EventMap _eventsIntro; - uint8 _burningAdrenalineCast; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBlackwingLairAI(creature); + DoMeleeAttackIfReady(); } + + void JustSummoned(Creature* summoned) override + { + if (summoned->GetEntry() == NPC_VICTOR_NEFARIUS) + { + // Set not selectable, so players won't interact with it + summoned->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + m_nefariusGuid = summoned->GetGUID(); + } + } + + void sGossipSelect(Player* player, uint32 sender, uint32 action) override + { + if (sender == GOSSIP_ID && action == 0) + { + CloseGossipMenuFor(player); + BeginSpeech(player); + } + } + +private: + ObjectGuid PlayerGUID; + ObjectGuid m_nefariusGuid; + bool HasYelled; + bool _introDone; + EventMap _eventsIntro; + uint8 _burningAdrenalineCast; }; // 18173 - Burning Adrenaline @@ -308,9 +295,7 @@ class spell_vael_burning_adrenaline : public AuraScript void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (!GetTarget()) - { return; - } // Do the explosion, then kill the target. GetTarget()->CastSpell(GetTarget(), SPELL_BURNING_ADRENALINE_EXPLOSION, true); @@ -325,6 +310,6 @@ class spell_vael_burning_adrenaline : public AuraScript void AddSC_boss_vaelastrasz() { - new boss_vaelastrasz(); + RegisterBlackwingLairCreatureAI(boss_vaelastrasz); RegisterSpellScript(spell_vael_burning_adrenaline); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp index 2dfb99fc4..a77af22d0 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -72,404 +72,355 @@ Position const SummonPosition[8] = uint32 const Entry[3] = { 12422, 12416, 12420 }; -class instance_blackwing_lair : public InstanceMapScript +struct instance_blackwing_lair : public InstanceScript { -public: - instance_blackwing_lair() : InstanceMapScript(BWLScriptName, MAP_BLACKWING_LAIR) { } - - struct instance_blackwing_lair_InstanceMapScript : public InstanceScript + instance_blackwing_lair(Map* map) : InstanceScript(map) { - instance_blackwing_lair_InstanceMapScript(Map* map) : InstanceScript(map) + SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadDoorData(doorData); + LoadObjectData(creatureData, objectData); + } + + void Initialize() override + { + // Razorgore + EggCount = 0; + EggEvent = 0; + NefarianLeftTunnel = 0; + NefarianRightTunnel = 0; + addsCount.fill(0); + } + + void OnCreatureCreate(Creature* creature) override + { + // This is required because the tempspawn at Vael overwrites his GUID. + if (creature->GetEntry() == NPC_VICTOR_NEFARIUS && creature->ToTempSummon()) + return; + + InstanceScript::OnCreatureCreate(creature); + + switch (creature->GetEntry()) { - SetHeaders(DataHeader); - SetBossNumber(EncounterCount); - LoadDoorData(doorData); - LoadObjectData(creatureData, objectData); + case NPC_RAZORGORE: + razorgoreGUID = creature->GetGUID(); + break; + case NPC_BLACKWING_DRAGON: + ++addsCount[0]; + if (Creature* razor = instance->GetCreature(razorgoreGUID)) + if (CreatureAI* razorAI = razor->AI()) + razorAI->JustSummoned(creature); + break; + case NPC_BLACKWING_LEGIONAIRE: + case NPC_BLACKWING_MAGE: + ++addsCount[1]; + if (Creature* razor = instance->GetCreature(razorgoreGUID)) + if (CreatureAI* razorAI = razor->AI()) + razorAI->JustSummoned(creature); + break; + case NPC_BLACKWING_GUARDSMAN: + guardList.push_back(creature->GetGUID()); + break; + case NPC_NEFARIAN: + nefarianGUID = creature->GetGUID(); + break; + case NPC_BLACK_DRAKONID: + case NPC_BLUE_DRAKONID: + case NPC_BRONZE_DRAKONID: + case NPC_CHROMATIC_DRAKONID: + case NPC_GREEN_DRAKONID: + case NPC_RED_DRAKONID: + if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS)) + if (CreatureAI* nefariusAI = nefarius->AI()) + nefariusAI->JustSummoned(creature); + break; + default: + break; + } + } + + void OnGameObjectCreate(GameObject* go) override + { + InstanceScript::OnGameObjectCreate(go); + + switch (go->GetEntry()) + { + case GO_BLACK_DRAGON_EGG: + if (GetBossState(DATA_FIREMAW) == DONE) + go->SetPhaseMask(2, true); + else + EggList.push_back(go->GetGUID()); + break; + default: + break; + } + } + + void OnGameObjectRemove(GameObject* go) override + { + InstanceScript::OnGameObjectRemove(go); + + if (go->GetEntry() == GO_BLACK_DRAGON_EGG) + EggList.remove(go->GetGUID()); + } + + uint32 GetData(uint32 data) const override + { + switch (data) + { + case DATA_NEFARIAN_LEFT_TUNNEL: + return NefarianLeftTunnel; + case DATA_NEFARIAN_RIGHT_TUNNEL: + return NefarianRightTunnel; + case DATA_EGG_EVENT: + return EggEvent; + default: + break; } - void Initialize() override + return 0; + } + + bool CheckRequiredBosses(uint32 bossId, Player const* /* player */) const override + { + switch (bossId) { - // Razorgore - EggCount = 0; - EggEvent = 0; - NefarianLeftTunnel = 0; - NefarianRightTunnel = 0; - addsCount.fill(0); + case DATA_BROODLORD_LASHLAYER: + if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE) + return false; + break; + default: + break; } - void OnCreatureCreate(Creature* creature) override + return true; + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) { - // This is required because the tempspawn at Vael overwrites his GUID. - if (creature->GetEntry() == NPC_VICTOR_NEFARIUS && creature->ToTempSummon()) - { - return; - } - - InstanceScript::OnCreatureCreate(creature); - - switch (creature->GetEntry()) - { - case NPC_RAZORGORE: - razorgoreGUID = creature->GetGUID(); - break; - case NPC_BLACKWING_DRAGON: - ++addsCount[0]; - if (Creature* razor = instance->GetCreature(razorgoreGUID)) + case DATA_RAZORGORE_THE_UNTAMED: + if (state == DONE) + { + for (ObjectGuid const& guid : EggList) { - if (CreatureAI* razorAI = razor->AI()) - { - razorAI->JustSummoned(creature); - } + // Eggs should be destroyed instead + /// @todo: after dynamic spawns + if (GameObject* egg = instance->GetGameObject(guid)) + egg->SetPhaseMask(2, true); } - break; - case NPC_BLACKWING_LEGIONAIRE: - case NPC_BLACKWING_MAGE: - ++addsCount[1]; - if (Creature* razor = instance->GetCreature(razorgoreGUID)) - { - if (CreatureAI* razorAI = razor->AI()) - { - razorAI->JustSummoned(creature); - } - } - break; - case NPC_BLACKWING_GUARDSMAN: - guardList.push_back(creature->GetGUID()); - break; - case NPC_NEFARIAN: - nefarianGUID = creature->GetGUID(); - break; - case NPC_BLACK_DRAKONID: - case NPC_BLUE_DRAKONID: - case NPC_BRONZE_DRAKONID: - case NPC_CHROMATIC_DRAKONID: - case NPC_GREEN_DRAKONID: - case NPC_RED_DRAKONID: - if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS)) - { - if (CreatureAI* nefariusAI = nefarius->AI()) - { - nefariusAI->JustSummoned(creature); - } - } - break; - default: - break; - } + } + break; + case DATA_NEFARIAN: + switch (state) + { + case FAIL: + _events.ScheduleEvent(EVENT_RESPAWN_NEFARIUS, 15min); + [[fallthrough]]; + case NOT_STARTED: + if (Creature* nefarian = instance->GetCreature(nefarianGUID)) + nefarian->DespawnOrUnsummon(); + break; + default: + break; + } + break; } + return true; + } - void OnGameObjectCreate(GameObject* go) override - { - InstanceScript::OnGameObjectCreate(go); - - switch (go->GetEntry()) - { - case GO_BLACK_DRAGON_EGG: - if (GetBossState(DATA_FIREMAW) == DONE) - { - go->SetPhaseMask(2, true); - } - else - { - EggList.push_back(go->GetGUID()); - } - break; - default: - break; - } - } - - void OnGameObjectRemove(GameObject* go) override - { - InstanceScript::OnGameObjectRemove(go); - - if (go->GetEntry() == GO_BLACK_DRAGON_EGG) - EggList.remove(go->GetGUID()); - } - - uint32 GetData(uint32 data) const override + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_EGG_EVENT) { switch (data) { - case DATA_NEFARIAN_LEFT_TUNNEL: - return NefarianLeftTunnel; - case DATA_NEFARIAN_RIGHT_TUNNEL: - return NefarianRightTunnel; - case DATA_EGG_EVENT: - return EggEvent; - default: + case DONE: + EggEvent = data; break; - } - - return 0; - } - - bool CheckRequiredBosses(uint32 bossId, Player const* /* player */) const override - { - switch (bossId) - { - case DATA_BROODLORD_LASHLAYER: - if (GetBossState(DATA_VAELASTRAZ_THE_CORRUPT) != DONE) - return false; + case FAIL: + _events.CancelEvent(EVENT_RAZOR_SPAWN); break; - default: + case IN_PROGRESS: + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45s); + EggEvent = data; + EggCount = 0; + addsCount.fill(0); break; - } + case NOT_STARTED: + _events.CancelEvent(EVENT_RAZOR_SPAWN); + EggEvent = data; + EggCount = 0; + addsCount.fill(0); - return true; - } + for (ObjectGuid const& guid : EggList) + DoRespawnGameObject(guid, 0); - bool SetBossState(uint32 type, EncounterState state) override - { - if (!InstanceScript::SetBossState(type, state)) - return false; + DoRespawnCreature(DATA_GRETHOK); - switch (type) - { - case DATA_RAZORGORE_THE_UNTAMED: - if (state == DONE) + for (ObjectGuid const& guid : guardList) + DoRespawnCreature(guid); + + break; + case SPECIAL: + if (EggEvent == NOT_STARTED) + SetData(DATA_EGG_EVENT, IN_PROGRESS); + if (++EggCount >= EggList.size()) { - for (ObjectGuid const& guid : EggList) + if (Creature* razor = instance->GetCreature(razorgoreGUID)) { - // Eggs should be destroyed instead - /// @todo: after dynamic spawns - if (GameObject* egg = instance->GetGameObject(guid)) - { - egg->SetPhaseMask(2, true); - } + SetData(DATA_EGG_EVENT, DONE); + razor->RemoveAurasDueToSpell(19832); // MindControl + DoRemoveAurasDueToSpellOnPlayers(19832); } - } - break; - case DATA_NEFARIAN: - switch (state) - { - case FAIL: - _events.ScheduleEvent(EVENT_RESPAWN_NEFARIUS, 15min); - [[fallthrough]]; - case NOT_STARTED: - if (Creature* nefarian = instance->GetCreature(nefarianGUID)) - { - nefarian->DespawnOrUnsummon(); - } - break; - default: - break; - } - break; - } - return true; - } - - void SetData(uint32 type, uint32 data) override - { - if (type == DATA_EGG_EVENT) - { - switch (data) - { - case DONE: - EggEvent = data; - break; - case FAIL: + _events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1s); _events.CancelEvent(EVENT_RAZOR_SPAWN); - break; - case IN_PROGRESS: - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 45s); - EggEvent = data; - EggCount = 0; - addsCount.fill(0); - break; - case NOT_STARTED: - _events.CancelEvent(EVENT_RAZOR_SPAWN); - EggEvent = data; - EggCount = 0; - addsCount.fill(0); - - for (ObjectGuid const& guid : EggList) - { - DoRespawnGameObject(guid, 0); - } - - DoRespawnCreature(DATA_GRETHOK); - - for (ObjectGuid const& guid : guardList) - { - DoRespawnCreature(guid); - } - - break; - case SPECIAL: - if (EggEvent == NOT_STARTED) - SetData(DATA_EGG_EVENT, IN_PROGRESS); - if (++EggCount >= EggList.size()) - { - if (Creature* razor = instance->GetCreature(razorgoreGUID)) - { - SetData(DATA_EGG_EVENT, DONE); - razor->RemoveAurasDueToSpell(19832); // MindControl - DoRemoveAurasDueToSpellOnPlayers(19832); - } - _events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1s); - _events.CancelEvent(EVENT_RAZOR_SPAWN); - } - break; - } - } - - if (type == DATA_NEFARIAN_LEFT_TUNNEL) - { - NefarianLeftTunnel = data; - } - - if (type == DATA_NEFARIAN_RIGHT_TUNNEL) - { - NefarianRightTunnel = data; - } - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case DATA_RAZORGORE_THE_UNTAMED: - return razorgoreGUID; - default: - break; - } - - return ObjectGuid::Empty; - } - - void OnUnitDeath(Unit* unit) override - { - switch (unit->GetEntry()) - { - case NPC_BLACKWING_DRAGON: - --addsCount[0]; - if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN)) - { - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s); } break; - case NPC_BLACKWING_LEGIONAIRE: - case NPC_BLACKWING_MAGE: - --addsCount[1]; - if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN)) - { - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s); - } - break; - default: - break; } } - void Update(uint32 diff) override + if (type == DATA_NEFARIAN_LEFT_TUNNEL) + NefarianLeftTunnel = data; + + if (type == DATA_NEFARIAN_RIGHT_TUNNEL) + NefarianRightTunnel = data; + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) { - if (_events.Empty()) - return; + case DATA_RAZORGORE_THE_UNTAMED: + return razorgoreGUID; + default: + break; + } - _events.Update(diff); + return ObjectGuid::Empty; + } - while (uint32 eventId = _events.ExecuteEvent()) + void OnUnitDeath(Unit* unit) override + { + switch (unit->GetEntry()) + { + case NPC_BLACKWING_DRAGON: + --addsCount[0]; + if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN)) + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s); + break; + case NPC_BLACKWING_LEGIONAIRE: + case NPC_BLACKWING_MAGE: + --addsCount[1]; + if (EggEvent != DONE && !_events.HasTimeUntilEvent(EVENT_RAZOR_SPAWN)) + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 1s); + break; + default: + break; + } + } + + void Update(uint32 diff) override + { + if (_events.Empty()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - switch (eventId) - { - case EVENT_RAZOR_SPAWN: - if (EggEvent == IN_PROGRESS) + case EVENT_RAZOR_SPAWN: + if (EggEvent == IN_PROGRESS) + { + bool spawnMoreAdds = true; + for (uint8 i = urand(2, 5); i > 0; --i) { - bool spawnMoreAdds = true; - for (uint8 i = urand(2, 5); i > 0; --i) - { - uint32 mobEntry = Entry[urand(0, 2)]; - uint32 dragonkinsCount = addsCount[0]; - uint32 orcsCount = addsCount[1]; + uint32 mobEntry = Entry[urand(0, 2)]; + uint32 dragonkinsCount = addsCount[0]; + uint32 orcsCount = addsCount[1]; - // If more than 12 dragonkins... - if (dragonkinsCount >= 12) + // If more than 12 dragonkins... + if (dragonkinsCount >= 12) + { + //... and more than 40 orcs - stop spawning more adds. + if (orcsCount >= 40) { - //... and more than 40 orcs - stop spawning more adds. - if (orcsCount >= 40) - { - spawnMoreAdds = false; - break; - } - //... - stop spawning them. - else if (mobEntry == NPC_BLACKWING_DRAGON) - { - continue; - } + spawnMoreAdds = false; + break; } - // If more than 40 orcs - stop spawning them. - else if (orcsCount >= 40 && mobEntry != NPC_BLACKWING_DRAGON) + //... - stop spawning them. + else if (mobEntry == NPC_BLACKWING_DRAGON) { continue; } - - if (Creature* summon = instance->SummonCreature(mobEntry, SummonPosition[urand(0, 7)])) - { - summon->AI()->DoZoneInCombat(); - } } - - if (spawnMoreAdds) + // If more than 40 orcs - stop spawning them. + else if (orcsCount >= 40 && mobEntry != NPC_BLACKWING_DRAGON) { - _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15s); + continue; } + + if (Creature* summon = instance->SummonCreature(mobEntry, SummonPosition[urand(0, 7)])) + summon->AI()->DoZoneInCombat(); } - break; - case EVENT_RAZOR_PHASE_TWO: - _events.CancelEvent(EVENT_RAZOR_SPAWN); - if (Creature* razor = instance->GetCreature(razorgoreGUID)) - razor->AI()->DoAction(ACTION_PHASE_TWO); - break; - case EVENT_RESPAWN_NEFARIUS: - if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS)) - { - nefarius->SetPhaseMask(1, true); - nefarius->setActive(true); - nefarius->Respawn(); - nefarius->GetMotionMaster()->MoveTargetedHome(); - } - break; - } + + if (spawnMoreAdds) + _events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15s); + } + break; + case EVENT_RAZOR_PHASE_TWO: + _events.CancelEvent(EVENT_RAZOR_SPAWN); + if (Creature* razor = instance->GetCreature(razorgoreGUID)) + razor->AI()->DoAction(ACTION_PHASE_TWO); + break; + case EVENT_RESPAWN_NEFARIUS: + if (Creature* nefarius = GetCreature(DATA_LORD_VICTOR_NEFARIUS)) + { + nefarius->SetPhaseMask(1, true); + nefarius->setActive(true); + nefarius->Respawn(); + nefarius->GetMotionMaster()->MoveTargetedHome(); + } + break; } } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> NefarianLeftTunnel; - data >> NefarianRightTunnel; - } - - void WriteSaveDataMore(std::ostringstream& data) override - { - data << NefarianLeftTunnel << ' ' << NefarianRightTunnel; - } - - protected: - ObjectGuid razorgoreGUID; - ObjectGuid nefarianGUID; - ObjectGuid nefarianDoorGUID; - - // Razorgore - uint8 EggCount; - uint32 EggEvent; - GuidList EggList; - GuidList guardList; - std::array addsCount; - - // Nefarian - uint32 NefarianLeftTunnel; - uint32 NefarianRightTunnel; - - // Misc - EventMap _events; - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_blackwing_lair_InstanceMapScript(map); } + + void ReadSaveDataMore(std::istringstream& data) override + { + data >> NefarianLeftTunnel; + data >> NefarianRightTunnel; + } + + void WriteSaveDataMore(std::ostringstream& data) override + { + data << NefarianLeftTunnel << ' ' << NefarianRightTunnel; + } + +protected: + ObjectGuid razorgoreGUID; + ObjectGuid nefarianGUID; + ObjectGuid nefarianDoorGUID; + + // Razorgore + uint8 EggCount; + uint32 EggEvent; + GuidList EggList; + GuidList guardList; + std::array addsCount; + + // Nefarian + uint32 NefarianLeftTunnel; + uint32 NefarianRightTunnel; + + // Misc + EventMap _events; }; enum ShadowFlame @@ -527,7 +478,7 @@ public: void AddSC_instance_blackwing_lair() { - new instance_blackwing_lair(); + RegisterInstanceScript(instance_blackwing_lair, MAP_BLACKWING_LAIR); RegisterSpellScript(spell_bwl_shadowflame); new at_orb_of_command(); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp index 448ec46ff..96cfbed45 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp @@ -43,88 +43,73 @@ enum Events EVENT_LIVING_BOMB, }; -class boss_baron_geddon : public CreatureScript +struct boss_baron_geddon : public BossAI { -public: - boss_baron_geddon() : CreatureScript("boss_baron_geddon") { } - - struct boss_baron_geddonAI : public BossAI + boss_baron_geddon(Creature* creature) : BossAI(creature, DATA_GEDDON), + armageddonCasted(false) { - boss_baron_geddonAI(Creature* creature) : BossAI(creature, DATA_GEDDON), - armageddonCasted(false) - { - } - - void Reset() override - { - _Reset(); - armageddonCasted = false; - } - - void JustEngagedWith(Unit* /*attacker*/) override - { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_INFERNO, 13s, 15s); - events.ScheduleEvent(EVENT_IGNITE_MANA, 7s, 19s); - events.ScheduleEvent(EVENT_LIVING_BOMB, 11s, 16s); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override - { - // If boss is below 2% hp - cast Armageddon - if (!armageddonCasted && damage < me->GetHealth() && me->HealthBelowPctDamaged(2, damage)) - { - me->RemoveAurasDueToSpell(SPELL_INFERNO); - me->StopMoving(); - if (me->CastSpell(me, SPELL_ARMAGEDDON, TRIGGERED_FULL_MASK) == SPELL_CAST_OK) - { - Talk(EMOTE_SERVICE); - armageddonCasted = true; - } - } - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) - { - case EVENT_INFERNO: - { - DoCastAOE(SPELL_INFERNO); - events.Repeat(21s, 26s); - break; - } - case EVENT_IGNITE_MANA: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IGNITE_MANA)) - { - DoCast(target, SPELL_IGNITE_MANA); - } - - events.Repeat(27s, 32s); - break; - } - case EVENT_LIVING_BOMB: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - DoCast(target, SPELL_LIVING_BOMB); - } - - events.Repeat(11s, 16s); - break; - } - } - } - - private: - bool armageddonCasted; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } + + void Reset() override + { + _Reset(); + armageddonCasted = false; + } + + void JustEngagedWith(Unit* /*attacker*/) override + { + _JustEngagedWith(); + events.ScheduleEvent(EVENT_INFERNO, 13s, 15s); + events.ScheduleEvent(EVENT_IGNITE_MANA, 7s, 19s); + events.ScheduleEvent(EVENT_LIVING_BOMB, 11s, 16s); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override + { + // If boss is below 2% hp - cast Armageddon + if (!armageddonCasted && damage < me->GetHealth() && me->HealthBelowPctDamaged(2, damage)) + { + me->RemoveAurasDueToSpell(SPELL_INFERNO); + me->StopMoving(); + if (me->CastSpell(me, SPELL_ARMAGEDDON, TRIGGERED_FULL_MASK) == SPELL_CAST_OK) + { + Talk(EMOTE_SERVICE); + armageddonCasted = true; + } + } + } + + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_INFERNO: + { + DoCastAOE(SPELL_INFERNO); + events.Repeat(21s, 26s); + break; + } + case EVENT_IGNITE_MANA: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IGNITE_MANA)) + DoCast(target, SPELL_IGNITE_MANA); + + events.Repeat(27s, 32s); + break; + } + case EVENT_LIVING_BOMB: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + DoCast(target, SPELL_LIVING_BOMB); + + events.Repeat(11s, 16s); + break; + } + } + } + +private: + bool armageddonCasted; }; // 19695 Inferno @@ -149,9 +134,7 @@ class spell_geddon_inferno_aura : public AuraScript void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Creature* pCreatureTarget = GetTarget()->ToCreature()) - { pCreatureTarget->SetReactState(REACT_AGGRESSIVE); - } } void PeriodicTick(AuraEffect const* aurEff) @@ -209,9 +192,7 @@ class spell_geddon_armageddon_aura : public AuraScript void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Creature* pCreatureTarget = GetTarget()->ToCreature()) - { pCreatureTarget->SetReactState(REACT_AGGRESSIVE); - } } void Register() override @@ -223,7 +204,7 @@ class spell_geddon_armageddon_aura : public AuraScript void AddSC_boss_baron_geddon() { - new boss_baron_geddon(); + RegisterMoltenCoreCreatureAI(boss_baron_geddon); // Spells RegisterSpellScript(spell_geddon_inferno_aura); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp index 15f3995b0..1e18daf55 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp @@ -51,123 +51,93 @@ enum Events EVENT_MAGMA_SHACKLES, }; -class boss_garr : public CreatureScript +struct boss_garr : public BossAI { -public: - boss_garr() : CreatureScript("boss_garr") {} - - struct boss_garrAI : public BossAI + boss_garr(Creature* creature) : BossAI(creature, DATA_GARR), + massEruptionTimer(600000) // 10 mins { - boss_garrAI(Creature* creature) : BossAI(creature, DATA_GARR), - massEruptionTimer(600000) // 10 mins + } + + void Reset() override + { + _Reset(); + massEruptionTimer = 600000; + } + + void JustEngagedWith(Unit* /*attacker*/) override + { + _JustEngagedWith(); + DoCastSelf(SPELL_SEPARATION_ANXIETY, true); + events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 15s); + events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 10s); + massEruptionTimer = 600000; // 10 mins + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + // This should always process + if (massEruptionTimer <= diff) { + Talk(EMOTE_MASS_ERRUPTION, me); + DoCastAOE(SPELL_ERUPTION_TRIGGER, true); + massEruptionTimer = 20000; + } + else + { + massEruptionTimer -= diff; } - void Reset() override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 const eventId = events.ExecuteEvent()) { - _Reset(); - massEruptionTimer = 600000; - } - - void JustEngagedWith(Unit* /*attacker*/) override - { - _JustEngagedWith(); - DoCastSelf(SPELL_SEPARATION_ANXIETY, true); - events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 15s); - events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 10s); - massEruptionTimer = 600000; // 10 mins - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) + switch (eventId) { - return; + case EVENT_ANTIMAGIC_PULSE: + { + DoCastSelf(SPELL_ANTIMAGIC_PULSE); + events.Repeat(20s); + break; + } + case EVENT_MAGMA_SHACKLES: + { + DoCastSelf(SPELL_MAGMA_SHACKLES); + events.Repeat(15s); + break; + } } - // This should always process - if (massEruptionTimer <= diff) - { - Talk(EMOTE_MASS_ERRUPTION, me); - DoCastAOE(SPELL_ERUPTION_TRIGGER, true); - massEruptionTimer = 20000; - } - else - { - massEruptionTimer -= diff; - } - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } - - while (uint32 const eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ANTIMAGIC_PULSE: - { - DoCastSelf(SPELL_ANTIMAGIC_PULSE); - events.Repeat(20s); - break; - } - case EVENT_MAGMA_SHACKLES: - { - DoCastSelf(SPELL_MAGMA_SHACKLES); - events.Repeat(15s); - break; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - } - - DoMeleeAttackIfReady(); } - private: - uint32 massEruptionTimer; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); + DoMeleeAttackIfReady(); } + +private: + uint32 massEruptionTimer; }; -class npc_garr_firesworn : public CreatureScript +struct npc_garr_firesworn : public ScriptedAI { -public: - npc_garr_firesworn() : CreatureScript("npc_garr_firesworn") {} + npc_garr_firesworn(Creature* creature) : ScriptedAI(creature) {} - struct npc_garr_fireswornAI : public ScriptedAI + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override { - npc_garr_fireswornAI(Creature* creature) : ScriptedAI(creature) {} - - void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override + if (damage >= me->GetHealth()) { - if (damage >= me->GetHealth()) - { - // Prevent double damage because Firesworn can kill himself with Massive Erruption - if (me != attacker) - { - DoCastSelf(SPELL_ERUPTION, true); - } + // Prevent double damage because Firesworn can kill himself with Massive Eruption + if (me != attacker) + DoCastSelf(SPELL_ERUPTION, true); - DoCastAOE(SPELL_ENRAGE_TRIGGER); - } + DoCastAOE(SPELL_ENRAGE_TRIGGER); } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; @@ -210,9 +180,7 @@ class spell_garr_frenzy : public SpellScript void HandleHit(SpellEffIndex /*effIndex*/) { if (Unit* target = GetHitUnit()) - { target->CastSpell(target, SPELL_FRENZY); - } } void Register() override @@ -223,8 +191,8 @@ class spell_garr_frenzy : public SpellScript void AddSC_boss_garr() { - new boss_garr(); - new npc_garr_firesworn(); + RegisterMoltenCoreCreatureAI(boss_garr); + RegisterMoltenCoreCreatureAI(npc_garr_firesworn); // Spells RegisterSpellScript(spell_garr_separation_anxiety_aura); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp index 53662ddca..26d4af08c 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp @@ -34,74 +34,57 @@ enum Events EVENT_SHADOW_BOLT, }; -class boss_gehennas : public CreatureScript +struct boss_gehennas : public BossAI { -public: - boss_gehennas() : CreatureScript("boss_gehennas") { } + boss_gehennas(Creature* creature) : BossAI(creature, DATA_GEHENNAS) {} - struct boss_gehennasAI : public BossAI + void JustEngagedWith(Unit* /*attacker*/) override { - boss_gehennasAI(Creature* creature) : BossAI(creature, DATA_GEHENNAS) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_GEHENNAS_CURSE, 6s, 9s); + events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 10s); + events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s, 5s); + } - void JustEngagedWith(Unit* /*attacker*/) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_GEHENNAS_CURSE, 6s, 9s); - events.ScheduleEvent(EVENT_RAIN_OF_FIRE, 10s); - events.ScheduleEvent(EVENT_SHADOW_BOLT, 3s, 5s); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_GEHENNAS_CURSE: { - case EVENT_GEHENNAS_CURSE: + DoCastVictim(SPELL_GEHENNAS_CURSE); + events.Repeat(25s, 30s); + break; + } + case EVENT_RAIN_OF_FIRE: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + DoCast(target, SPELL_RAIN_OF_FIRE, true); + events.Repeat(6s); + break; + } + case EVENT_SHADOW_BOLT: + { + if (urand(0, 1)) { - DoCastVictim(SPELL_GEHENNAS_CURSE); - events.Repeat(25s, 30s); - break; - } - case EVENT_RAIN_OF_FIRE: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - DoCast(target, SPELL_RAIN_OF_FIRE, true); - } - events.Repeat(6s); - break; - } - case EVENT_SHADOW_BOLT: - { - if (urand(0, 1)) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false)) - { - DoCast(target, SPELL_SHADOW_BOLT_RANDOM); - } - else - { - DoCastVictim(SPELL_SHADOW_BOLT_VICTIM); - } - } + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false)) + DoCast(target, SPELL_SHADOW_BOLT_RANDOM); else - { DoCastVictim(SPELL_SHADOW_BOLT_VICTIM); - } - - events.Repeat(5s); - break; } + else + { + DoCastVictim(SPELL_SHADOW_BOLT_VICTIM); + } + + events.Repeat(5s); + break; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; void AddSC_boss_gehennas() { - new boss_gehennas(); + RegisterMoltenCoreCreatureAI(boss_gehennas); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp index d88c1e2b3..84d95bb1d 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp @@ -40,191 +40,157 @@ enum Spells SPELL_FULL_HEAL = 17683, }; -class boss_golemagg : public CreatureScript +struct boss_golemagg : public BossAI { -public: - boss_golemagg() : CreatureScript("boss_golemagg") { } + boss_golemagg(Creature* creature) : BossAI(creature, DATA_GOLEMAGG), + earthquakeTimer(0), + pyroblastTimer(0), + enraged(false) + {} - struct boss_golemaggAI : public BossAI + void Reset() override { - boss_golemaggAI(Creature* creature) : BossAI(creature, DATA_GOLEMAGG), - earthquakeTimer(0), - pyroblastTimer(0), - enraged(false) - {} + _Reset(); + earthquakeTimer = 0; + pyroblastTimer = urand(3000, 7000); + enraged = false; + DoCastSelf(SPELL_MAGMASPLASH); + DoCastSelf(SPELL_GOLEMAGG_TRUST_AURA); + DoCastSelf(SPELL_DOUBLE_ATTACK); + } - void Reset() override + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!enraged && me->HealthBelowPctDamaged(10, damage)) { - _Reset(); - earthquakeTimer = 0; - pyroblastTimer = urand(3000, 7000); - enraged = false; - DoCastSelf(SPELL_MAGMASPLASH); - DoCastSelf(SPELL_GOLEMAGG_TRUST_AURA); - DoCastSelf(SPELL_DOUBLE_ATTACK); + DoCastSelf(SPELL_ATTRACK_RAGER, true); + DoCastAOE(SPELL_EARTHQUAKE, true); + earthquakeTimer = 5000; + enraged = true; } + } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + // Should not get impact by cast state (cast should always happen) + if (earthquakeTimer) { - if (!enraged && me->HealthBelowPctDamaged(10, damage)) + if (earthquakeTimer <= diff) { - DoCastSelf(SPELL_ATTRACK_RAGER, true); - DoCastAOE(SPELL_EARTHQUAKE, true); + DoCastSelf(SPELL_EARTHQUAKE, true); earthquakeTimer = 5000; - enraged = true; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - return; - } - - // Should not get impact by cast state (cast should always happen) - if (earthquakeTimer) - { - if (earthquakeTimer <= diff) - { - DoCastSelf(SPELL_EARTHQUAKE, true); - earthquakeTimer = 5000; - } - else - { - earthquakeTimer -= diff; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - if (pyroblastTimer <= diff) - { - DoCastRandomTarget(SPELL_PYROBLAST); - - pyroblastTimer = 7000; } else { - pyroblastTimer -= diff; + earthquakeTimer -= diff; } - - DoMeleeAttackIfReady(); } - private: - uint32 earthquakeTimer; - uint32 pyroblastTimer; - bool enraged; - }; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); + if (pyroblastTimer <= diff) + { + DoCastRandomTarget(SPELL_PYROBLAST); + + pyroblastTimer = 7000; + } + else + { + pyroblastTimer -= diff; + } + + DoMeleeAttackIfReady(); } + +private: + uint32 earthquakeTimer; + uint32 pyroblastTimer; + bool enraged; }; -class npc_core_rager : public CreatureScript +struct npc_core_rager : public ScriptedAI { -public: - npc_core_rager() : CreatureScript("npc_core_rager") { } - - struct npc_core_ragerAI : public ScriptedAI + npc_core_rager(Creature* creature) : ScriptedAI(creature), + instance(creature->GetInstanceScript()), + mangleTimer(7000), + rangeCheckTimer(1000) { - npc_core_ragerAI(Creature* creature) : ScriptedAI(creature), - instance(creature->GetInstanceScript()), - mangleTimer(7000), - rangeCheckTimer(1000) - { - } - - void Reset() override - { - mangleTimer = 7000; // These times are probably wrong - rangeCheckTimer = 1000; - - if (instance->GetBossState(DATA_GOLEMAGG) == DONE) - { - DoCastSelf(SPELL_CORE_RAGER_QUIET_SUICIDE, true); - } - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override - { - // Just in case if something will go bad, let players to kill this creature - if (instance->GetBossState(DATA_GOLEMAGG) == DONE) - { - return; - } - - if (me->HealthBelowPctDamaged(50, damage)) - { - damage = 0; - DoCastSelf(SPELL_FULL_HEAL, true); - Talk(EMOTE_LOWHP); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - return; - } - - // Should have no impact from unit state - if (rangeCheckTimer <= diff) - { - Creature const* golemagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOLEMAGG)); - if (golemagg && me->GetDistance(golemagg) > 100.0f) - { - instance->DoAction(ACTION_RESET_GOLEMAGG_ENCOUNTER); - return; - } - - rangeCheckTimer = 1000; - } - else - { - rangeCheckTimer -= diff; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - // Mangle - if (mangleTimer <= diff) - { - DoCastVictim(SPELL_MANGLE); - mangleTimer = 10000; - } - else - { - mangleTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* instance; - uint32 mangleTimer; - uint32 rangeCheckTimer; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } + + void Reset() override + { + mangleTimer = 7000; // These times are probably wrong + rangeCheckTimer = 1000; + + if (instance->GetBossState(DATA_GOLEMAGG) == DONE) + DoCastSelf(SPELL_CORE_RAGER_QUIET_SUICIDE, true); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override + { + // Just in case if something will go bad, let players to kill this creature + if (instance->GetBossState(DATA_GOLEMAGG) == DONE) + return; + + if (me->HealthBelowPctDamaged(50, damage)) + { + damage = 0; + DoCastSelf(SPELL_FULL_HEAL, true); + Talk(EMOTE_LOWHP); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + // Should have no impact from unit state + if (rangeCheckTimer <= diff) + { + Creature const* golemagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GOLEMAGG)); + if (golemagg && me->GetDistance(golemagg) > 100.0f) + { + instance->DoAction(ACTION_RESET_GOLEMAGG_ENCOUNTER); + return; + } + + rangeCheckTimer = 1000; + } + else + { + rangeCheckTimer -= diff; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + // Mangle + if (mangleTimer <= diff) + { + DoCastVictim(SPELL_MANGLE); + mangleTimer = 10000; + } + else + { + mangleTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* instance; + uint32 mangleTimer; + uint32 rangeCheckTimer; }; void AddSC_boss_golemagg() { - new boss_golemagg(); - new npc_core_rager(); + RegisterMoltenCoreCreatureAI(boss_golemagg); + RegisterMoltenCoreCreatureAI(npc_core_rager); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp index dd38b6ca8..1f8f89b3f 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp @@ -33,56 +33,45 @@ enum Events EVENT_SHADOW_SHOCK = 3, }; -class boss_lucifron : public CreatureScript +struct boss_lucifron : public BossAI { -public: - boss_lucifron() : CreatureScript("boss_lucifron") { } + boss_lucifron(Creature* creature) : BossAI(creature, DATA_LUCIFRON) {} - struct boss_lucifronAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_lucifronAI(Creature* creature) : BossAI(creature, DATA_LUCIFRON) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_IMPENDING_DOOM, 6s, 11s); + events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 11s, 14s); + events.ScheduleEvent(EVENT_SHADOW_SHOCK, 5s); + } - void JustEngagedWith(Unit* /*who*/) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_IMPENDING_DOOM, 6s, 11s); - events.ScheduleEvent(EVENT_LUCIFRON_CURSE, 11s, 14s); - events.ScheduleEvent(EVENT_SHADOW_SHOCK, 5s); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_IMPENDING_DOOM: { - case EVENT_IMPENDING_DOOM: - { - DoCastVictim(SPELL_IMPENDING_DOOM); - events.Repeat(20s); - break; - } - case EVENT_LUCIFRON_CURSE: - { - DoCastVictim(SPELL_LUCIFRON_CURSE); - events.Repeat(20s); - break; - } - case EVENT_SHADOW_SHOCK: - { - DoCastVictim(SPELL_SHADOW_SHOCK); - events.Repeat(5s); - break; - } + DoCastVictim(SPELL_IMPENDING_DOOM); + events.Repeat(20s); + break; + } + case EVENT_LUCIFRON_CURSE: + { + DoCastVictim(SPELL_LUCIFRON_CURSE); + events.Repeat(20s); + break; + } + case EVENT_SHADOW_SHOCK: + { + DoCastVictim(SPELL_SHADOW_SHOCK); + events.Repeat(5s); + break; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; void AddSC_boss_lucifron() { - new boss_lucifron(); + RegisterMoltenCoreCreatureAI(boss_lucifron); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp index f0d7563a8..9d1eb17ae 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp @@ -47,73 +47,58 @@ enum Events constexpr float MELEE_TARGET_LOOKUP_DIST = 10.0f; -class boss_magmadar : public CreatureScript +struct boss_magmadar : public BossAI { -public: - boss_magmadar() : CreatureScript("boss_magmadar") {} + boss_magmadar(Creature* creature) : BossAI(creature, DATA_MAGMADAR) {} - struct boss_magmadarAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_magmadarAI(Creature* creature) : BossAI(creature, DATA_MAGMADAR) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_FRENZY, 8500ms); + events.ScheduleEvent(EVENT_PANIC, 9500ms); + events.ScheduleEvent(EVENT_LAVA_BOMB, 12s); + events.ScheduleEvent(EVENT_LAVA_BOMB_RANGED, 15s); + } - void JustEngagedWith(Unit* /*who*/) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_FRENZY, 8500ms); - events.ScheduleEvent(EVENT_PANIC, 9500ms); - events.ScheduleEvent(EVENT_LAVA_BOMB, 12s); - events.ScheduleEvent(EVENT_LAVA_BOMB_RANGED, 15s); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_FRENZY: { - case EVENT_FRENZY: - { - Talk(EMOTE_FRENZY); - DoCastSelf(SPELL_FRENZY); - events.Repeat(15s, 20s); - break; - } - case EVENT_PANIC: - { - DoCastVictim(SPELL_PANIC); - events.Repeat(31s, 38s); - break; - } - case EVENT_LAVA_BOMB: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true)) - { - DoCast(target, SPELL_LAVA_BOMB); - } + Talk(EMOTE_FRENZY); + DoCastSelf(SPELL_FRENZY); + events.Repeat(15s, 20s); + break; + } + case EVENT_PANIC: + { + DoCastVictim(SPELL_PANIC); + events.Repeat(31s, 38s); + break; + } + case EVENT_LAVA_BOMB: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, MELEE_TARGET_LOOKUP_DIST, true)) + DoCast(target, SPELL_LAVA_BOMB); - events.Repeat(12s, 15s); - break; - } - case EVENT_LAVA_BOMB_RANGED: + events.Repeat(12s, 15s); + break; + } + case EVENT_LAVA_BOMB_RANGED: + { + std::list targets; + SelectTargetList(targets, 1, SelectTargetMethod::Random, 1, [this](Unit* target) { - std::list targets; - SelectTargetList(targets, 1, SelectTargetMethod::Random, 1, [this](Unit* target) - { - return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f; - }); + return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f; + }); - if (!targets.empty()) - { - DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED); - } - events.Repeat(12s, 15s); - break; - } + if (!targets.empty()) + DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED); + events.Repeat(12s, 15s); + break; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; @@ -162,7 +147,7 @@ class spell_magmadar_lava_bomb : public SpellScript void AddSC_boss_magmadar() { - new boss_magmadar(); + RegisterMoltenCoreCreatureAI(boss_magmadar); // Spells RegisterSpellScript(spell_magmadar_lava_bomb); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp index ad4da94c6..7498b88fc 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp @@ -131,412 +131,389 @@ struct MajordomoAddData MajordomoAddData(ObjectGuid _guid, uint32 _creatureEntry, Position _spawnPos) : guid(_guid), creatureEntry(_creatureEntry), spawnPos(_spawnPos) { } }; -class boss_majordomo : public CreatureScript +struct boss_majordomo : public BossAI { -public: - boss_majordomo() : CreatureScript("boss_majordomo") {} + boss_majordomo(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {} - struct boss_majordomoAI : public BossAI + void JustDied(Unit* /*killer*/) override { - boss_majordomoAI(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS) {} - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - me->DespawnOrUnsummon(10s, 0s); - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() == NPC_RAGNAROS) - { - summon->CastSpell(summon, SPELL_RAGNAROS_FADE); - summon->CastSpell(summon, SPELL_RAGNAROS_SUBMERGE_EFFECT, true); - summon->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - summon->SetImmuneToAll(true); - summon->SetReactState(REACT_PASSIVE); - } - } - - void InitializeAI() override - { - BossAI::InitializeAI(); - if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) - { - events.SetPhase(PHASE_COMBAT); - - std::list p_summons; - me->SummonCreatureGroup(SUMMON_GROUP_ADDS, &p_summons); - if (!p_summons.empty()) - { - for (TempSummon const* summon : p_summons) - { - if (summon) - { - static_minionsGUIDS.insert(summon->GetGUID()); - majordomoSummonsData[summon->GetGUID().GetCounter()] = MajordomoAddData(summon->GetGUID(), summon->GetEntry(), summon->GetPosition()); - } - } - } - } - else - { - events.SetPhase(PHASE_NONE); - me->SetImmuneToAll(true); - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->SetFaction(FACTION_MAJORDOMO_FRIENDLY); - } - } - - void Reset() override - { - me->ResetLootMode(); - events.Reset(); - aliveMinionsGUIDS.clear(); - - if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) - { - events.SetPhase(PHASE_COMBAT); - instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, NOT_STARTED); - - for (auto const& summon : majordomoSummonsData) - { - if (ObjectAccessor::GetCreature(*me, summon.second.guid)) - { - continue; - } - - if (Creature* spawn = me->SummonCreature(summon.second.creatureEntry, summon.second.spawnPos)) - { - static_minionsGUIDS.erase(summon.second.guid); // Erase the guid from the previous, no longer existing, spawn. - static_minionsGUIDS.insert(spawn->GetGUID()); - majordomoSummonsData.erase(summon.second.guid.GetCounter()); - majordomoSummonsData[spawn->GetGUID().GetCounter()] = MajordomoAddData(spawn->GetGUID(), spawn->GetEntry(), spawn->GetPosition()); - } - } - - me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - } - else - { - static_minionsGUIDS.clear(); - majordomoSummonsData.clear(); - summons.DespawnAll(); - } - } - - bool CanAIAttack(Unit const* /*target*/) const override - { - return instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE; - } - - void KilledUnit(Unit* victim) override - { - if (roll_chance_i(25) && victim->IsPlayer()) - { - Talk(SAY_SLAY); - } - } - - void JustEngagedWith(Unit* /*attacker*/) override - { - if (!events.IsInPhase(PHASE_COMBAT)) - { - return; - } - - _JustEngagedWith(); - DoCastAOE(SPELL_SEPARATION_ANXIETY); - Talk(SAY_AGGRO); - DoCastSelf(SPELL_AEGIS_OF_RAGNAROS, true); - - events.ScheduleEvent(EVENT_SHIELD_REFLECTION, 30s, PHASE_COMBAT, PHASE_COMBAT); - events.ScheduleEvent(EVENT_TELEPORT_RANDOM, 25s, PHASE_COMBAT, PHASE_COMBAT); - events.ScheduleEvent(EVENT_TELEPORT_TARGET, 15s, PHASE_COMBAT, PHASE_COMBAT); - - aliveMinionsGUIDS.clear(); - aliveMinionsGUIDS = static_minionsGUIDS; - } - - void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override - { - aliveMinionsGUIDS.erase(summon->GetGUID()); - if (summon->GetEntry() == NPC_FLAMEWAKER_HEALER || summon->GetEntry() == NPC_FLAMEWAKER_ELITE) - { - uint32 const remainingAdds = std::count_if(aliveMinionsGUIDS.begin(), aliveMinionsGUIDS.end(), [](ObjectGuid const& summonGuid) - { - return summonGuid.GetEntry() == NPC_FLAMEWAKER_HEALER || summonGuid.GetEntry() == NPC_FLAMEWAKER_ELITE; - }); - - // Last remaining add - if (remainingAdds == 1) - { - Talk(SAY_LAST_ADD); - DoCastAOE(SPELL_CHAMPION); - } - // 50% of adds - else if (remainingAdds == 4) - { - DoCastAOE(SPELL_IMMUNE_POLY); - } - else if (!remainingAdds) - { - static_minionsGUIDS.clear(); - - instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, DONE); - events.CancelEventGroup(PHASE_COMBAT); - me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me); - me->SetImmuneToAll(true); - me->SetFaction(FACTION_MAJORDOMO_FRIENDLY); - EnterEvadeMode(); - Talk(SAY_DEFEAT); - return; - } - DoCastAOE(SPELL_ENCOURAGEMENT); - } - } - - void JustReachedHome() override - { - _JustReachedHome(); - if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) == DONE) - { - events.Reset(); - events.SetPhase(PHASE_DEFEAT_OUTRO); - events.ScheduleEvent(EVENT_DEFEAT_OUTRO_1, 7500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); - } - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override - { - if (events.IsInPhase(PHASE_COMBAT) && me->GetHealth() <= damage) - { - damage = 0; - } - } - - void UpdateAI(uint32 diff) override - { - - switch (events.GetPhaseMask()) - { - case (1 << (PHASE_COMBAT - 1)): - { - if (!UpdateVictim()) - { - return; - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - while (uint32 const eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_SHIELD_REFLECTION: - { - if (rand_chance() <= 50.f) - { - DoCastSelf(SPELL_MAGIC_REFLECTION); - } - else - { - DoCastSelf(SPELL_DAMAGE_REFLECTION); - } - events.Repeat(30s); - break; - } - case EVENT_TELEPORT_RANDOM: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false)) - { - DoCastSelf(SPELL_HATE_TO_ZERO, true); - DoCast(target, SPELL_TELEPORT_RANDOM); - } - - events.Repeat(30s); - break; - } - case EVENT_TELEPORT_TARGET: - { - DoCastSelf(SPELL_HATE_TO_ZERO, true); - DoCastAOE(SPELL_TELEPORT_TARGET); - events.Repeat(30s); - break; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - } - - DoMeleeAttackIfReady(); - break; - } - case (1 << (PHASE_DEFEAT_OUTRO - 1)): - { - events.Update(diff); - while (uint32 const eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DEFEAT_OUTRO_1: - { - Talk(SAY_DEFEAT_2); - events.ScheduleEvent(EVENT_DEFEAT_OUTRO_2, 8s, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); - break; - } - case EVENT_DEFEAT_OUTRO_2: - { - Talk(SAY_DEFEAT_3); - events.ScheduleEvent(EVENT_DEFEAT_OUTRO_3, 21500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); - break; - } - case EVENT_DEFEAT_OUTRO_3: - { - DoCastSelf(SPELL_TELEPORT_SELF); - break; - } - } - } - break; - } - case (1 << (PHASE_RAGNAROS_SUMMONING - 1)): - { - events.Update(diff); - while (uint32 const eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_RAGNAROS_SUMMON_1: - { - if (GameObject* lavaSplash = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_SPLASH))) - { - lavaSplash->SetRespawnTime(900); - lavaSplash->Refresh(); - } - if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM))) - { - lavaSteam->SetRespawnTime(900); - lavaSteam->Refresh(); - } - Talk(SAY_RAG_SUM_2); - // Next event will get triggered in MovementInform - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_RAGNAROS_SUMMON, MajordomoMoveRagPos, FORCED_MOVEMENT_NONE, 0.f, true, false); - break; - } - case EVENT_RAGNAROS_SUMMON_2: - { - if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM))) - { - me->SetFacingToObject(lavaSteam); - } - - Talk(SAY_SUMMON_MAJ); - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_3, 16700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - events.ScheduleEvent(EVENT_RAGNAROS_EMERGE, 15s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - break; - } - case EVENT_RAGNAROS_SUMMON_3: - { - if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) - { - ragnaros->AI()->Talk(SAY_ARRIVAL1_RAG); - } - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_4, 11700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - break; - } - case EVENT_RAGNAROS_SUMMON_4: - { - Talk(SAY_ARRIVAL2_MAJ); - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_5, 8700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - break; - } - case EVENT_RAGNAROS_SUMMON_5: - { - if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) - { - ragnaros->AI()->Talk(SAY_ARRIVAL3_RAG); - } - - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_6, 16500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - break; - } - case EVENT_RAGNAROS_SUMMON_6: - { - if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) - { - ragnaros->CastSpell(me, SPELL_ELEMENTAL_FIRE, true); - ragnaros->AI()->DoAction(ACTION_FINISH_RAGNAROS_INTRO); - } - break; - } - // Additional events - case EVENT_RAGNAROS_EMERGE: - { - if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) - { - ragnaros->RemoveAurasDueToSpell(SPELL_RAGNAROS_FADE); - ragnaros->CastSpell(ragnaros, SPELL_RAGNA_EMERGE); - } - }break; - } - } - break; - } - } - } - - void MovementInform(uint32 type, uint32 pointId) override - { - if (type == POINT_MOTION_TYPE && pointId == POINT_RAGNAROS_SUMMON) - { - DoCastAOE(SPELL_SUMMON_RAGNAROS); - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_2, 11500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - } - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (events.IsInPhase(PHASE_DEFEAT_OUTRO) && spellInfo->Id == SPELL_TELEPORT_SELF) - { - me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - me->SetHomePosition(MajordomoRagnaros); - me->NearTeleportTo(MajordomoRagnaros.GetPositionX(), MajordomoRagnaros.GetPositionY(), MajordomoRagnaros.GetPositionZ(), MajordomoRagnaros.GetOrientation()); - events.SetPhase(PHASE_NONE); - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_START_RAGNAROS_INTRO && !events.IsInPhase(PHASE_RAGNAROS_SUMMONING)) - { - events.SetPhase(PHASE_RAGNAROS_SUMMONING); - events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_1, 5s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); - } - } - private: - GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion - GuidSet aliveMinionsGUIDS; // used for calculations - std::unordered_map majordomoSummonsData; - }; - - bool OnGossipHello(Player* player, Creature* creature) override - { - AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - SendGossipMenuFor(player, TEXT_ID_SUMMON_1, creature->GetGUID()); - return true; + Talk(SAY_DEATH); + me->DespawnOrUnsummon(10s, 0s); } - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() == NPC_RAGNAROS) + { + summon->CastSpell(summon, SPELL_RAGNAROS_FADE); + summon->CastSpell(summon, SPELL_RAGNAROS_SUBMERGE_EFFECT, true); + summon->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + summon->SetImmuneToAll(true); + summon->SetReactState(REACT_PASSIVE); + } + } + + void InitializeAI() override + { + BossAI::InitializeAI(); + if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) + { + events.SetPhase(PHASE_COMBAT); + + std::list p_summons; + me->SummonCreatureGroup(SUMMON_GROUP_ADDS, &p_summons); + if (!p_summons.empty()) + { + for (TempSummon const* summon : p_summons) + { + if (summon) + { + static_minionsGUIDS.insert(summon->GetGUID()); + majordomoSummonsData[summon->GetGUID().GetCounter()] = MajordomoAddData(summon->GetGUID(), summon->GetEntry(), summon->GetPosition()); + } + } + } + } + else + { + events.SetPhase(PHASE_NONE); + me->SetImmuneToAll(true); + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetFaction(FACTION_MAJORDOMO_FRIENDLY); + } + } + + void Reset() override + { + me->ResetLootMode(); + events.Reset(); + aliveMinionsGUIDS.clear(); + + if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) + { + events.SetPhase(PHASE_COMBAT); + instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, NOT_STARTED); + + for (auto const& summon : majordomoSummonsData) + { + if (ObjectAccessor::GetCreature(*me, summon.second.guid)) + continue; + + if (Creature* spawn = me->SummonCreature(summon.second.creatureEntry, summon.second.spawnPos)) + { + static_minionsGUIDS.erase(summon.second.guid); // Erase the guid from the previous, no longer existing, spawn. + static_minionsGUIDS.insert(spawn->GetGUID()); + majordomoSummonsData.erase(summon.second.guid.GetCounter()); + majordomoSummonsData[spawn->GetGUID().GetCounter()] = MajordomoAddData(spawn->GetGUID(), spawn->GetEntry(), spawn->GetPosition()); + } + } + + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + } + else + { + static_minionsGUIDS.clear(); + majordomoSummonsData.clear(); + summons.DespawnAll(); + } + } + + bool CanAIAttack(Unit const* /*target*/) const override + { + return instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE; + } + + void KilledUnit(Unit* victim) override + { + if (roll_chance_i(25) && victim->IsPlayer()) + Talk(SAY_SLAY); + } + + void JustEngagedWith(Unit* /*attacker*/) override + { + if (!events.IsInPhase(PHASE_COMBAT)) + return; + + _JustEngagedWith(); + DoCastAOE(SPELL_SEPARATION_ANXIETY); + Talk(SAY_AGGRO); + DoCastSelf(SPELL_AEGIS_OF_RAGNAROS, true); + + events.ScheduleEvent(EVENT_SHIELD_REFLECTION, 30s, PHASE_COMBAT, PHASE_COMBAT); + events.ScheduleEvent(EVENT_TELEPORT_RANDOM, 25s, PHASE_COMBAT, PHASE_COMBAT); + events.ScheduleEvent(EVENT_TELEPORT_TARGET, 15s, PHASE_COMBAT, PHASE_COMBAT); + + aliveMinionsGUIDS.clear(); + aliveMinionsGUIDS = static_minionsGUIDS; + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + aliveMinionsGUIDS.erase(summon->GetGUID()); + if (summon->GetEntry() == NPC_FLAMEWAKER_HEALER || summon->GetEntry() == NPC_FLAMEWAKER_ELITE) + { + uint32 const remainingAdds = std::count_if(aliveMinionsGUIDS.begin(), aliveMinionsGUIDS.end(), [](ObjectGuid const& summonGuid) + { + return summonGuid.GetEntry() == NPC_FLAMEWAKER_HEALER || summonGuid.GetEntry() == NPC_FLAMEWAKER_ELITE; + }); + + // Last remaining add + if (remainingAdds == 1) + { + Talk(SAY_LAST_ADD); + DoCastAOE(SPELL_CHAMPION); + } + // 50% of adds + else if (remainingAdds == 4) + { + DoCastAOE(SPELL_IMMUNE_POLY); + } + else if (!remainingAdds) + { + static_minionsGUIDS.clear(); + + instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, DONE); + events.CancelEventGroup(PHASE_COMBAT); + me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me); + me->SetImmuneToAll(true); + me->SetFaction(FACTION_MAJORDOMO_FRIENDLY); + EnterEvadeMode(); + Talk(SAY_DEFEAT); + return; + } + DoCastAOE(SPELL_ENCOURAGEMENT); + } + } + + void JustReachedHome() override + { + _JustReachedHome(); + if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) == DONE) + { + events.Reset(); + events.SetPhase(PHASE_DEFEAT_OUTRO); + events.ScheduleEvent(EVENT_DEFEAT_OUTRO_1, 7500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override + { + if (events.IsInPhase(PHASE_COMBAT) && me->GetHealth() <= damage) + { + damage = 0; + } + } + + void UpdateAI(uint32 diff) override + { + + switch (events.GetPhaseMask()) + { + case (1 << (PHASE_COMBAT - 1)): + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 const eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SHIELD_REFLECTION: + { + if (rand_chance() <= 50.f) + { + DoCastSelf(SPELL_MAGIC_REFLECTION); + } + else + { + DoCastSelf(SPELL_DAMAGE_REFLECTION); + } + events.Repeat(30s); + break; + } + case EVENT_TELEPORT_RANDOM: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false)) + { + DoCastSelf(SPELL_HATE_TO_ZERO, true); + DoCast(target, SPELL_TELEPORT_RANDOM); + } + + events.Repeat(30s); + break; + } + case EVENT_TELEPORT_TARGET: + { + DoCastSelf(SPELL_HATE_TO_ZERO, true); + DoCastAOE(SPELL_TELEPORT_TARGET); + events.Repeat(30s); + break; + } + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } + + DoMeleeAttackIfReady(); + break; + } + case (1 << (PHASE_DEFEAT_OUTRO - 1)): + { + events.Update(diff); + while (uint32 const eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DEFEAT_OUTRO_1: + { + Talk(SAY_DEFEAT_2); + events.ScheduleEvent(EVENT_DEFEAT_OUTRO_2, 8s, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); + break; + } + case EVENT_DEFEAT_OUTRO_2: + { + Talk(SAY_DEFEAT_3); + events.ScheduleEvent(EVENT_DEFEAT_OUTRO_3, 21500ms, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO); + break; + } + case EVENT_DEFEAT_OUTRO_3: + { + DoCastSelf(SPELL_TELEPORT_SELF); + break; + } + } + } + break; + } + case (1 << (PHASE_RAGNAROS_SUMMONING - 1)): + { + events.Update(diff); + while (uint32 const eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RAGNAROS_SUMMON_1: + { + if (GameObject* lavaSplash = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_SPLASH))) + { + lavaSplash->SetRespawnTime(900); + lavaSplash->Refresh(); + } + if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM))) + { + lavaSteam->SetRespawnTime(900); + lavaSteam->Refresh(); + } + Talk(SAY_RAG_SUM_2); + // Next event will get triggered in MovementInform + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(POINT_RAGNAROS_SUMMON, MajordomoMoveRagPos, FORCED_MOVEMENT_NONE, 0.f, true, false); + break; + } + case EVENT_RAGNAROS_SUMMON_2: + { + if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM))) + { + me->SetFacingToObject(lavaSteam); + } + + Talk(SAY_SUMMON_MAJ); + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_3, 16700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + events.ScheduleEvent(EVENT_RAGNAROS_EMERGE, 15s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + break; + } + case EVENT_RAGNAROS_SUMMON_3: + { + if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) + { + ragnaros->AI()->Talk(SAY_ARRIVAL1_RAG); + } + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_4, 11700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + break; + } + case EVENT_RAGNAROS_SUMMON_4: + { + Talk(SAY_ARRIVAL2_MAJ); + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_5, 8700ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + break; + } + case EVENT_RAGNAROS_SUMMON_5: + { + if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) + { + ragnaros->AI()->Talk(SAY_ARRIVAL3_RAG); + } + + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_6, 16500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + break; + } + case EVENT_RAGNAROS_SUMMON_6: + { + if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) + { + ragnaros->CastSpell(me, SPELL_ELEMENTAL_FIRE, true); + ragnaros->AI()->DoAction(ACTION_FINISH_RAGNAROS_INTRO); + } + break; + } + // Additional events + case EVENT_RAGNAROS_EMERGE: + { + if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS))) + { + ragnaros->RemoveAurasDueToSpell(SPELL_RAGNAROS_FADE); + ragnaros->CastSpell(ragnaros, SPELL_RAGNA_EMERGE); + } + }break; + } + } + break; + } + } + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type == POINT_MOTION_TYPE && pointId == POINT_RAGNAROS_SUMMON) + { + DoCastAOE(SPELL_SUMMON_RAGNAROS); + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_2, 11500ms, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (events.IsInPhase(PHASE_DEFEAT_OUTRO) && spellInfo->Id == SPELL_TELEPORT_SELF) + { + me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + me->SetHomePosition(MajordomoRagnaros); + me->NearTeleportTo(MajordomoRagnaros.GetPositionX(), MajordomoRagnaros.GetPositionY(), MajordomoRagnaros.GetPositionZ(), MajordomoRagnaros.GetOrientation()); + events.SetPhase(PHASE_NONE); + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_START_RAGNAROS_INTRO && !events.IsInPhase(PHASE_RAGNAROS_SUMMONING)) + { + events.SetPhase(PHASE_RAGNAROS_SUMMONING); + events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_1, 5s, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING); + } + } + + void sGossipHello(Player* player) override + { + AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + SendGossipMenuFor(player, TEXT_ID_SUMMON_1, me->GetGUID()); + } + + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); switch (action) @@ -544,40 +521,39 @@ public: case GOSSIP_ACTION_INFO_DEF: { AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID()); + SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF+1: { AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID()); + SendGossipMenuFor(player, TEXT_ID_SUMMON_2, me->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF+2: { AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - SendGossipMenuFor(player, TEXT_ID_SUMMON_3, creature->GetGUID()); + SendGossipMenuFor(player, TEXT_ID_SUMMON_3, me->GetGUID()); break; } case GOSSIP_ACTION_INFO_DEF+3: { CloseGossipMenuFor(player); - creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - creature->AI()->Talk(SAY_RAG_SUM_1, player); - creature->AI()->DoAction(ACTION_START_RAGNAROS_INTRO); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + Talk(SAY_RAG_SUM_1, player); + DoAction(ACTION_START_RAGNAROS_INTRO); break; } default: CloseGossipMenuFor(player); break; } - return true; } - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); - } +private: + GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion + GuidSet aliveMinionsGUIDS; // used for calculations + std::unordered_map majordomoSummonsData; }; // 20538 Hate to Zero (SERVERSIDE) @@ -593,12 +569,8 @@ class spell_hate_to_zero : public SpellScript void HandleHit(SpellEffIndex /*effIndex*/) { if (Unit* caster = GetCaster()) - { if (Creature* creatureCaster = caster->ToCreature()) - { creatureCaster->GetThreatMgr().ResetAllThreat(); - } - } } void Register() override @@ -641,9 +613,7 @@ class spell_summon_ragnaros : public SpellScript void HandleHit() { if (Unit* caster = GetCaster()) - { caster->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2 * HOUR * IN_MILLISECONDS); - } } void Register() override @@ -654,7 +624,7 @@ class spell_summon_ragnaros : public SpellScript void AddSC_boss_majordomo() { - new boss_majordomo(); + RegisterMoltenCoreCreatureAI(boss_majordomo); // Spells RegisterSpellScript(spell_hate_to_zero); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp index 01145b41e..45ec1dccc 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp @@ -112,390 +112,353 @@ enum Misc constexpr float DEATH_ORIENTATION = 4.0f; -class boss_ragnaros : public CreatureScript +struct boss_ragnaros : public BossAI { -public: - boss_ragnaros() : CreatureScript("boss_ragnaros") {} - - struct boss_ragnarosAI : public BossAI + boss_ragnaros(Creature* creature) : BossAI(creature, DATA_RAGNAROS), + _isIntroDone(false), + _hasYelledMagmaBurst(false), + _processingMagmaBurst(false), + _hasSubmergedOnce(false), + _isKnockbackEmoteAllowed(true) { - boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS), - _isIntroDone(false), - _hasYelledMagmaBurst(false), - _processingMagmaBurst(false), - _hasSubmergedOnce(false), - _isKnockbackEmoteAllowed(true) + } + + void Reset() override + { + _Reset(); + + // Never reset intro events! + if (_isIntroDone && !(extraEvents.GetPhaseMask() & (1 << (PHASE_INTRO - 1)))) { - } - - void Reset() override - { - _Reset(); - - // Never reset intro events! - if (_isIntroDone && !(extraEvents.GetPhaseMask() & (1 << (PHASE_INTRO - 1)))) - { - extraEvents.Reset(); - extraEvents.SetPhase(PHASE_EMERGED); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - } - - _hasYelledMagmaBurst = false; - _processingMagmaBurst = false; - _hasSubmergedOnce = false; - _isKnockbackEmoteAllowed = true; - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - me->SetControlled(true, UNIT_STATE_ROOT); - _lavaBurstGUIDS.clear(); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (events.IsInPhase(PHASE_SUBMERGED) && damage >= me->GetHealth()) - { - damage = 0; - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_FINISH_RAGNAROS_INTRO) - { - extraEvents.SetPhase(PHASE_INTRO); - extraEvents.ScheduleEvent(EVENT_INTRO_SAY, 5s, 0, PHASE_INTRO); - } - } - - void JustSummoned(Creature* summon) override - { - BossAI::JustSummoned(summon); - if (summon->GetEntry() == NPC_FLAME_OF_RAGNAROS) - { - summon->CastSpell((Unit*)nullptr, SPELL_INTENSE_HEAT, true, nullptr, nullptr, me->GetGUID()); - } - else if (summon->GetEntry() == NPC_SON_OF_FLAME) - { - DoZoneInCombat(summon); - } - } - - void SetGUID(ObjectGuid const& guid, int32 index) override - { - if (index == GO_LAVA_BURST) - { - if (_lavaBurstGUIDS.empty()) - { - extraEvents.ScheduleEvent(EVENT_LAVA_BURST_TRIGGER, 1ms); - } - - _lavaBurstGUIDS.insert(guid); - } - } - - void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override - { - summons.Despawn(summon); - if (events.IsInPhase(PHASE_SUBMERGED) && !summons.HasEntry(NPC_SON_OF_FLAME)) - { - HandleEmerge(); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - events.SetPhase(PHASE_EMERGED); - ScheduleCombatEvents(); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); extraEvents.Reset(); - me->SetFacingTo(DEATH_ORIENTATION); + extraEvents.SetPhase(PHASE_EMERGED); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); + me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); } - void KilledUnit(Unit* victim) override + _hasYelledMagmaBurst = false; + _processingMagmaBurst = false; + _hasSubmergedOnce = false; + _isKnockbackEmoteAllowed = true; + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); + me->SetControlled(true, UNIT_STATE_ROOT); + _lavaBurstGUIDS.clear(); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (events.IsInPhase(PHASE_SUBMERGED) && damage >= me->GetHealth()) { - if (roll_chance_i(25) && victim->IsPlayer()) + damage = 0; + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_FINISH_RAGNAROS_INTRO) + { + extraEvents.SetPhase(PHASE_INTRO); + extraEvents.ScheduleEvent(EVENT_INTRO_SAY, 5s, 0, PHASE_INTRO); + } + } + + void JustSummoned(Creature* summon) override + { + BossAI::JustSummoned(summon); + if (summon->GetEntry() == NPC_FLAME_OF_RAGNAROS) + summon->CastSpell((Unit*)nullptr, SPELL_INTENSE_HEAT, true, nullptr, nullptr, me->GetGUID()); + else if (summon->GetEntry() == NPC_SON_OF_FLAME) + DoZoneInCombat(summon); + } + + void SetGUID(ObjectGuid const& guid, int32 index) override + { + if (index == GO_LAVA_BURST) + { + if (_lavaBurstGUIDS.empty()) + extraEvents.ScheduleEvent(EVENT_LAVA_BURST_TRIGGER, 1ms); + + _lavaBurstGUIDS.insert(guid); + } + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + summons.Despawn(summon); + if (events.IsInPhase(PHASE_SUBMERGED) && !summons.HasEntry(NPC_SON_OF_FLAME)) + HandleEmerge(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + events.SetPhase(PHASE_EMERGED); + ScheduleCombatEvents(); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + extraEvents.Reset(); + me->SetFacingTo(DEATH_ORIENTATION); + } + + void KilledUnit(Unit* victim) override + { + if (roll_chance_i(25) && victim->IsPlayer()) + Talk(SAY_KILL); + } + + void AttackStart(Unit* target) override + { + if (target && me->Attack(target, true)) + DoStartNoMovement(target); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (!me->GetThreatMgr().IsThreatListEmpty()) + { + if (!_processingMagmaBurst) { - Talk(SAY_KILL); + // Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast + _processingMagmaBurst = true; + events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED); } } - - void AttackStart(Unit* target) override + else { - if (target && me->Attack(target, true)) - { - DoStartNoMovement(target); - } + BossAI::EnterEvadeMode(why); } + } - void EnterEvadeMode(EvadeReason why) override + bool CanAIAttack(Unit const* victim) const override + { + // Used for Magma Blast handling to force EnterEvadeMode if there are no melee targets + return me->IsWithinMeleeRange(victim); + } + + void UpdateAI(uint32 diff) override + { + if (!extraEvents.Empty()) { - if (!me->GetThreatMgr().IsThreatListEmpty()) - { - if (!_processingMagmaBurst) - { - // Boss try to evade, but still got some targets on threat list - it means that none of these targets are in melee range - cast magma blast - _processingMagmaBurst = true; - events.ScheduleEvent(EVENT_MAGMA_BLAST, 4s, PHASE_EMERGED, PHASE_EMERGED); - } - } - else - { - BossAI::EnterEvadeMode(why); - } - } + extraEvents.Update(diff); - bool CanAIAttack(Unit const* victim) const override - { - // Used for Magma Blast handling to force EnterEvadeMode if there are no melee targets - return me->IsWithinMeleeRange(victim); - } - - void UpdateAI(uint32 diff) override - { - if (!extraEvents.Empty()) - { - extraEvents.Update(diff); - - while (uint32 const eventId = extraEvents.ExecuteEvent()) - { - switch (eventId) - { - // Intro events - case EVENT_INTRO_SAY: - { - Talk(SAY_ARRIVAL5_RAG); - extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500ms, 0, PHASE_INTRO); - break; - } - case EVENT_INTRO_MAKE_ATTACKABLE: - { - _isIntroDone = true; - extraEvents.SetPhase(PHASE_EMERGED); - me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToAll(false); - me->SetReactState(REACT_AGGRESSIVE); - DoZoneInCombat(); - break; - } - // Submerge events - case EVENT_EMERGE: - { - HandleEmerge(); - break; - } - case EVENT_RESET_KNOCKBACK_EMOTE: - { - _isKnockbackEmoteAllowed = true; - break; - } - case EVENT_LAVA_BURST_TRIGGER: - { - if (!_lavaBurstGUIDS.empty()) - { - ObjectGuid lavaBurstGUID = Acore::Containers::SelectRandomContainerElement(_lavaBurstGUIDS); - - if (GameObject* go = ObjectAccessor::GetGameObject(*me, lavaBurstGUID)) - { - go->CastSpell(nullptr, SPELL_LAVA_BURST_TRAP); - go->SendCustomAnim(0); - } - - _lavaBurstGUIDS.erase(lavaBurstGUID); - extraEvents.Repeat(1s); - } - else - { - events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED); - } - - break; - } - } - } - } - - if (!UpdateVictim()) - { - if (!_processingMagmaBurst) - { - return; - } - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - - // Base combat events - (mainly emerge phase) - while (uint32 const eventId = events.ExecuteEvent()) + while (uint32 const eventId = extraEvents.ExecuteEvent()) { switch (eventId) { - case EVENT_WRATH_OF_RAGNAROS: + // Intro events + case EVENT_INTRO_SAY: { - DoCastVictim(SPELL_WRATH_OF_RAGNAROS); - - if (urand(0, 1)) - { - Talk(SAY_WRATH); - } - events.Repeat(25s); + Talk(SAY_ARRIVAL5_RAG); + extraEvents.ScheduleEvent(EVENT_INTRO_MAKE_ATTACKABLE, 2500ms, 0, PHASE_INTRO); break; } - case EVENT_HAND_OF_RAGNAROS: + case EVENT_INTRO_MAKE_ATTACKABLE: { - DoCastSelf(SPELL_HAND_OF_RAGNAROS); - if (_isKnockbackEmoteAllowed) + _isIntroDone = true; + extraEvents.SetPhase(PHASE_EMERGED); + me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToAll(false); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + break; + } + // Submerge events + case EVENT_EMERGE: + { + HandleEmerge(); + break; + } + case EVENT_RESET_KNOCKBACK_EMOTE: + { + _isKnockbackEmoteAllowed = true; + break; + } + case EVENT_LAVA_BURST_TRIGGER: + { + if (!_lavaBurstGUIDS.empty()) { - Talk(SAY_KNOCKBACK); + ObjectGuid lavaBurstGUID = Acore::Containers::SelectRandomContainerElement(_lavaBurstGUIDS); + + if (GameObject* go = ObjectAccessor::GetGameObject(*me, lavaBurstGUID)) + { + go->CastSpell(nullptr, SPELL_LAVA_BURST_TRAP); + go->SendCustomAnim(0); + } + + _lavaBurstGUIDS.erase(lavaBurstGUID); + extraEvents.Repeat(1s); + } + else + { + events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED); + } + + break; + } + } + } + } + + if (!UpdateVictim()) + { + if (!_processingMagmaBurst) + return; + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + // Base combat events - (mainly emerge phase) + while (uint32 const eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_WRATH_OF_RAGNAROS: + { + DoCastVictim(SPELL_WRATH_OF_RAGNAROS); + + if (urand(0, 1)) + Talk(SAY_WRATH); + events.Repeat(25s); + break; + } + case EVENT_HAND_OF_RAGNAROS: + { + DoCastSelf(SPELL_HAND_OF_RAGNAROS); + if (_isKnockbackEmoteAllowed) + { + Talk(SAY_KNOCKBACK); + _isKnockbackEmoteAllowed = false; + extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s); + } + events.Repeat(20s); + break; + } + case EVENT_LAVA_BURST: + { + DoCastAOE(SPELL_LAVA_BURST); + break; + } + case EVENT_MAGMA_BLAST: + { + _processingMagmaBurst = false; + + if (!IsVictimWithinMeleeRange()) + { + DoCastRandomTarget(SPELL_MAGMA_BLAST); + + if (!_hasYelledMagmaBurst) + { + Talk(SAY_MAGMABURST); + _hasYelledMagmaBurst = true; + } + } + + break; + } + case EVENT_MIGHT_OF_RAGNAROS: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [](Unit const* target) + { + return target->IsPlayer() && target->getPowerType() == POWER_MANA; + })) + { + if (me->CastSpell(target, SPELL_MIGHT_OF_RAGNAROS) == SPELL_CAST_OK && _isKnockbackEmoteAllowed) + { + Talk(SAY_KNOCKBACK, me); _isKnockbackEmoteAllowed = false; extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s); } - events.Repeat(20s); - break; - } - case EVENT_LAVA_BURST: - { - DoCastAOE(SPELL_LAVA_BURST); - break; - } - case EVENT_MAGMA_BLAST: - { - _processingMagmaBurst = false; - - if (!IsVictimWithinMeleeRange()) - { - DoCastRandomTarget(SPELL_MAGMA_BLAST); - - if (!_hasYelledMagmaBurst) - { - Talk(SAY_MAGMABURST); - _hasYelledMagmaBurst = true; - } - } - - break; - } - case EVENT_MIGHT_OF_RAGNAROS: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [](Unit const* target) - { - return target->IsPlayer() && target->getPowerType() == POWER_MANA; - })) - { - if (me->CastSpell(target, SPELL_MIGHT_OF_RAGNAROS) == SPELL_CAST_OK && _isKnockbackEmoteAllowed) - { - Talk(SAY_KNOCKBACK, me); - _isKnockbackEmoteAllowed = false; - extraEvents.RescheduleEvent(EVENT_RESET_KNOCKBACK_EMOTE, 5s); - } - } - events.Repeat(11s, 30s); - break; - } - case EVENT_SUBMERGE: - { - events.CancelEventGroup(PHASE_EMERGED); - events.SetPhase(PHASE_SUBMERGED); - extraEvents.SetPhase(PHASE_SUBMERGED); - me->SetReactState(REACT_PASSIVE); - me->InterruptNonMeleeSpells(false); - me->AttackStop(); - DoResetThreatList(); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED); - DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true); - //me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); - - Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1); - - DoCastAOE(SPELL_SUMMON_SONS_FLAME); - - if (!_hasSubmergedOnce) - { - _hasSubmergedOnce = true; - } - - extraEvents.ScheduleEvent(EVENT_EMERGE, 90s, PHASE_SUBMERGED, PHASE_SUBMERGED); - break; } + events.Repeat(11s, 30s); + break; } - - if (me->HasUnitState(UNIT_STATE_CASTING)) + case EVENT_SUBMERGE: { - return; + events.CancelEventGroup(PHASE_EMERGED); + events.SetPhase(PHASE_SUBMERGED); + extraEvents.SetPhase(PHASE_SUBMERGED); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(false); + me->AttackStop(); + DoResetThreatList(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED); + DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true); + //me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + + Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1); + + DoCastAOE(SPELL_SUMMON_SONS_FLAME); + + if (!_hasSubmergedOnce) + _hasSubmergedOnce = true; + + extraEvents.ScheduleEvent(EVENT_EMERGE, 90s, PHASE_SUBMERGED, PHASE_SUBMERGED); + break; } } - DoMeleeAttackIfReady(); - } - - private: - EventMap extraEvents; - bool _isIntroDone; - bool _hasYelledMagmaBurst; - bool _processingMagmaBurst; - bool _hasSubmergedOnce; - bool _isKnockbackEmoteAllowed; // Prevents possible text overlap - - GuidSet _lavaBurstGUIDS; - - void HandleEmerge() - { - if (events.IsInPhase(PHASE_EMERGED)) - { + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - } - - events.SetPhase(PHASE_EMERGED); - ScheduleCombatEvents(); - extraEvents.CancelEventGroup(PHASE_SUBMERGED); - extraEvents.SetPhase(PHASE_EMERGED); - - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); - me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - - me->RemoveAurasDueToSpell(SPELL_RAGNA_SUBMERGE_VISUAL); - - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - AttackStart(target); - } } - void ScheduleCombatEvents() - { - events.RescheduleEvent(EVENT_ERUPTION, 15s, PHASE_EMERGED, PHASE_EMERGED); - events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30s, PHASE_EMERGED, PHASE_EMERGED); - events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25s, PHASE_EMERGED, PHASE_EMERGED); - events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED); - events.RescheduleEvent(EVENT_SUBMERGE, 180s, PHASE_EMERGED, PHASE_EMERGED); - events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11s, PHASE_EMERGED, PHASE_EMERGED); - } + DoMeleeAttackIfReady(); + } - bool IsVictimWithinMeleeRange() const - { - return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()); - } - }; +private: + EventMap extraEvents; + bool _isIntroDone; + bool _hasYelledMagmaBurst; + bool _processingMagmaBurst; + bool _hasSubmergedOnce; + bool _isKnockbackEmoteAllowed; // Prevents possible text overlap - CreatureAI* GetAI(Creature* creature) const override + GuidSet _lavaBurstGUIDS; + + void HandleEmerge() { - return GetMoltenCoreAI(creature); + if (events.IsInPhase(PHASE_EMERGED)) + return; + + events.SetPhase(PHASE_EMERGED); + ScheduleCombatEvents(); + extraEvents.CancelEventGroup(PHASE_SUBMERGED); + extraEvents.SetPhase(PHASE_EMERGED); + + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); + me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + + me->RemoveAurasDueToSpell(SPELL_RAGNA_SUBMERGE_VISUAL); + + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + AttackStart(target); + } + + void ScheduleCombatEvents() + { + events.RescheduleEvent(EVENT_ERUPTION, 15s, PHASE_EMERGED, PHASE_EMERGED); + events.RescheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30s, PHASE_EMERGED, PHASE_EMERGED); + events.RescheduleEvent(EVENT_HAND_OF_RAGNAROS, 25s, PHASE_EMERGED, PHASE_EMERGED); + events.RescheduleEvent(EVENT_LAVA_BURST, 10s, PHASE_EMERGED, PHASE_EMERGED); + events.RescheduleEvent(EVENT_SUBMERGE, 180s, PHASE_EMERGED, PHASE_EMERGED); + events.RescheduleEvent(EVENT_MIGHT_OF_RAGNAROS, 11s, PHASE_EMERGED, PHASE_EMERGED); + } + + bool IsVictimWithinMeleeRange() const + { + return me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()); } }; @@ -547,9 +510,7 @@ class spell_ragnaros_summon_sons_of_flame : public SpellScript if (Unit* caster = GetCaster()) { for (uint32 spell : RagnarosSoFSpells) - { caster->CastSpell(caster, spell, true); - } } } @@ -561,7 +522,7 @@ class spell_ragnaros_summon_sons_of_flame : public SpellScript void AddSC_boss_ragnaros() { - new boss_ragnaros(); + RegisterMoltenCoreCreatureAI(boss_ragnaros); RegisterSpellScript(spell_ragnaros_lava_burst_randomizer); RegisterSpellScript(spell_ragnaros_summon_sons_of_flame); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp index 45c9f7ad1..dfac88db9 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp @@ -41,70 +41,57 @@ enum Events EVENT_SHAZZRAH_GATE, }; -class boss_shazzrah : public CreatureScript +struct boss_shazzrah : public BossAI { -public: - boss_shazzrah() : CreatureScript("boss_shazzrah") { } + boss_shazzrah(Creature* creature) : BossAI(creature, DATA_SHAZZRAH) {} - struct boss_shazzrahAI : public BossAI + void JustEngagedWith(Unit* /*target*/) override { - boss_shazzrahAI(Creature* creature) : BossAI(creature, DATA_SHAZZRAH) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2s, 4s); + events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 7s,11s); + events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 14s, 19s); + events.ScheduleEvent(EVENT_COUNTERSPELL, 9s, 10s); + events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 30s); + } - void JustEngagedWith(Unit* /*target*/) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2s, 4s); - events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 7s,11s); - events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 14s, 19s); - events.ScheduleEvent(EVENT_COUNTERSPELL, 9s, 10s); - events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 30s); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_ARCANE_EXPLOSION: { - case EVENT_ARCANE_EXPLOSION: - { - DoCastVictim(SPELL_ARCANE_EXPLOSION); - events.Repeat(4s, 5s); - break; - } - case EVENT_SHAZZRAH_CURSE: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE)) - { - DoCast(target, SPELL_SHAZZRAH_CURSE); - } - events.Repeat(23s, 26s); - break; - } - case EVENT_MAGIC_GROUNDING: - { - DoCastSelf(SPELL_MAGIC_GROUNDING); - events.Repeat(7s, 9s); - break; - } - case EVENT_COUNTERSPELL: - { - DoCastAOE(SPELL_COUNTERSPELL); - events.Repeat(15s, 18s); - break; - } - case EVENT_SHAZZRAH_GATE: - { - DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY); - events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, 3s, 6s); - events.Repeat(45s); - break; - } + DoCastVictim(SPELL_ARCANE_EXPLOSION); + events.Repeat(4s, 5s); + break; + } + case EVENT_SHAZZRAH_CURSE: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHAZZRAH_CURSE)) + DoCast(target, SPELL_SHAZZRAH_CURSE); + events.Repeat(23s, 26s); + break; + } + case EVENT_MAGIC_GROUNDING: + { + DoCastSelf(SPELL_MAGIC_GROUNDING); + events.Repeat(7s, 9s); + break; + } + case EVENT_COUNTERSPELL: + { + DoCastAOE(SPELL_COUNTERSPELL); + events.Repeat(15s, 18s); + break; + } + case EVENT_SHAZZRAH_GATE: + { + DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY); + events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, 3s, 6s); + events.Repeat(45s); + break; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; @@ -128,30 +115,22 @@ class spell_shazzrah_gate_dummy : public SpellScript Player const* plrTarget = target->ToPlayer(); // Should not target non player targets if (!plrTarget) - { return true; - } // Should skip current victim if (caster->GetVictim() == plrTarget) - { return true; - } // Should not target enemies within melee range if (plrTarget->IsWithinMeleeRange(caster)) - { return true; - } return false; }); } if (!targets.empty()) - { Acore::Containers::RandomResize(targets, 1); - } } void HandleScript(SpellEffIndex /*effIndex*/) @@ -182,7 +161,7 @@ class spell_shazzrah_gate_dummy : public SpellScript void AddSC_boss_shazzrah() { - new boss_shazzrah(); + RegisterMoltenCoreCreatureAI(boss_shazzrah); // Spells RegisterSpellScript(spell_shazzrah_gate_dummy); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp index edc39e8cc..3eb80a537 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp @@ -47,172 +47,138 @@ enum Events EVENT_IMMOLATE, }; -class boss_sulfuron : public CreatureScript +struct boss_sulfuron : public BossAI { -public: - boss_sulfuron() : CreatureScript("boss_sulfuron") {} + boss_sulfuron(Creature* creature) : BossAI(creature, DATA_SULFURON) {} - struct boss_sulfuronAI : public BossAI + void JustEngagedWith(Unit* /*who*/) override { - boss_sulfuronAI(Creature* creature) : BossAI(creature, DATA_SULFURON) {} + _JustEngagedWith(); + events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 6s, 20s); + events.ScheduleEvent(EVENT_INSPIRE, 7s, 10s); + events.ScheduleEvent(EVENT_KNOCKDOWN, 6s); + events.ScheduleEvent(EVENT_FLAMESPEAR, 2s); + } - void JustEngagedWith(Unit* /*who*/) override + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) { - _JustEngagedWith(); - events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 6s, 20s); - events.ScheduleEvent(EVENT_INSPIRE, 7s, 10s); - events.ScheduleEvent(EVENT_KNOCKDOWN, 6s); - events.ScheduleEvent(EVENT_FLAMESPEAR, 2s); - } - - void ExecuteEvent(uint32 eventId) override - { - switch (eventId) + case EVENT_DEMORALIZING_SHOUT: { - case EVENT_DEMORALIZING_SHOUT: - { - DoCastVictim(SPELL_DEMORALIZING_SHOUT); - events.Repeat(12s, 18s); - break; - } - case EVENT_INSPIRE: - { - std::list healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE); - if (!healers.empty()) - { - DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE); - } + DoCastVictim(SPELL_DEMORALIZING_SHOUT); + events.Repeat(12s, 18s); + break; + } + case EVENT_INSPIRE: + { + std::list healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE); + if (!healers.empty()) + DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE); - DoCastSelf(SPELL_INSPIRE); - events.Repeat(13s, 20s); - break; - } - case EVENT_KNOCKDOWN: - { - DoCastVictim(SPELL_KNOCKDOWN); - events.Repeat(10s, 20s); - break; - } - case EVENT_FLAMESPEAR: - { - DoCastRandomTarget(SPELL_FLAMESPEAR); - events.Repeat(12s, 16s); - break; - } + DoCastSelf(SPELL_INSPIRE); + events.Repeat(13s, 20s); + break; + } + case EVENT_KNOCKDOWN: + { + DoCastVictim(SPELL_KNOCKDOWN); + events.Repeat(10s, 20s); + break; + } + case EVENT_FLAMESPEAR: + { + DoCastRandomTarget(SPELL_FLAMESPEAR); + events.Repeat(12s, 16s); + break; } } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } }; -class npc_flamewaker_priest : public CreatureScript +struct npc_flamewaker_priest : public ScriptedAI { -public: - npc_flamewaker_priest() : CreatureScript("npc_flamewaker_priest") {} + npc_flamewaker_priest(Creature* creature) : ScriptedAI(creature) {} - struct npc_flamewaker_priestAI : public ScriptedAI + void Reset() override { - npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature) {} + events.Reset(); + } - void Reset() override - { - events.Reset(); - } + void JustDied(Unit* /*killer*/) override + { + events.Reset(); + } - void JustDied(Unit* /*killer*/) override - { - events.Reset(); - } + void JustEngagedWith(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_DARK_STRIKE, 4s, 7s); + events.ScheduleEvent(EVENT_DARK_MENDING, 15s, 30s); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2s, 4s); + events.ScheduleEvent(EVENT_IMMOLATE, 3500ms, 6s); + } - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_DARK_STRIKE, 4s, 7s); - events.ScheduleEvent(EVENT_DARK_MENDING, 15s, 30s); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2s, 4s); - events.ScheduleEvent(EVENT_IMMOLATE, 3500ms, 6s); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void UpdateAI(uint32 diff) override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 const eventId = events.ExecuteEvent()) { - if (!UpdateVictim()) + switch (eventId) { - return; + case EVENT_DARK_STRIKE: + { + DoCastVictim(SPELL_DARK_STRIKE); + events.Repeat(4s, 7s); + break; + } + case EVENT_DARK_MENDING: + { + if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1)) + { + if (target->GetGUID() != me->GetGUID()) + { + DoCast(target, SPELL_DARK_MENDING); + } + } + events.Repeat(15s, 20s); + break; + } + case EVENT_SHADOW_WORD_PAIN: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHADOW_WORD_PAIN)) + DoCast(target, SPELL_SHADOW_WORD_PAIN); + events.Repeat(2500ms, 5s); + break; + } + case EVENT_IMMOLATE: + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IMMOLATE)) + DoCast(target, SPELL_IMMOLATE); + events.Repeat(5s, 7s); + break; + } } - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - { return; - } - - while (uint32 const eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DARK_STRIKE: - { - DoCastVictim(SPELL_DARK_STRIKE); - events.Repeat(4s, 7s); - break; - } - case EVENT_DARK_MENDING: - { - if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1)) - { - if (target->GetGUID() != me->GetGUID()) - { - DoCast(target, SPELL_DARK_MENDING); - } - } - events.Repeat(15s, 20s); - break; - } - case EVENT_SHADOW_WORD_PAIN: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_SHADOW_WORD_PAIN)) - { - DoCast(target, SPELL_SHADOW_WORD_PAIN); - } - events.Repeat(2500ms, 5s); - break; - } - case EVENT_IMMOLATE: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_IMMOLATE)) - { - DoCast(target, SPELL_IMMOLATE); - } - events.Repeat(5s, 7s); - break; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - return; - } - } - - DoMeleeAttackIfReady(); } - private: - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); + DoMeleeAttackIfReady(); } + +private: + EventMap events; }; void AddSC_boss_sulfuron() { - new boss_sulfuron(); - new npc_flamewaker_priest(); + RegisterMoltenCoreCreatureAI(boss_sulfuron); + RegisterMoltenCoreCreatureAI(npc_flamewaker_priest); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp index e9163cb89..b51e49018 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp @@ -53,384 +53,331 @@ MCBossObject const linkedBossObjData[MAX_MC_LINKED_BOSS_OBJ]= constexpr uint8 SAY_SPAWN = 1; -class instance_molten_core : public InstanceMapScript +struct instance_molten_core : public InstanceScript { -public: - instance_molten_core() : InstanceMapScript(MCScriptName, MAP_MOLTEN_CORE) {} - - struct instance_molten_core_InstanceMapScript : public InstanceScript + instance_molten_core(Map* map) : InstanceScript(map) { - instance_molten_core_InstanceMapScript(Map* map) : InstanceScript(map) - { - SetHeaders(DataHeader); - SetBossNumber(MAX_ENCOUNTER); - LoadMinionData(minionData); - } - - void OnPlayerEnter(Player* /*player*/) override - { - if (CheckMajordomoExecutus()) - { - SummonMajordomoExecutus(); - } - } - - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_GOLEMAGG_THE_INCINERATOR: - { - _golemaggGUID = creature->GetGUID(); - break; - } - case NPC_CORE_RAGER: - { - _golemaggMinionsGUIDS.insert(creature->GetGUID()); - break; - } - case NPC_MAJORDOMO_EXECUTUS: - { - _majordomoExecutusGUID = creature->GetGUID(); - break; - } - case NPC_GARR: - { - _garrGUID = creature->GetGUID(); - break; - } - case NPC_RAGNAROS: - { - _ragnarosGUID = creature->GetGUID(); - break; - } - case NPC_FIRESWORN: - case NPC_FLAMEWALKER: - case NPC_FLAMEWALKER_PROTECTOR: - case NPC_FLAMEWALKER_PRIEST: - case NPC_FLAMEWALKER_HEALER: - case NPC_FLAMEWALKER_ELITE: - { - AddMinion(creature); - break; - } - } - } - - void OnCreatureRemove(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_FIRESWORN: - { - RemoveMinion(creature); - break; - } - case NPC_FLAMEWALKER: - case NPC_FLAMEWALKER_PROTECTOR: - case NPC_FLAMEWALKER_PRIEST: - case NPC_FLAMEWALKER_HEALER: - case NPC_FLAMEWALKER_ELITE: - { - RemoveMinion(creature); - break; - } - } - } - - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_CACHE_OF_THE_FIRELORD: - { - _cacheOfTheFirelordGUID = go->GetGUID(); - break; - } - case GO_CIRCLE_GEDDON: - case GO_CIRCLE_GARR: - case GO_CIRCLE_GEHENNAS: - case GO_CIRCLE_GOLEMAGG: - case GO_CIRCLE_MAGMADAR: - case GO_CIRCLE_SHAZZRAH: - case GO_CIRCLE_SULFURON: - { - for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i) - { - if (linkedBossObjData[i].circleId != go->GetEntry()) - { - continue; - } - - if (GetBossState(linkedBossObjData[i].bossId) == DONE) - { - go->DespawnOrUnsummon(0ms, Seconds(WEEK)); - } - else - { - _circlesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID(); - } - } - - break; - } - case GO_RUNE_KRESS: - case GO_RUNE_MOHN: - case GO_RUNE_BLAZ: - case GO_RUNE_MAZJ: - case GO_RUNE_ZETH: - case GO_RUNE_THERI: - case GO_RUNE_KORO: - { - for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i) - { - if (linkedBossObjData[i].runeId != go->GetEntry()) - { - continue; - } - - if (GetBossState(linkedBossObjData[i].bossId) == DONE) - { - go->UseDoorOrButton(WEEK * IN_MILLISECONDS); - } - else - { - _runesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID(); - } - } - break; - } - case GO_LAVA_STEAM: - { - _lavaSteamGUID = go->GetGUID(); - break; - } - case GO_LAVA_SPLASH: - { - _lavaSplashGUID = go->GetGUID(); - break; - } - case GO_LAVA_BURST: - { - if (Creature* ragnaros = instance->GetCreature(_ragnarosGUID)) - { - ragnaros->AI()->SetGUID(go->GetGUID(), GO_LAVA_BURST); - } - break; - } - } - } - - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case DATA_GOLEMAGG: - return _golemaggGUID; - case DATA_MAJORDOMO_EXECUTUS: - return _majordomoExecutusGUID; - case DATA_GARR: - return _garrGUID; - case DATA_LAVA_STEAM: - return _lavaSteamGUID; - case DATA_LAVA_SPLASH: - return _lavaSplashGUID; - case DATA_RAGNAROS: - return _ragnarosGUID; - } - - return ObjectGuid::Empty; - } - - bool SetBossState(uint32 bossId, EncounterState state) override - { - if (!InstanceScript::SetBossState(bossId, state)) - { - return false; - } - - if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE) - { - if (GameObject* cache = instance->GetGameObject(_cacheOfTheFirelordGUID)) - { - cache->SetRespawnTime(7 * DAY); - cache->SetLootRecipient(instance); - } - } - else if (bossId == DATA_GOLEMAGG) - { - switch (state) - { - case NOT_STARTED: - case FAIL: - { - if (!_golemaggMinionsGUIDS.empty()) - { - for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) - { - Creature* minion = instance->GetCreature(minionGuid); - if (minion && minion->isDead()) - { - minion->Respawn(); - } - } - } - break; - } - case IN_PROGRESS: - { - if (!_golemaggMinionsGUIDS.empty()) - { - for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) - { - if (Creature* minion = instance->GetCreature(minionGuid)) - { - minion->AI()->DoZoneInCombat(nullptr, 150.0f); - } - } - } - break; - } - case DONE: - { - if (!_golemaggMinionsGUIDS.empty()) - { - for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) - { - if (Creature* minion = instance->GetCreature(minionGuid)) - { - minion->CastSpell(minion, SPELL_CORE_RAGER_QUIET_SUICIDE, true); - } - } - _golemaggMinionsGUIDS.clear(); - } - break; - } - default: - break; - } - } - // Perform needed checks for Majordomu - if (bossId < DATA_MAJORDOMO_EXECUTUS && state == DONE) - { - if (GameObject* circle = instance->GetGameObject(_circlesGUIDs[bossId])) - { - circle->DespawnOrUnsummon(0ms, Seconds(WEEK)); - _circlesGUIDs[bossId].Clear(); - } - - if (GameObject* rune = instance->GetGameObject(_runesGUIDs[bossId])) - { - rune->UseDoorOrButton(WEEK * IN_MILLISECONDS); - _runesGUIDs[bossId].Clear(); - } - - if (CheckMajordomoExecutus()) - { - SummonMajordomoExecutus(); - } - } - - return true; - } - - void DoAction(int32 action) override - { - if (action == ACTION_RESET_GOLEMAGG_ENCOUNTER) - { - if (Creature* golemagg = instance->GetCreature(_golemaggGUID)) - { - golemagg->AI()->EnterEvadeMode(); - } - - if (!_golemaggMinionsGUIDS.empty()) - { - for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) - { - if (Creature* minion = instance->GetCreature(minionGuid)) - { - minion->AI()->EnterEvadeMode(); - } - } - } - } - } - - void SummonMajordomoExecutus() - { - if (instance->GetCreature(_majordomoExecutusGUID)) - { - return; - } - - if (GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) - { - if (Creature* creature = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoSummonPos)) - { - creature->AI()->Talk(SAY_SPAWN); - } - } - else - { - instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoRagnaros); - } - } - - bool CheckMajordomoExecutus() const - { - if (GetBossState(DATA_RAGNAROS) == DONE) - { - return false; - } - - for (uint8 i = 0; i < DATA_MAJORDOMO_EXECUTUS; ++i) - { - if (i == DATA_LUCIFRON) - { - continue; - } - - if (GetBossState(i) != DONE) - { - return false; - } - } - - // Prevent spawning if Ragnaros is present - if (instance->GetCreature(_ragnarosGUID)) - { - return false; - } - - return true; - } - - private: - std::unordered_map _circlesGUIDs; - std::unordered_map _runesGUIDs; - - // Golemagg encounter related - ObjectGuid _golemaggGUID; - GuidSet _golemaggMinionsGUIDS; - - // Ragnaros encounter related - ObjectGuid _ragnarosGUID; - ObjectGuid _lavaSteamGUID; - ObjectGuid _lavaSplashGUID; - - ObjectGuid _majordomoExecutusGUID; - ObjectGuid _cacheOfTheFirelordGUID; - ObjectGuid _garrGUID; - ObjectGuid _magmadarGUID; - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_molten_core_InstanceMapScript(map); + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + LoadMinionData(minionData); } + + void OnPlayerEnter(Player* /*player*/) override + { + if (CheckMajordomoExecutus()) + SummonMajordomoExecutus(); + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_GOLEMAGG_THE_INCINERATOR: + { + _golemaggGUID = creature->GetGUID(); + break; + } + case NPC_CORE_RAGER: + { + _golemaggMinionsGUIDS.insert(creature->GetGUID()); + break; + } + case NPC_MAJORDOMO_EXECUTUS: + { + _majordomoExecutusGUID = creature->GetGUID(); + break; + } + case NPC_GARR: + { + _garrGUID = creature->GetGUID(); + break; + } + case NPC_RAGNAROS: + { + _ragnarosGUID = creature->GetGUID(); + break; + } + case NPC_FIRESWORN: + case NPC_FLAMEWALKER: + case NPC_FLAMEWALKER_PROTECTOR: + case NPC_FLAMEWALKER_PRIEST: + case NPC_FLAMEWALKER_HEALER: + case NPC_FLAMEWALKER_ELITE: + { + AddMinion(creature); + break; + } + } + } + + void OnCreatureRemove(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_FIRESWORN: + { + RemoveMinion(creature); + break; + } + case NPC_FLAMEWALKER: + case NPC_FLAMEWALKER_PROTECTOR: + case NPC_FLAMEWALKER_PRIEST: + case NPC_FLAMEWALKER_HEALER: + case NPC_FLAMEWALKER_ELITE: + { + RemoveMinion(creature); + break; + } + } + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_CACHE_OF_THE_FIRELORD: + { + _cacheOfTheFirelordGUID = go->GetGUID(); + break; + } + case GO_CIRCLE_GEDDON: + case GO_CIRCLE_GARR: + case GO_CIRCLE_GEHENNAS: + case GO_CIRCLE_GOLEMAGG: + case GO_CIRCLE_MAGMADAR: + case GO_CIRCLE_SHAZZRAH: + case GO_CIRCLE_SULFURON: + { + for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i) + { + if (linkedBossObjData[i].circleId != go->GetEntry()) + continue; + + if (GetBossState(linkedBossObjData[i].bossId) == DONE) + go->DespawnOrUnsummon(0ms, Seconds(WEEK)); + else + _circlesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID(); + } + + break; + } + case GO_RUNE_KRESS: + case GO_RUNE_MOHN: + case GO_RUNE_BLAZ: + case GO_RUNE_MAZJ: + case GO_RUNE_ZETH: + case GO_RUNE_THERI: + case GO_RUNE_KORO: + { + for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i) + { + if (linkedBossObjData[i].runeId != go->GetEntry()) + continue; + + if (GetBossState(linkedBossObjData[i].bossId) == DONE) + go->UseDoorOrButton(WEEK * IN_MILLISECONDS); + else + _runesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID(); + } + break; + } + case GO_LAVA_STEAM: + { + _lavaSteamGUID = go->GetGUID(); + break; + } + case GO_LAVA_SPLASH: + { + _lavaSplashGUID = go->GetGUID(); + break; + } + case GO_LAVA_BURST: + { + if (Creature* ragnaros = instance->GetCreature(_ragnarosGUID)) + ragnaros->AI()->SetGUID(go->GetGUID(), GO_LAVA_BURST); + break; + } + } + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_GOLEMAGG: + return _golemaggGUID; + case DATA_MAJORDOMO_EXECUTUS: + return _majordomoExecutusGUID; + case DATA_GARR: + return _garrGUID; + case DATA_LAVA_STEAM: + return _lavaSteamGUID; + case DATA_LAVA_SPLASH: + return _lavaSplashGUID; + case DATA_RAGNAROS: + return _ragnarosGUID; + } + + return ObjectGuid::Empty; + } + + bool SetBossState(uint32 bossId, EncounterState state) override + { + if (!InstanceScript::SetBossState(bossId, state)) + return false; + + if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE) + { + if (GameObject* cache = instance->GetGameObject(_cacheOfTheFirelordGUID)) + { + cache->SetRespawnTime(7 * DAY); + cache->SetLootRecipient(instance); + } + } + else if (bossId == DATA_GOLEMAGG) + { + switch (state) + { + case NOT_STARTED: + case FAIL: + { + if (!_golemaggMinionsGUIDS.empty()) + { + for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) + { + Creature* minion = instance->GetCreature(minionGuid); + if (minion && minion->isDead()) + minion->Respawn(); + } + } + break; + } + case IN_PROGRESS: + { + if (!_golemaggMinionsGUIDS.empty()) + { + for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) + { + if (Creature* minion = instance->GetCreature(minionGuid)) + minion->AI()->DoZoneInCombat(nullptr, 150.0f); + } + } + break; + } + case DONE: + { + if (!_golemaggMinionsGUIDS.empty()) + { + for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) + { + if (Creature* minion = instance->GetCreature(minionGuid)) + minion->CastSpell(minion, SPELL_CORE_RAGER_QUIET_SUICIDE, true); + } + _golemaggMinionsGUIDS.clear(); + } + break; + } + default: + break; + } + } + // Perform needed checks for Majordomu + if (bossId < DATA_MAJORDOMO_EXECUTUS && state == DONE) + { + if (GameObject* circle = instance->GetGameObject(_circlesGUIDs[bossId])) + { + circle->DespawnOrUnsummon(0ms, Seconds(WEEK)); + _circlesGUIDs[bossId].Clear(); + } + + if (GameObject* rune = instance->GetGameObject(_runesGUIDs[bossId])) + { + rune->UseDoorOrButton(WEEK * IN_MILLISECONDS); + _runesGUIDs[bossId].Clear(); + } + + if (CheckMajordomoExecutus()) + SummonMajordomoExecutus(); + } + + return true; + } + + void DoAction(int32 action) override + { + if (action == ACTION_RESET_GOLEMAGG_ENCOUNTER) + { + if (Creature* golemagg = instance->GetCreature(_golemaggGUID)) + golemagg->AI()->EnterEvadeMode(); + + if (!_golemaggMinionsGUIDS.empty()) + { + for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS) + { + if (Creature* minion = instance->GetCreature(minionGuid)) + minion->AI()->EnterEvadeMode(); + } + } + } + } + + void SummonMajordomoExecutus() + { + if (instance->GetCreature(_majordomoExecutusGUID)) + return; + + if (GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE) + { + if (Creature* creature = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoSummonPos)) + creature->AI()->Talk(SAY_SPAWN); + } + else + { + instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, MajordomoRagnaros); + } + } + + bool CheckMajordomoExecutus() const + { + if (GetBossState(DATA_RAGNAROS) == DONE) + return false; + + for (uint8 i = 0; i < DATA_MAJORDOMO_EXECUTUS; ++i) + { + if (i == DATA_LUCIFRON) + continue; + + if (GetBossState(i) != DONE) + return false; + } + + // Prevent spawning if Ragnaros is present + if (instance->GetCreature(_ragnarosGUID)) + return false; + + return true; + } + +private: + std::unordered_map _circlesGUIDs; + std::unordered_map _runesGUIDs; + + // Golemagg encounter related + ObjectGuid _golemaggGUID; + GuidSet _golemaggMinionsGUIDS; + + // Ragnaros encounter related + ObjectGuid _ragnarosGUID; + ObjectGuid _lavaSteamGUID; + ObjectGuid _lavaSplashGUID; + + ObjectGuid _majordomoExecutusGUID; + ObjectGuid _cacheOfTheFirelordGUID; + ObjectGuid _garrGUID; + ObjectGuid _magmadarGUID; }; void AddSC_instance_molten_core() { - new instance_molten_core(); + RegisterInstanceScript(instance_molten_core, MAP_MOLTEN_CORE); } diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp index 117f06926..4b9548ecf 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.cpp @@ -46,75 +46,60 @@ enum Spells }; // Serrated Bites timer may be wrong -class npc_mc_core_hound : public CreatureScript +struct npc_mc_core_hound : public CreatureAI { -public: - npc_mc_core_hound() : CreatureScript("npc_mc_core_hound") {} - - struct npc_mc_core_houndAI : public CreatureAI + npc_mc_core_hound(Creature* creature) : + CreatureAI(creature), + instance(creature->GetInstanceScript()), + serratedBiteTimer(3000) { - npc_mc_core_houndAI(Creature* creature) : - CreatureAI(creature), - instance(creature->GetInstanceScript()), - serratedBiteTimer(3000) - { - } - - void Reset() override - { - serratedBiteTimer = 3000; - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override - { - // Prevent receiving any extra damage if Hound is playing dead - if (me->HasAura(SPELL_PLAY_DEAD)) - { - damage = 0; - return; - } - else if (me->GetHealth() <= damage) - { - damage = 0; - Talk(EMOTE_SMOLDERING); - DoCastSelf(SPELL_PLAY_DEAD); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - return; - } - - if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_PLAY_DEAD)) - { - return; - } - - if (serratedBiteTimer <= diff) - { - DoCastVictim(SPELL_SERRATED_BITE); - serratedBiteTimer = urand(5000, 6000); - } - else - { - serratedBiteTimer -= diff; - } - - DoMeleeAttackIfReady(); - } - - private: - InstanceScript* instance; - uint32 serratedBiteTimer; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetMoltenCoreAI(creature); } + + void Reset() override + { + serratedBiteTimer = 3000; + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override + { + // Prevent receiving any extra damage if Hound is playing dead + if (me->HasAura(SPELL_PLAY_DEAD)) + { + damage = 0; + return; + } + else if (me->GetHealth() <= damage) + { + damage = 0; + Talk(EMOTE_SMOLDERING); + DoCastSelf(SPELL_PLAY_DEAD); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_PLAY_DEAD)) + return; + + if (serratedBiteTimer <= diff) + { + DoCastVictim(SPELL_SERRATED_BITE); + serratedBiteTimer = urand(5000, 6000); + } + else + { + serratedBiteTimer -= diff; + } + + DoMeleeAttackIfReady(); + } + +private: + InstanceScript* instance; + uint32 serratedBiteTimer; }; // 19822 Play Dead @@ -136,9 +121,7 @@ class spell_mc_play_dead_aura : public AuraScript { Creature* creatureTarget = GetTarget()->ToCreature(); if (!creatureTarget) - { return; - } creatureTarget->CastSpell(creatureTarget, SPELL_PLAY_DEAD_PACIFY, true); creatureTarget->SetDynamicFlag(UNIT_DYNFLAG_DEAD); @@ -154,9 +137,7 @@ class spell_mc_play_dead_aura : public AuraScript { Creature* creatureTarget = GetTarget()->ToCreature(); if (!creatureTarget) - { return; - } creatureTarget->RemoveAurasDueToSpell(SPELL_PLAY_DEAD_PACIFY); creatureTarget->RemoveDynamicFlag(UNIT_DYNFLAG_DEAD); @@ -166,9 +147,7 @@ class spell_mc_play_dead_aura : public AuraScript creatureTarget->SetReactState(REACT_AGGRESSIVE); if (!creatureTarget->IsInCombat()) - { return; - } bool shouldDie = true; std::list hounds; @@ -246,9 +225,7 @@ struct npc_lava_spawn : public ScriptedAI void UpdateAI(uint32 diff) override { if (!UpdateVictim()) - { return; - } _scheduler.Update(diff); @@ -262,7 +239,7 @@ private: void AddSC_molten_core() { // Creatures - new npc_mc_core_hound(); + RegisterMoltenCoreCreatureAI(npc_mc_core_hound); RegisterCreatureAI(npc_lava_spawn); // Spells diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h index 0dea07421..ca58eee1d 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h @@ -127,4 +127,7 @@ inline AI* GetMoltenCoreAI(T* obj) return GetInstanceAI(obj, MCScriptName); } +#define RegisterMoltenCoreCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMoltenCoreAI) +#define RegisterMoltenCoreGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetMoltenCoreAI) + #endif