From a2eaa5739423fe613f66bce0d118a097edf150ef Mon Sep 17 00:00:00 2001 From: Razor2142 Date: Tue, 25 Feb 2025 19:40:42 +0100 Subject: [PATCH] fix(Scripts/Naxxramas): refactored instance script (#21539) --- .../rev_1739822360188928600.sql | 8 + .../Northrend/Naxxramas/boss_anubrekhan.cpp | 2 +- .../Northrend/Naxxramas/boss_faerlina.cpp | 9 +- .../Naxxramas/boss_four_horsemen.cpp | 50 +- .../Northrend/Naxxramas/boss_gluth.cpp | 14 +- .../Northrend/Naxxramas/boss_gothik.cpp | 79 +- .../Northrend/Naxxramas/boss_grobbulus.cpp | 17 +- .../Northrend/Naxxramas/boss_heigan.cpp | 71 +- .../Northrend/Naxxramas/boss_kelthuzad.cpp | 119 +- .../Northrend/Naxxramas/boss_loatheb.cpp | 33 +- .../Northrend/Naxxramas/boss_maexxna.cpp | 22 +- .../scripts/Northrend/Naxxramas/boss_noth.cpp | 31 +- .../Northrend/Naxxramas/boss_patchwerk.cpp | 18 +- .../Northrend/Naxxramas/boss_razuvious.cpp | 43 +- .../Northrend/Naxxramas/boss_sapphiron.cpp | 15 +- .../Northrend/Naxxramas/boss_thaddius.cpp | 133 +- .../Naxxramas/instance_naxxramas.cpp | 1844 ++++++----------- .../scripts/Northrend/Naxxramas/naxxramas.h | 301 ++- 18 files changed, 1053 insertions(+), 1756 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1739822360188928600.sql diff --git a/data/sql/updates/pending_db_world/rev_1739822360188928600.sql b/data/sql/updates/pending_db_world/rev_1739822360188928600.sql new file mode 100644 index 000000000..77db67f34 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1739822360188928600.sql @@ -0,0 +1,8 @@ +-- update Mr. Bigglesworth script name +UPDATE `creature_template` SET `ScriptName` = 'npc_mr_bigglesworth' WHERE (`entry` = 16998); + +-- update Living Poison script name +UPDATE `creature_template` SET `ScriptName` = 'npc_living_poison' WHERE (`entry` = 16027); + +-- update Naxxramas Trigger script name +UPDATE `creature_template` SET `ScriptName` = 'npc_naxxramas_trigger' WHERE (`entry` = 16082); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index f89542bba..b8cc1d9c2 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -118,7 +118,7 @@ public: Talk(SAY_SLAY); victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID()); - instance->SetData(DATA_IMMORTAL_FAIL, 0); + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustEngagedWith(Unit* who) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 1be14803f..9ab1fcde0 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -83,8 +83,6 @@ public: BossAI::Reset(); summons.DespawnAll(); SummonHelpers(); - if (GameObject* go = me->GetMap()->GetGameObject(instance->GetGuidData(DATA_FAERLINA_WEB))) - go->SetGoState(GO_STATE_ACTIVE); } void JustEngagedWith(Unit* who) override @@ -114,9 +112,6 @@ public: else context.Repeat(30s); }); - - if (GameObject* go = me->GetMap()->GetGameObject(instance->GetGuidData(DATA_FAERLINA_WEB))) - go->SetGoState(GO_STATE_READY); } void MoveInLineOfSight(Unit* who) override @@ -137,15 +132,13 @@ public: if (!urand(0, 3)) Talk(SAY_SLAY); - instance->SetData(DATA_IMMORTAL_FAIL, 0); + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); - if (GameObject* go = me->GetMap()->GetGameObject(instance->GetGuidData(DATA_FAERLINA_WEB))) - go->SetGoState(GO_STATE_ACTIVE); } void SpellHit(Unit* caster, SpellInfo const* spell) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index 0308ab316..6439f45ad 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -131,7 +131,6 @@ public: { explicit boss_four_horsemenAI(Creature* c) : BossAI(c, BOSS_HORSEMAN) { - pInstance = me->GetInstanceScript(); switch (me->GetEntry()) { case NPC_SIR_ZELIEK: @@ -150,7 +149,6 @@ public: } EventMap events; - InstanceScript* pInstance; uint8 currentWaypoint{}; uint8 movementPhase{}; uint8 horsemanId; @@ -203,16 +201,6 @@ public: { events.RescheduleEvent(EVENT_SECONDARY_SPELL, 15s); } - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE))) - { - if (pInstance->GetBossState(BOSS_GOTHIK) == DONE) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } - } } void MovementInform(uint32 type, uint32 id) override @@ -262,36 +250,19 @@ public: return; Talk(SAY_SLAY); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override { BossAI::JustDied(killer); - if (pInstance) - { - if (pInstance->GetBossState(BOSS_HORSEMAN) == DONE) - { - if (!me->GetMap()->GetPlayers().IsEmpty()) - { - if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource()) - { - if (GameObject* chest = player->SummonGameObject(RAID_MODE(GO_HORSEMEN_CHEST_10, GO_HORSEMEN_CHEST_25), 2514.8f, -2944.9f, 245.55f, 5.51f, 0, 0, 0, 0, 0)) - { - chest->SetLootRecipient(me); - } - } - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } - } Talk(SAY_DEATH); + + if (instance->GetBossState(BOSS_HORSEMAN) == DONE) + if (!me->GetMap()->GetPlayers().IsEmpty()) + if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource()) + if (GameObject* chest = player->SummonGameObject(RAID_MODE(GO_HORSEMEN_CHEST_10, GO_HORSEMEN_CHEST_25), 2514.8f, -2944.9f, 245.55f, 5.51f, 0, 0, 0, 0, 0)) + chest->SetLootRecipient(me); } void JustEngagedWith(Unit* who) override @@ -305,13 +276,6 @@ public: me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true); MoveToCorner(); } - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index cea3baccf..30b678a87 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -79,13 +79,10 @@ public: struct boss_gluthAI : public BossAI { explicit boss_gluthAI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} EventMap events; SummonList summons; - InstanceScript* pInstance; void Reset() override { @@ -138,13 +135,10 @@ public: void KilledUnit(Unit* who) override { if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW) - { me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f)); - } - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index fd4bb92e7..939f0bf19 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -201,12 +201,10 @@ public: struct boss_gothikAI : public BossAI { explicit boss_gothikAI(Creature* c) : BossAI(c, BOSS_GOTHIK), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} + EventMap events; SummonList summons; - InstanceScript* pInstance; bool secondPhase{}; bool gateOpened{}; uint8 waveCount{}; @@ -233,21 +231,6 @@ public: gateOpened = false; waveCount = 0; me->NearTeleportTo(2642.139f, -3386.959f, 285.492f, 6.265f); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_EXIT_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void JustEngagedWith(Unit* who) override @@ -261,17 +244,6 @@ public: me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); events.ScheduleEvent(EVENT_SUMMON_ADDS, 30s); events.ScheduleEvent(EVENT_CHECK_PLAYERS, 2min); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void JustSummoned(Creature* summon) override @@ -327,10 +299,7 @@ public: return; Talk(SAY_KILL); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override @@ -338,21 +307,6 @@ public: BossAI::JustDied(killer); Talk(SAY_DEATH); summons.DespawnAll(); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_EXIT_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void SummonHelpers(uint32 entry) @@ -472,12 +426,11 @@ public: events.Repeat(20s); break; case EVENT_CHECK_HEALTH: - if (me->HealthBelowPct(30) && pInstance) + if (me->HealthBelowPct(30)) { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE))) - { + if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE)) go->SetGoState(GO_STATE_ACTIVE); - } + events.CancelEvent(EVENT_TELEPORT); break; } @@ -509,10 +462,9 @@ public: case EVENT_CHECK_PLAYERS: if (!CheckGroupSplitted()) { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE))) - { + if (GameObject* go = instance->GetGameObject(DATA_GOTHIK_INNER_GATE)) go->SetGoState(GO_STATE_ACTIVE); - } + gateOpened = true; Talk(EMOTE_GATE_OPENED); } @@ -597,10 +549,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && me->GetInstanceScript()) - { - me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override @@ -767,17 +717,14 @@ public: // dead side summons are "owned" by gothik void JustSummoned(Creature* summon) override { - if (Creature* gothik = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(DATA_GOTHIK_BOSS))) - { + if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS)) gothik->AI()->JustSummoned(summon); - } } + void SummonedCreatureDespawn(Creature* summon) override { - if (Creature* gothik = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(DATA_GOTHIK_BOSS))) - { + if (Creature* gothik = me->GetInstanceScript()->GetCreature(DATA_GOTHIK_BOSS)) gothik->AI()->SummonedCreatureDespawn(summon); - } } }; }; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index 39a84201e..fd3f395f8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -70,13 +70,10 @@ public: struct boss_grobbulusAI : public BossAI { explicit boss_grobbulusAI(Creature* c) : BossAI(c, BOSS_GROBBULUS), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} EventMap events; SummonList summons; - InstanceScript* pInstance; uint32 dropSludgeTimer{}; void Reset() override @@ -138,10 +135,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override @@ -217,10 +212,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && me->GetInstanceScript()) - { - me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp index c91f67ba7..de73995e9 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp @@ -69,11 +69,8 @@ public: struct boss_heiganAI : public BossAI { explicit boss_heiganAI(Creature* c) : BossAI(c, BOSS_HEIGAN) - { - pInstance = me->GetInstanceScript(); - } + {} - InstanceScript* pInstance; EventMap events; uint8 currentPhase{}; uint8 currentSection{}; @@ -86,13 +83,6 @@ public: currentPhase = 0; currentSection = 3; moveRight = true; - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_ENTER_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void KilledUnit(Unit* who) override @@ -101,10 +91,7 @@ public: return; Talk(SAY_SLAY); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override @@ -118,13 +105,6 @@ public: BossAI::JustEngagedWith(who); me->SetInCombatWithZone(); Talk(SAY_AGGRO); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_ENTER_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } StartFightPhase(PHASE_SLOW_DANCE); } @@ -206,41 +186,38 @@ public: } break; case EVENT_ERUPT_SECTION: - if (pInstance) - { - pInstance->SetData(DATA_HEIGAN_ERUPTION, currentSection); - if (currentSection == 3) - { - moveRight = false; - } - else if (currentSection == 0) - { - moveRight = true; - } - moveRight ? currentSection++ : currentSection--; - } + { + instance->SetData(DATA_HEIGAN_ERUPTION, currentSection); + if (currentSection == 3) + moveRight = false; + else if (currentSection == 0) + moveRight = true; + + moveRight ? currentSection++ : currentSection--; + if (currentPhase == PHASE_SLOW_DANCE) - { Talk(SAY_TAUNT); - } + events.Repeat(currentPhase == PHASE_SLOW_DANCE ? 10s : 4s); break; + } case EVENT_SAFETY_DANCE: + { + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + for (auto const& itr : pList) { - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - for (auto const& itr : pList) + if (IsInRoom(itr.GetSource()) && !itr.GetSource()->IsAlive()) { - if (IsInRoom(itr.GetSource()) && !itr.GetSource()->IsAlive()) - { - pInstance->SetData(DATA_DANCE_FAIL, 0); - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - return; - } + instance->SetData(DATA_DANCE_FAIL, 0); + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); + return; } - events.Repeat(5s); - return; } + events.Repeat(5s); + return; + } } + DoMeleeAttackIfReady(); } }; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 2fab24707..e6f781e60 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -145,15 +145,10 @@ public: struct boss_kelthuzadAI : public BossAI { explicit boss_kelthuzadAI(Creature* c) : BossAI(c, BOSS_KELTHUZAD), summons(me) - { - pInstance = me->GetInstanceScript(); - _justSpawned = true; - } + {} EventMap events; SummonList summons; - InstanceScript* pInstance; - bool _justSpawned; float NormalizeOrientation(float o) { @@ -224,35 +219,23 @@ public: summons.DespawnAll(); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE); me->SetReactState(REACT_AGGRESSIVE); - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR))) + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR)) { go->SetPhaseMask(1, true); go->SetGoState(GO_STATE_READY); } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE))) - { - if (!_justSpawned) // Don't open the door if we just spawned and are still doing the conversation - { - go->SetGoState(GO_STATE_ACTIVE); - } - } - _justSpawned = false; - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_1))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1)) go->SetGoState(GO_STATE_READY); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_2))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2)) go->SetGoState(GO_STATE_READY); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_3))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3)) go->SetGoState(GO_STATE_READY); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_4))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4)) go->SetGoState(GO_STATE_READY); - } } void EnterEvadeMode(EvadeReason why) override @@ -267,10 +250,7 @@ public: return; Talk(SAY_SLAY); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override @@ -282,13 +262,6 @@ public: guardian->AI()->Talk(EMOTE_GUARDIAN_FLEE); } Talk(SAY_DEATH); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void MoveInLineOfSight(Unit* who) override @@ -312,17 +285,11 @@ public: events.ScheduleEvent(EVENT_SUMMON_SOUL_WEAVER, 12s); events.ScheduleEvent(EVENT_PHASE_2, 228s); events.ScheduleEvent(EVENT_ENRAGE, 15min); - if (pInstance) + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR)) { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR))) - { - events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s); - go->SetGoState(GO_STATE_ACTIVE); - } - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE))) - { - go->SetGoState(GO_STATE_READY); + events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s); + go->SetGoState(GO_STATE_ACTIVE); } } @@ -354,14 +321,11 @@ public: switch (events.ExecuteEvent()) { case EVENT_FLOOR_CHANGE: - if (pInstance) + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_FLOOR)) { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR))) - { - events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s); - go->SetGoState(GO_STATE_READY); - go->SetPhaseMask(2, true); - } + events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15s); + go->SetGoState(GO_STATE_READY); + go->SetPhaseMask(2, true); } break; case EVENT_SPAWN_POOL: @@ -465,39 +429,32 @@ public: Talk(SAY_REQUEST_AID); events.DelayEvents(5500ms); events.ScheduleEvent(EVENT_P3_LICH_KING_SAY, 5s); - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_1))) - { + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_1)) go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_2))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_2)) go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_3))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_3)) go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_4))) - { + + if (GameObject* go = instance->GetGameObject(DATA_KELTHUZAD_PORTAL_4)) go->SetGoState(GO_STATE_ACTIVE); - } + break; } events.Repeat(1s); break; case EVENT_P3_LICH_KING_SAY: - if (pInstance) - { - if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_LICH_KING_BOSS))) - { - cr->AI()->Talk(SAY_ANSWER_REQUEST); - } - } + { + if (Creature* cr = instance->GetCreature(DATA_LICH_KING_BOSS)) + cr->AI()->Talk(SAY_ANSWER_REQUEST); + for (uint8 i = 0 ; i < RAID_MODE(2, 4); ++i) - { events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_ICECROWN, 10000 + (i * 5000)); - } + break; + } case EVENT_SUMMON_GUARDIAN_OF_ICECROWN: if (Creature* cr = me->SummonCreature(NPC_GUARDIAN_OF_ICECROWN, SpawnPool[RAND(0, 1, 3, 4)])) { @@ -573,10 +530,8 @@ public: void JustDied(Unit* /*killer*/) override { - if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION && me->GetInstanceScript()) - { + if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION) me->GetInstanceScript()->SetData(DATA_ABOMINATION_KILLED, 0); - } } void AttackStart(Unit* who) override @@ -618,10 +573,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && me->GetInstanceScript()) - { - me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustReachedHome() override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 52a0b4fe5..fe8d1589e 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -62,11 +62,9 @@ public: { explicit boss_loathebAI(Creature* c) : BossAI(c, BOSS_LOATHEB), summons(me) { - pInstance = me->GetInstanceScript(); me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); } - InstanceScript* pInstance; uint8 doomCounter; EventMap events; SummonList summons; @@ -77,14 +75,6 @@ public: events.Reset(); summons.DespawnAll(); doomCounter = 0; - if (pInstance) - { - pInstance->SetData(BOSS_LOATHEB, NOT_STARTED); - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_LOATHEB_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void JustSummoned(Creature* cr) override @@ -95,18 +85,13 @@ public: void SummonedCreatureDies(Creature* /*cr*/, Unit*) override { - if (pInstance) - { - pInstance->SetData(DATA_SPORE_KILLED, 0); - } + instance->SetData(DATA_SPORE_KILLED, 0); } void KilledUnit(Unit* who) override { - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustEngagedWith(Unit* who) override @@ -118,24 +103,12 @@ public: events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2min); events.ScheduleEvent(EVENT_SUMMON_SPORE, 15s); events.ScheduleEvent(EVENT_BERSERK, 12min); - if (pInstance) - { - pInstance->SetData(BOSS_LOATHEB, IN_PROGRESS); - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_LOATHEB_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void JustDied(Unit* killer) override { BossAI::JustDied(killer); summons.DespawnAll(); - if (pInstance) - { - pInstance->SetData(BOSS_LOATHEB, DONE); - } } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index eb4757c6f..76bf91ccb 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -106,11 +106,8 @@ public: struct boss_maexxnaAI : public BossAI { explicit boss_maexxnaAI(Creature* c) : BossAI(c, BOSS_MAEXXNA), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} - InstanceScript* pInstance; EventMap events; SummonList summons; @@ -131,10 +128,6 @@ public: BossAI::Reset(); events.Reset(); summons.DespawnAll(); - if (pInstance) - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE))) - if (pInstance->GetBossState(BOSS_FAERLINA) == DONE) - go->SetGoState(GO_STATE_ACTIVE); } void JustEngagedWith(Unit* who) override @@ -147,13 +140,6 @@ public: events.ScheduleEvent(EVENT_NECROTIC_POISON, 5s); events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s); events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30s); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void JustSummoned(Creature* cr) override @@ -171,10 +157,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp index c461384fd..79045abcf 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp @@ -89,11 +89,8 @@ public: struct boss_nothAI : public BossAI { explicit boss_nothAI(Creature* c) : BossAI(c, BOSS_NOTH), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} - InstanceScript* pInstance; uint8 timesInBalcony; EventMap events; SummonList summons; @@ -151,13 +148,6 @@ public: me->SetControlled(false, UNIT_STATE_ROOT); me->SetReactState(REACT_AGGRESSIVE); timesInBalcony = 0; - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void EnterEvadeMode(EvadeReason why) override @@ -171,13 +161,6 @@ public: BossAI::JustEngagedWith(who); Talk(SAY_AGGRO); StartGroundPhase(); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - } } void JustSummoned(Creature* summon) override @@ -195,13 +178,6 @@ public: } BossAI::JustDied(killer); Talk(SAY_DEATH); - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } } void KilledUnit(Unit* who) override @@ -210,10 +186,7 @@ public: return; Talk(SAY_SLAY); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index aa61c5fb1..3342c9a23 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -63,12 +63,9 @@ public: struct boss_patchwerkAI : public BossAI { explicit boss_patchwerkAI(Creature* c) : BossAI(c, BOSS_PATCHWERK) - { - pInstance = me->GetInstanceScript(); - } + {} EventMap events; - InstanceScript* pInstance; void Reset() override { @@ -82,13 +79,9 @@ public: return; if (!urand(0, 3)) - { Talk(SAY_SLAY); - } - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override @@ -105,10 +98,7 @@ public: events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 1500ms); events.ScheduleEvent(EVENT_BERSERK, 6min); events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s); - if (pInstance) - { - pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); - } + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index b3cac8840..14f334245 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -82,13 +82,10 @@ public: struct boss_razuviousAI : public BossAI { explicit boss_razuviousAI(Creature* c) : BossAI(c, BOSS_RAZUVIOUS), summons(me) - { - pInstance = me->GetInstanceScript(); - } + {} EventMap events; SummonList summons; - InstanceScript* pInstance; void SpawnHelpers() { @@ -210,13 +207,10 @@ public: void KilledUnit(Unit* who) override { if (roll_chance_i(30)) - { Talk(SAY_SLAY); - } - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override @@ -331,17 +325,16 @@ public: switch (action) { case ACTION_FACE_ME: + { scheduler.CancelGroup(GROUP_OOC_RP); me->SetSheath(SHEATH_STATE_UNARMED); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); - if (InstanceScript* instance = me->GetInstanceScript()) - { - if (Creature* creature = instance->GetCreature(DATA_RAZUVIOUS)) - { - me->SetFacingToObject(creature); - } - } + + if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS)) + me->SetFacingToObject(creature); + break; + } case ACTION_TALK: Talk(SAY_DEATH_KNIGHT_UNDERSTUDY); break; @@ -360,22 +353,18 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && me->GetInstanceScript()) - { - me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustEngagedWith(Unit* who) override { scheduler.CancelGroup(GROUP_OOC_RP); - if (InstanceScript* instance = me->GetInstanceScript()) + + if (Creature* creature = me->GetInstanceScript()->GetCreature(DATA_RAZUVIOUS_BOSS)) { - if (Creature* creature = instance->GetCreature(DATA_RAZUVIOUS)) - { - creature->SetInCombatWithZone(); - creature->AI()->AttackStart(who); - } + creature->SetInCombatWithZone(); + creature->AI()->AttackStart(who); } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index 8ecc62f56..98717dcbb 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -92,12 +92,9 @@ public: struct boss_sapphironAI : public BossAI { explicit boss_sapphironAI(Creature* c) : BossAI(c, BOSS_SAPPHIRON) - { - pInstance = me->GetInstanceScript(); - } + {} EventMap events; - InstanceScript* pInstance; uint8 iceboltCount{}; uint32 spawnTimer{}; GuidList blockList; @@ -221,10 +218,8 @@ public: void KilledUnit(Unit* who) override { - if (who->IsPlayer() && pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + if (who->IsPlayer()) + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override @@ -402,9 +397,9 @@ public: Map::PlayerList const& pList = me->GetMap()->GetPlayers(); for (auto const& itr : pList) { - if (itr.GetSource()->GetResistance(SPELL_SCHOOL_FROST) > 100 && pInstance) + if (itr.GetSource()->GetResistance(SPELL_SCHOOL_FROST) > 100) { - pInstance->SetData(DATA_HUNDRED_CLUB, 0); + instance->SetData(DATA_HUNDRED_CLUB, 0); return; } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index dd25921e9..cf953363d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -123,11 +123,8 @@ public: struct boss_thaddiusAI : public BossAI { explicit boss_thaddiusAI(Creature* c) : BossAI(c, BOSS_THADDIUS), summons(me), ballLightningEnabled(false) - { - pInstance = me->GetInstanceScript(); - } + {} - InstanceScript* pInstance; EventMap events; SummonList summons; uint32 summonTimer{}; @@ -184,28 +181,15 @@ public: } if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_LEFT, 100.0f)) - { go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (pInstance) - { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE))) - { - if (pInstance->GetBossState(BOSS_GLUTH) == DONE) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } - } - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK); + if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f)) + go->SetGoState(GO_STATE_ACTIVE); + + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK); } void KilledUnit(Unit* who) override @@ -214,27 +198,17 @@ public: return; Talk(SAY_SLAY); - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); - if (pInstance) - { - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK); - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE))) - { - go->SetGoState(GO_STATE_ACTIVE); - } - } + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK); } void JustSummoned(Creature* cr) override @@ -384,11 +358,9 @@ public: { explicit boss_thaddius_summonAI(Creature* c) : ScriptedAI(c) { - pInstance = me->GetInstanceScript(); overload = false; } - InstanceScript* pInstance; EventMap events; uint32 pullTimer{}; uint32 visualTimer{}; @@ -439,17 +411,11 @@ public: { events.ScheduleEvent(EVENT_MINION_MAGNETIC_PULL, 20s); } - if (pInstance) + + if (Creature* cr = me->GetInstanceScript()->GetCreature(DATA_THADDIUS_BOSS)) { - if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE))) - { - go->SetGoState(GO_STATE_READY); - } - if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_THADDIUS_BOSS))) - { - cr->AI()->AttackStart(pWho); - cr->AddThreat(pWho, 10.0f); - } + cr->AI()->AttackStart(pWho); + cr->AddThreat(pWho, 10.0f); } } @@ -479,13 +445,9 @@ public: { Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_DEATH : SAY_FEUG_DEATH); Talk(me->GetEntry() == NPC_STALAGG ? EMOTE_STAL_DEATH : EMOTE_FEUG_DEATH); - if (pInstance) - { - if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_THADDIUS_BOSS))) - { - cr->AI()->DoAction(ACTION_SUMMON_DIED); - } - } + + if (Creature* cr = me->GetInstanceScript()->GetCreature(DATA_THADDIUS_BOSS)) + cr->AI()->DoAction(ACTION_SUMMON_DIED); } void KilledUnit(Unit* who) override @@ -493,14 +455,10 @@ public: if (!who->IsPlayer()) return; - if (pInstance) - { - pInstance->SetData(DATA_IMMORTAL_FAIL, 0); - } if (!urand(0, 2)) - { Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_SLAY : SAY_FEUG_SLAY); - } + + me->GetInstanceScript()->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); } void UpdateAI(uint32 diff) override @@ -547,31 +505,30 @@ public: events.Repeat(3s); break; case EVENT_MINION_MAGNETIC_PULL: + { events.Repeat(20s); - if (pInstance) + if (Creature* feugen = me->GetInstanceScript()->GetCreature(DATA_FEUGEN_BOSS)) { - if (Creature* feugen = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_FEUGEN_BOSS))) - { - if (!feugen->IsAlive() || !feugen->GetVictim() || !me->GetVictim()) - return; + if (!feugen->IsAlive() || !feugen->GetVictim() || !me->GetVictim()) + return; - float threatFeugen = feugen->GetThreatMgr().GetThreat(feugen->GetVictim()); - float threatStalagg = me->GetThreatMgr().GetThreat(me->GetVictim()); - Unit* tankFeugen = feugen->GetVictim(); - Unit* tankStalagg = me->GetVictim(); + float threatFeugen = feugen->GetThreatMgr().GetThreat(feugen->GetVictim()); + float threatStalagg = me->GetThreatMgr().GetThreat(me->GetVictim()); + Unit* tankFeugen = feugen->GetVictim(); + Unit* tankStalagg = me->GetVictim(); - feugen->GetThreatMgr().ModifyThreatByPercent(tankFeugen, -100); - feugen->AddThreat(tankStalagg, threatFeugen); - feugen->CastSpell(tankStalagg, SPELL_MAGNETIC_PULL, true); - feugen->AI()->DoAction(ACTION_MAGNETIC_PULL); + feugen->GetThreatMgr().ModifyThreatByPercent(tankFeugen, -100); + feugen->AddThreat(tankStalagg, threatFeugen); + feugen->CastSpell(tankStalagg, SPELL_MAGNETIC_PULL, true); + feugen->AI()->DoAction(ACTION_MAGNETIC_PULL); - me->GetThreatMgr().ModifyThreatByPercent(tankStalagg, -100); - me->AddThreat(tankFeugen, threatStalagg); - me->CastSpell(tankFeugen, SPELL_MAGNETIC_PULL, true); - DoAction(ACTION_MAGNETIC_PULL); - } + me->GetThreatMgr().ModifyThreatByPercent(tankStalagg, -100); + me->AddThreat(tankFeugen, threatStalagg); + me->CastSpell(tankFeugen, SPELL_MAGNETIC_PULL, true); + DoAction(ACTION_MAGNETIC_PULL); } break; + } case EVENT_MINION_CHECK_DISTANCE: if (Creature* cr = ObjectAccessor::GetCreature(*me, myCoil)) { @@ -652,9 +609,9 @@ class spell_thaddius_pos_neg_charge : public SpellScript { SetHitDamage(0); } - else if (target->GetInstanceScript()) + else if (InstanceScript* instance = target->GetInstanceScript()) { - target->GetInstanceScript()->SetData(DATA_CHARGES_CROSSED, 0); + instance->SetData(DATA_CHARGES_CROSSED, 0); } } @@ -736,15 +693,13 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*areaTrigger*/) override { InstanceScript* instance = player->GetInstanceScript(); - if (!instance || instance->GetData(DATA_HAD_THADDIUS_GREET) || instance->GetBossState(BOSS_THADDIUS) == DONE) + if (!instance || instance->GetData(DATA_THADDIUS_INTRO) || instance->GetBossState(BOSS_THADDIUS) == DONE) return true; - if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THADDIUS_BOSS))) - { + if (Creature* thaddius = instance->GetCreature(DATA_THADDIUS_BOSS)) thaddius->AI()->Talk(SAY_GREET); - } - instance->SetData(DATA_HAD_THADDIUS_GREET, 1); + instance->SetData(DATA_THADDIUS_INTRO, 1); return true; } }; diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index a72a33e29..f116047d8 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -17,1250 +17,748 @@ #include "AreaTriggerScript.h" #include "CellImpl.h" +#include "CreatureAIImpl.h" #include "CreatureScript.h" -#include "GridNotifiers.h" -#include "GridNotifiersImpl.h" #include "InstanceMapScript.h" +#include "InstanceScript.h" #include "PassiveAI.h" -#include "ScriptedCreature.h" +#include "Player.h" #include "naxxramas.h" -static constexpr uint8 HorsemanCount = 4; +struct LivingPoisonData +{ + Position Start {}; + Position End {}; + uint32 DespawnTime {}; +}; -const float HeiganPos[2] = {2796, -3707}; -const float HeiganEruptionSlope[3] = +static const LivingPoisonData LivingPoisonDataList[3] +{ + { Position { 3128.59, -3118.81, 293.346, 4.76754 }, Position { 3130.322, -3156.51, 293.324 }, 15200 }, + { Position { 3154.25, -3125.7, 293.43, 4.47694 }, Position { 3144.779, -3158.416, 293.324 }, 14800 }, + { Position { 3175.42, -3134.86, 293.34, 4.284 }, Position { 3158.778, -3164.201, 293.312 }, 14800 } +}; + +static const float HeiganPos[2] +{ + 2796, -3707 +}; + +static const float HeiganEruptionSlope[3] { (-3685 - HeiganPos[1]) / (2724 - HeiganPos[0]), (-3647 - HeiganPos[1]) / (2749 - HeiganPos[0]), (-3637 - HeiganPos[1]) / (2771 - HeiganPos[0]), }; -inline uint8 GetEruptionSection(float x, float y) +static constexpr std::array HorsemanDataGroup { - y -= HeiganPos[1]; - if (y < 1.0f) - return 0; - - x -= HeiganPos[0]; - if (x > -1.0f) - return 3; - - float slope = y / x; - for (uint32 i = 0; i < 3; ++i) - { - if (slope > HeiganEruptionSlope[i]) - return i; - } - return 3; -} - -DoorData const doorData[] = -{ - { GO_ANUB_GATE, BOSS_ANUB, DOOR_TYPE_ROOM }, - { 0, 0, DOOR_TYPE_ROOM }, + DATA_BARON_RIVENDARE_BOSS, + DATA_SIR_ZELIEK_BOSS, + DATA_LADY_BLAUMEUX_BOSS, + DATA_THANE_KORTHAZZ_BOSS }; -ObjectData const creatureData[] = +static WorldLocation const SapphironTeleportPos { - { NPC_RAZUVIOUS, DATA_RAZUVIOUS }, - { 0, 0 } + NaxxramasMapId, 3498.300049f, -5349.490234f, 144.968002f, 1.3698910f }; -ObjectData const gameObjectData[] = +static DoorData const doorData[] { - { 0, 0 } + { GO_PATCHWERK_GATE, BOSS_PATCHWERK, DOOR_TYPE_PASSAGE }, + { GO_PATCHWERK_GATE, BOSS_GROBBULUS, DOOR_TYPE_ROOM }, + { GO_GLUTH_GATE, BOSS_GLUTH, DOOR_TYPE_PASSAGE }, + { GO_THADDIUS_GATE, BOSS_GLUTH, DOOR_TYPE_PASSAGE }, + { GO_NOTH_ENTRY_GATE, BOSS_NOTH, DOOR_TYPE_ROOM }, + { GO_NOTH_EXIT_GATE, BOSS_NOTH, DOOR_TYPE_PASSAGE }, + { GO_HEIGAN_ENTRY_GATE, BOSS_NOTH, DOOR_TYPE_PASSAGE }, + { GO_HEIGAN_ENTRY_GATE, BOSS_HEIGAN, DOOR_TYPE_ROOM }, + { GO_HEIGAN_EXIT_GATE, BOSS_HEIGAN, DOOR_TYPE_PASSAGE }, + { GO_LOATHEB_GATE, BOSS_HEIGAN, DOOR_TYPE_PASSAGE }, + { GO_LOATHEB_GATE, BOSS_LOATHEB, DOOR_TYPE_ROOM }, + { GO_PLAGUE_EYE_PORTAL, BOSS_LOATHEB, DOOR_TYPE_PASSAGE }, + { GO_PLAG_EYE_RAMP_BOSS, BOSS_LOATHEB, DOOR_TYPE_PASSAGE }, + { GO_ANUB_GATE, BOSS_ANUB, DOOR_TYPE_ROOM }, + { GO_ANUB_NEXT_GATE, BOSS_ANUB, DOOR_TYPE_PASSAGE }, + { GO_FAERLINA_WEB, BOSS_FAERLINA, DOOR_TYPE_ROOM }, + { GO_FAERLINA_GATE, BOSS_FAERLINA, DOOR_TYPE_PASSAGE }, + { GO_MAEXXNA_GATE, BOSS_FAERLINA, DOOR_TYPE_PASSAGE }, + { GO_MAEXXNA_GATE, BOSS_MAEXXNA, DOOR_TYPE_ROOM }, + { GO_SPIDER_EYE_PORTAL, BOSS_MAEXXNA, DOOR_TYPE_PASSAGE }, + { GO_ARAC_EYE_RAMP_BOSS, BOSS_MAEXXNA, DOOR_TYPE_PASSAGE }, + { GO_THADDIUS_GATE, BOSS_THADDIUS, DOOR_TYPE_ROOM }, + { GO_ABOM_EYE_PORTAL, BOSS_THADDIUS, DOOR_TYPE_PASSAGE }, + { GO_CONS_EYE_RAMP_BOSS, BOSS_THADDIUS, DOOR_TYPE_PASSAGE }, + { GO_GOTHIK_ENTER_GATE, BOSS_GOTHIK, DOOR_TYPE_ROOM }, + { GO_GOTHIK_INNER_GATE, BOSS_GOTHIK, DOOR_TYPE_ROOM }, + { GO_GOTHIK_EXIT_GATE, BOSS_GOTHIK, DOOR_TYPE_PASSAGE }, + { GO_HORSEMEN_GATE, BOSS_GOTHIK, DOOR_TYPE_PASSAGE }, + { GO_HORSEMEN_GATE, BOSS_HORSEMAN, DOOR_TYPE_ROOM }, + { GO_DEATHKNIGHT_EYE_PORTAL, BOSS_HORSEMAN, DOOR_TYPE_PASSAGE }, + { GO_MILI_EYE_RAMP_BOSS, BOSS_HORSEMAN, DOOR_TYPE_PASSAGE }, + { GO_KELTHUZAD_GATE, BOSS_KELTHUZAD, DOOR_TYPE_ROOM }, + { 0, 0, DOOR_TYPE_ROOM } }; -class instance_naxxramas : public InstanceMapScript +static ObjectData const creatureData[] +{ + { NPC_PATCHWERK, DATA_PATCHWERK_BOSS }, + { NPC_STALAGG, DATA_STALAGG_BOSS }, + { NPC_FEUGEN, DATA_FEUGEN_BOSS }, + { NPC_THADDIUS, DATA_THADDIUS_BOSS }, + { NPC_RAZUVIOUS, DATA_RAZUVIOUS_BOSS }, + { NPC_GOTHIK, DATA_GOTHIK_BOSS }, + { NPC_BARON_RIVENDARE, DATA_BARON_RIVENDARE_BOSS }, + { NPC_SIR_ZELIEK, DATA_SIR_ZELIEK_BOSS }, + { NPC_LADY_BLAUMEUX, DATA_LADY_BLAUMEUX_BOSS }, + { NPC_THANE_KORTHAZZ, DATA_THANE_KORTHAZZ_BOSS }, + { NPC_SAPPHIRON, DATA_SAPPHIRON_BOSS }, + { NPC_KELTHUZAD, DATA_KELTHUZAD_BOSS }, + { NPC_LICH_KING, DATA_LICH_KING_BOSS }, + { 0, 0 } +}; + +static ObjectData const gameObjectData[] +{ + { GO_GOTHIK_INNER_GATE, DATA_GOTHIK_INNER_GATE }, + { GO_LOATHEB_PORTAL, DATA_LOATHEB_PORTAL }, + { GO_MAEXXNA_PORTAL, DATA_MAEXXNA_PORTAL }, + { GO_THADDIUS_PORTAL, DATA_THADDIUS_PORTAL }, + { GO_HORSEMAN_PORTAL, DATA_HORSEMAN_PORTAL }, + { GO_SAPPHIRON_GATE, DATA_SAPPHIRON_GATE }, + { GO_KELTHUZAD_FLOOR, DATA_KELTHUZAD_FLOOR }, + { GO_KELTHUZAD_GATE, DATA_KELTHUZAD_GATE }, + { GO_KELTHUZAD_PORTAL_1, DATA_KELTHUZAD_PORTAL_1 }, + { GO_KELTHUZAD_PORTAL_2, DATA_KELTHUZAD_PORTAL_2 }, + { GO_KELTHUZAD_PORTAL_3, DATA_KELTHUZAD_PORTAL_3 }, + { GO_KELTHUZAD_PORTAL_4, DATA_KELTHUZAD_PORTAL_4 }, + { 0, 0 } +}; + +class instance_naxxramas : public InstanceScript { public: - instance_naxxramas() : InstanceMapScript("instance_naxxramas", 533) { } - - InstanceScript* GetInstanceScript(InstanceMap* pMap) const override + instance_naxxramas(Map* map) : InstanceScript(map) { - return new instance_naxxramas_InstanceMapScript(pMap); - } + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTERS); + SetPersistentDataCount(PERSISTENT_DATA_COUNT); + LoadDoorData(doorData); + LoadObjectData(creatureData, gameObjectData); - struct instance_naxxramas_InstanceMapScript : public InstanceScript - { - explicit instance_naxxramas_InstanceMapScript(Map* pMap) : InstanceScript(pMap) - { - SetHeaders(DataHeader); - SetBossNumber(MAX_ENCOUNTERS); - LoadDoorData(doorData); - LoadObjectData(creatureData, gameObjectData); - for (auto& i : HeiganEruption) - i.clear(); - - // NPCs - PatchwerkRoomTrash.clear(); - - // Controls - _speakTimer = 0; - _horsemanTimer = 0; - _screamTimer = 2 * MINUTE * IN_MILLISECONDS; - _hadThaddiusGreet = false; - _currentWingTaunt = SAY_FIRST_WING_TAUNT; - _currentHorsemenLine = 0; - - // Achievements - abominationsKilled = 0; - faerlinaAchievement = true; - thaddiusAchievement = true; - loathebAchievement = true; - sapphironAchievement = true; - heiganAchievement = true; - immortalAchievement = 1; - } - - std::set HeiganEruption[4]; - - // GOs - ObjectGuid _patchwerkGateGUID; - ObjectGuid _gluthGateGUID; - ObjectGuid _nothEntryGateGUID; - ObjectGuid _nothExitGateGUID; - ObjectGuid _heiganGateGUID; - ObjectGuid _heiganGateExitGUID; - ObjectGuid _loathebGateGUID; - ObjectGuid _anubNextGateGUID; - ObjectGuid _faerlinaWebGUID; - ObjectGuid _faerlinaGateGUID; - ObjectGuid _maexxnaGateGUID; - ObjectGuid _thaddiusGateGUID; - ObjectGuid _gothikEnterGateGUID; - ObjectGuid _gothikInnerGateGUID; - ObjectGuid _gothikExitGateGUID{}; - ObjectGuid _horsemanGateGUID; - ObjectGuid _kelthuzadFloorGUID; - ObjectGuid _kelthuzadGateGUID; - ObjectGuid _kelthuzadPortal1GUID; - ObjectGuid _kelthuzadPortal2GUID; - ObjectGuid _kelthuzadPortal3GUID; - ObjectGuid _kelthuzadPortal4GUID; - ObjectGuid _sapphironGateGUID; - ObjectGuid _horsemanPortalGUID; - ObjectGuid _loathebPortalGUID; - ObjectGuid _maexxnaPortalGUID; - ObjectGuid _thaddiusPortalGUID; - ObjectGuid _deathknightEyePortalGUID; - ObjectGuid _plagueEyePortalGUID; - ObjectGuid _spiderEyePortalGUID; - ObjectGuid _abomEyePortalGUID; - ObjectGuid _deathknightGlowEyePortalGUID; - ObjectGuid _plagueGlowEyePortalGUID; - ObjectGuid _spiderGlowEyePortalGUID; - ObjectGuid _abomGlowEyePortalGUID; + // GameObjects + for (auto& i : _heiganEruption) + i.clear(); // NPCs - GuidList PatchwerkRoomTrash; - ObjectGuid _patchwerkGUID; - ObjectGuid _thaddiusGUID; - ObjectGuid _gothikGUID; - ObjectGuid _stalaggGUID; - ObjectGuid _feugenGUID; - ObjectGuid _zeliekGUID; - ObjectGuid _rivendareGUID; - ObjectGuid _blaumeuxGUID; - ObjectGuid _korthazzGUID; - ObjectGuid _sapphironGUID; - ObjectGuid _kelthuzadGUID; - ObjectGuid _lichkingGUID; + _patchwerkRoomTrash.clear(); // Controls - uint32 _speakTimer; - uint32 _horsemanTimer; - uint32 _screamTimer; - bool _hadThaddiusGreet; - EventMap events; - uint8 _currentWingTaunt; - uint8 _currentHorsemenLine; - uint8 _horsemanLoaded; + _events.Reset(); + _currentWingTaunt = SAY_FIRST_WING_TAUNT; + _horsemanLoaded = 0; // Achievements - uint8 abominationsKilled; - bool faerlinaAchievement; - bool thaddiusAchievement; - bool loathebAchievement; - bool sapphironAchievement; - bool heiganAchievement; - uint32 immortalAchievement; + _abominationsKilled = 0; + _faerlinaAchievement = true; + _thaddiusAchievement = true; + _loathebAchievement = true; + _heiganAchievement = true; + _sapphironAchievement = true; + _horsemanAchievement = true; + } - void HeiganEruptSections(uint32 section) - { - for (uint8 i = 0; i < 4; ++i) - { - if (i == section) - continue; + inline void CreatureTalk(uint32 dataCreature, uint8 dialog) + { + if (Creature* creature = GetCreature(dataCreature)) + creature->AI()->Talk(dialog); + } - for (auto itr : HeiganEruption[i]) - { - itr->SendCustomAnim(itr->GetGoAnimProgress()); - itr->CastSpell(nullptr, SPELL_ERUPTION); - } - } - } + inline void SetGoState(uint32 dataGameObject, GOState state) + { + if (GameObject* go = GetGameObject(dataGameObject)) + go->SetGoState(state); + } - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - { - if (GetBossState(i) == IN_PROGRESS) - return true; - } - return false; - } + inline void ActivateWingPortal(GameObject* go, EncounterState state) + { + if (!go || state != DONE) + return; - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_PATCHWERK: - _patchwerkGUID = creature->GetGUID(); - return; - case NPC_PATCHWORK_GOLEM: - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_BILE_RETCHER: - if (creature->GetPositionY() > -3258.0f) // we want only those inside the room, not before - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_SLUDGE_BELCHER: - if (creature->GetPositionY() > -3258.0f) // we want only those inside the room, not before - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_MAD_SCIENTIST: - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_LIVING_MONSTROSITY: - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_SURGICAL_ASSIST: - PatchwerkRoomTrash.push_back(creature->GetGUID()); - return; - case NPC_THADDIUS: - _thaddiusGUID = creature->GetGUID(); - return; - case NPC_STALAGG: - _stalaggGUID = creature->GetGUID(); - return; - case NPC_FEUGEN: - _feugenGUID = creature->GetGUID(); - return; - case NPC_GOTHIK: - _gothikGUID = creature->GetGUID(); - return; - case NPC_LADY_BLAUMEUX: - _blaumeuxGUID = creature->GetGUID(); - ++_horsemanLoaded; - return; - case NPC_SIR_ZELIEK: - _zeliekGUID = creature->GetGUID(); - ++_horsemanLoaded; - return; - case NPC_BARON_RIVENDARE: - _rivendareGUID = creature->GetGUID(); - ++_horsemanLoaded; - return; - case NPC_THANE_KORTHAZZ: - _korthazzGUID = creature->GetGUID(); - ++_horsemanLoaded; - return; - case NPC_SAPPHIRON: - _sapphironGUID = creature->GetGUID(); - return; - case NPC_KELTHUZAD: - _kelthuzadGUID = creature->GetGUID(); - return; - case NPC_LICH_KING: - _lichkingGUID = creature->GetGUID(); - return; - } + go->SetGoState(GO_STATE_ACTIVE); + go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); + } - if (_horsemanLoaded == HorsemanCount) - SetBossState(BOSS_HORSEMAN, GetBossState(BOSS_HORSEMAN)); - - InstanceScript::OnCreatureCreate(creature); - } - - void OnGameObjectCreate(GameObject* pGo) override - { - if (pGo->GetGOInfo()->displayId == 6785 || pGo->GetGOInfo()->displayId == 1287) - { - HeiganEruption[GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY())].insert(pGo); - return; - } - - switch (pGo->GetEntry()) - { - case GO_PATCHWERK_GATE: - _patchwerkGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_PATCHWERK) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_GLUTH_GATE: - _gluthGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_GLUTH) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_NOTH_ENTRY_GATE: - _nothEntryGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_NOTH) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_NOTH_EXIT_GATE: - _nothExitGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_NOTH) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_HEIGAN_ENTRY_GATE: - _heiganGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_HEIGAN) == DONE || GetBossState(BOSS_NOTH) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_HEIGAN_EXIT_GATE: - _heiganGateExitGUID = pGo->GetGUID(); - if (GetBossState(BOSS_HEIGAN) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_LOATHEB_GATE: - _loathebGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_LOATHEB) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_ANUB_NEXT_GATE: - _anubNextGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_ANUB) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_FAERLINA_GATE: - _faerlinaGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_FAERLINA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_FAERLINA_WEB: - _faerlinaWebGUID = pGo->GetGUID(); - if (GetBossState(BOSS_FAERLINA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_MAEXXNA_GATE: - _maexxnaGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_FAERLINA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_THADDIUS_GATE: - _thaddiusGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_GLUTH) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_GOTHIK_ENTER_GATE: - _gothikEnterGateGUID = pGo->GetGUID(); - break; - case GO_GOTHIK_INNER_GATE: - _gothikInnerGateGUID = pGo->GetGUID(); - break; - case GO_GOTHIK_EXIT_GATE: - _gothikExitGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_GOTHIK) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_HORSEMEN_GATE: - _horsemanGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_GOTHIK) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_KELTHUZAD_FLOOR: - _kelthuzadFloorGUID = pGo->GetGUID(); - break; - case GO_KELTHUZAD_GATE: - _kelthuzadGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_SAPPHIRON) == DONE && _speakTimer == 0) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_KELTHUZAD_PORTAL_1: - _kelthuzadPortal1GUID = pGo->GetGUID(); - break; - case GO_KELTHUZAD_PORTAL_2: - _kelthuzadPortal2GUID = pGo->GetGUID(); - break; - case GO_KELTHUZAD_PORTAL_3: - _kelthuzadPortal3GUID = pGo->GetGUID(); - break; - case GO_KELTHUZAD_PORTAL_4: - _kelthuzadPortal4GUID = pGo->GetGUID(); - break; - case GO_SAPPHIRON_GATE: - _sapphironGateGUID = pGo->GetGUID(); - if (GetBossState(BOSS_SAPPHIRON) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_LOATHEB_PORTAL: - _loathebPortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_LOATHEB) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - pGo->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - break; - case GO_THADDIUS_PORTAL: - _thaddiusPortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_THADDIUS) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - pGo->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - break; - case GO_MAEXXNA_PORTAL: - _maexxnaPortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_MAEXXNA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - pGo->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - break; - case GO_HORSEMAN_PORTAL: - _horsemanPortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_HORSEMAN) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - pGo->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - break; - - // Glow portals at center-side - case GO_DEATHKNIGHT_EYE_PORTAL: - _deathknightEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_HORSEMAN) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_PLAGUE_EYE_PORTAL: - _plagueEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_LOATHEB) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_SPIDER_EYE_PORTAL: - _spiderEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_MAEXXNA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_ABOM_EYE_PORTAL: - _abomEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_THADDIUS) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - - // Glow portals at boss-side - case GO_MILI_EYE_RAMP_BOSS: - _deathknightGlowEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_HORSEMAN) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_PLAG_EYE_RAMP_BOSS: - _plagueGlowEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_LOATHEB) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_ARAC_EYE_RAMP_BOSS: - _spiderGlowEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_MAEXXNA) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - case GO_CONS_EYE_RAMP_BOSS: - _abomGlowEyePortalGUID = pGo->GetGUID(); - if (GetBossState(BOSS_THADDIUS) == DONE) - { - pGo->SetGoState(GO_STATE_ACTIVE); - } - break; - } - - InstanceScript::OnGameObjectCreate(pGo); - } - - void OnGameObjectRemove(GameObject* pGo) override - { - if (pGo->GetGOInfo()->displayId == 6785 || pGo->GetGOInfo()->displayId == 1287) - { - uint32 section = GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY()); - HeiganEruption[section].erase(pGo); - return; - } - if (pGo->GetEntry() == GO_SAPPHIRON_BIRTH) - { - if (Creature* cr = instance->GetCreature(_sapphironGUID)) - { - cr->AI()->DoAction(ACTION_SAPPHIRON_BIRTH); - } - } - } - - bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override - { - switch (criteria_id) - { - case 7600: // And They Would All Go Down Together (10 player) - case 7601: // And They Would All Go Down Together (25 player) - return (_horsemanTimer < 15 * IN_MILLISECONDS); - case 7614: // Just Can't Get Enough (10 player) - case 7615: // Just Can't Get Enough (25 player) - return abominationsKilled >= 18; - case 7265: // Momma Said Knock You Out (10 player) - case 7549: // Momma Said Knock You Out (25 player) - return faerlinaAchievement; - case 7604: // Shocking! (10 player) - case 7605: // Shocking! (25 player) - return thaddiusAchievement; - case 7612: // Spore Loser (10 player) - case 7613: // Spore Loser (25 player) - return loathebAchievement; - case 7264: // The Safety Dance (10 player) - case 7548: // The Safety Dance (25 player) - return heiganAchievement; - case 7608: // Subtraction (10 player) - // The Dedicated few (10 player) - case 6802: - case 7146: - case 7147: - case 7148: - case 7149: - case 7150: - case 7151: - case 7152: - case 7153: - case 7154: - case 7155: - case 7156: - case 7157: - case 7158: - return (instance->GetPlayersCountExceptGMs() < 9); - case 7609: // Subtraction (25 player) - // The Dedicated few (25 player) - case 7159: - case 7160: - case 7161: - case 7162: - case 7163: - case 7164: - case 7165: - case 7166: - case 7167: - case 7168: - case 7169: - case 7170: - case 7171: - case 7172: - return (instance->GetPlayersCountExceptGMs() < 21); - case 7567: // The Hundred Club (10 player) - case 7568: // The Hundred Club (25 player) - return sapphironAchievement; - // The Undying - case 7617: - case 13237: - case 13238: - case 13239: - case 13240: - // The Immortal - case 7616: - case 13233: - case 13234: - case 13235: - case 13236: - { - uint8 count = 0; - for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - { - if (GetBossState(i) == NOT_STARTED) - ++count; - } - return !count && immortalAchievement; - } - - default: - return false; - } - } - - void SetData(uint32 id, uint32 data) override - { - switch (id) - { - case DATA_ABOMINATION_KILLED: - abominationsKilled++; - return; - case DATA_FRENZY_REMOVED: - faerlinaAchievement = false; - return; - case DATA_CHARGES_CROSSED: - thaddiusAchievement = false; - return; - case DATA_SPORE_KILLED: - loathebAchievement = false; - return; - case DATA_HUNDRED_CLUB: - sapphironAchievement = false; - return; - case DATA_DANCE_FAIL: - heiganAchievement = false; - return; - case DATA_IMMORTAL_FAIL: - immortalAchievement = 0; - SaveToDB(); - return; - case DATA_HEIGAN_ERUPTION: - HeiganEruptSections(data); - return; - case DATA_HAD_THADDIUS_GREET: - _hadThaddiusGreet = (data == 1); - default: - return; - } - } - - uint32 GetData(uint32 id) const override - { - if (id == DATA_HAD_THADDIUS_GREET && _hadThaddiusGreet) - return 1; + inline void ActivateWingPortal(uint32 wingPortal) + { + ActivateWingPortal(GetGameObject(wingPortal), DONE); + _events.RescheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s); + } + static inline uint8 GetEruptionSection(float x, float y) + { + y -= HeiganPos[1]; + if (y < 1.0f) return 0; + + x -= HeiganPos[0]; + if (x > -1.0f) + return 3; + + float slope = y / x; + for (uint32 i = 0; i < 3; ++i) + if (slope > HeiganEruptionSlope[i]) + return i; + + return 3; + } + + inline void HeiganEruptSections(uint32 section) + { + for (uint8 i = 0; i < HeiganEruptSectionCount; ++i) + { + if (i == section) + continue; + + for (GameObject* go : _heiganEruption[i]) + { + go->SendCustomAnim(go->GetGoAnimProgress()); + go->CastSpell(nullptr, SPELL_ERUPTION); + } + } + } + + void OnPlayerEnter(Player* player) override + { + InstanceScript::OnPlayerEnter(player); + + _events.ScheduleEvent(EVENT_THADDIUS_SCREAMS, 2min, 2min + 30s); + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_LIVING_MONSTROSITY: + case NPC_MAD_SCIENTIST: + case NPC_PATCHWORK_GOLEM: + case NPC_SURGICAL_ASSIST: + _patchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_BILE_RETCHER: + case NPC_SLUDGE_BELCHER: + if (creature->GetPositionY() > -3258.0f) // we want only those inside the room, not before + _patchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_BARON_RIVENDARE: + case NPC_SIR_ZELIEK: + case NPC_LADY_BLAUMEUX: + case NPC_THANE_KORTHAZZ: + if (++_horsemanLoaded == HorsemanCount) + SetBossState(BOSS_HORSEMAN, GetBossState(BOSS_HORSEMAN)); + break; + default: + break; } - bool SetBossState(uint32 bossId, EncounterState state) override + InstanceScript::OnCreatureCreate(creature); + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetGOInfo()->displayId) { - // pull all the trash if not killed - if (bossId == BOSS_PATCHWERK && state == IN_PROGRESS) - { - if (Creature* patch = instance->GetCreature(_patchwerkGUID)) - { - for (auto& itr : PatchwerkRoomTrash) - { - Creature* trash = ObjectAccessor::GetCreature(*patch, itr); - if (trash && trash->IsAlive() && !trash->IsInCombat()) - { - trash->AI()->AttackStart(patch->GetVictim()); - } - } - } - } + case GO_DISPLAY_ID_HEIGAN_ERUPTION1: + case GO_DISPLAY_ID_HEIGAN_ERUPTION2: + _heiganEruption[GetEruptionSection(go->GetPositionX(), go->GetPositionY())].insert(go); + break; + default: + break; + } - // Horseman handling - if (bossId == BOSS_HORSEMAN && _horsemanLoaded == HorsemanCount) - { - uint8 horsemanKilled {}; - if (Creature* cr = instance->GetCreature(_blaumeuxGUID)) - horsemanKilled += !cr->IsAlive(); + switch (go->GetEntry()) + { + case GO_SAPPHIRON_GATE: + if (GetBossState(BOSS_SAPPHIRON) == DONE) + go->SetGoState(GO_STATE_ACTIVE); + break; + case GO_LOATHEB_PORTAL: + ActivateWingPortal(go, GetBossState(BOSS_LOATHEB)); + break; + case GO_THADDIUS_PORTAL: + ActivateWingPortal(go, GetBossState(BOSS_THADDIUS)); + break; + case GO_MAEXXNA_PORTAL: + ActivateWingPortal(go, GetBossState(BOSS_MAEXXNA)); + break; + case GO_HORSEMAN_PORTAL: + ActivateWingPortal(go, GetBossState(BOSS_HORSEMAN)); + break; + default: + break; + } - if (Creature* cr = instance->GetCreature(_rivendareGUID)) - horsemanKilled += !cr->IsAlive(); + InstanceScript::OnGameObjectCreate(go); + } - if (Creature* cr = instance->GetCreature(_zeliekGUID)) - horsemanKilled += !cr->IsAlive(); + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetGOInfo()->displayId) + { + case GO_DISPLAY_ID_HEIGAN_ERUPTION1: + case GO_DISPLAY_ID_HEIGAN_ERUPTION2: + _heiganEruption[GetEruptionSection(go->GetPositionX(), go->GetPositionY())].erase(go); + break; + default: + break; + } - if (Creature* cr = instance->GetCreature(_korthazzGUID)) - horsemanKilled += !cr->IsAlive(); + switch (go->GetEntry()) + { + case GO_SAPPHIRON_BIRTH: + if (Creature* cr = GetCreature(DATA_SAPPHIRON_BOSS)) + cr->AI()->DoAction(ACTION_SAPPHIRON_BIRTH); + break; + default: + break; + } - if (state == DONE) - { - _horsemanTimer++; - if (horsemanKilled < HorsemanCount) - { + InstanceScript::OnGameObjectRemove(go); + } + + bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override + { + switch (criteria_id) + { + case ACHIEV_CRITERIA_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER_10_PLAYER: + case ACHIEV_CRITERIA_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER_25_PLAYER: + return _horsemanAchievement; + case ACHIEV_CRITERIA_JUST_CANT_GET_ENOUGH_10_PLAYER: + case ACHIEV_CRITERIA_JUST_CANT_GET_ENOUGH_25_PLAYER: + return _abominationsKilled >= AbominationKillCountReq; + case ACHIEV_CRITERIA_MOMMA_SAID_KNOCK_YOU_OUT_10_PLAYER: + case ACHIEV_CRITERIA_MOMMA_SAID_KNOCK_YOU_OUT_25_PLAYER: + return _faerlinaAchievement; + case ACHIEV_CRITERIA_SHOKING_10_PLAYER: + case ACHIEV_CRITERIA_SHOKING_25_PLAYER: + return _thaddiusAchievement; + case ACHIEV_CRITERIA_SPORE_LOSER_10_PLAYER: + case ACHIEV_CRITERIA_SPORE_LOSER_25_PLAYER: + return _loathebAchievement; + case ACHIEV_CRITERIA_THE_SAFETY_DANCE_10_PLAYER: + case ACHIEV_CRITERIA_THE_SAFETY_DANCE_25_PLAYER: + return _heiganAchievement; + case ACHIEV_CRITERIA_SUBTRACTION_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_KELTHUZAD_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GOTHIK_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_ANUB_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GROBBULUS_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_HEIGAN_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_FAERLINA_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_MAEXXNA_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_SAPPHIRON_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_LOATHEB_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GLUTH_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_THADDIUS_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_PATCHWERK_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_RAZUVIOUS_10_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_NOTH_10_PLAYER: + return instance->GetPlayersCountExceptGMs() < TheDedicatedFew10PlayerReq; + case ACHIEV_CRITERIA_SUBTRACTION_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_ANUB_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_FAERLINA_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_MAEXXNA_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_PATCHWERK_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GROBBULUS_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GLUTH_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_THADDIUS_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_NOTH_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_HEIGAN_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_LOATHEB_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_RAZUVIOUS_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_GOTHIK_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_SAPPHIRON_25_PLAYER: + case ACHIEV_CRITERIA_THE_DEDICATED_FEW_KELTHUZAD_25_PLAYER: + return instance->GetPlayersCountExceptGMs() < TheDedicatedFew25PlayerReq; + case ACHIEV_CRITERIA_THE_HUNDRED_CLUB_10_PLAYER: + case ACHIEV_CRITERIA_THE_HUNDRED_CLUB_25_PLAYER: + return _sapphironAchievement; + case ACHIEV_CRITERIA_THE_UNDYING_KELTHUZAD: + case ACHIEV_CRITERIA_THE_UNDYING_THE_FOUR_HORSEMEN: + case ACHIEV_CRITERIA_THE_UNDYING_MAEXXNA: + case ACHIEV_CRITERIA_THE_UNDYING_LOATHEB: + case ACHIEV_CRITERIA_THE_UNDYING_THADDIUS: + case ACHIEV_CRITERIA_THE_IMMORTAL_KELTHUZAD: + case ACHIEV_CRITERIA_THE_IMMORTAL_THE_FOUR_HORSEMEN: + case ACHIEV_CRITERIA_THE_IMMORTAL_MAEXXNA: + case ACHIEV_CRITERIA_THE_IMMORTAL_LOATHEB: + case ACHIEV_CRITERIA_THE_IMMORTAL_THADDIUS: + for (int i = 0; i < MAX_ENCOUNTERS; ++i) + if (GetBossState(i) != DONE) return false; - } - // All horsemans are killed - if (Creature* cr = instance->GetCreature(_blaumeuxGUID)) - { - cr->CastSpell(cr, 59450, true); // credit - } - } - // respawn - else if (state == NOT_STARTED && horsemanKilled > 0) - { - Creature* cr; - if ((cr = instance->GetCreature(_blaumeuxGUID))) - { - if (!cr->IsAlive()) - { - cr->SetPosition(cr->GetHomePosition()); - cr->Respawn(); - } - } - if ((cr = instance->GetCreature(_rivendareGUID))) - { - if (!cr->IsAlive()) - { - cr->SetPosition(cr->GetHomePosition()); - cr->Respawn(); - } - } - if ((cr = instance->GetCreature(_zeliekGUID))) - { - if (!cr->IsAlive()) - { - cr->SetPosition(cr->GetHomePosition()); - cr->Respawn(); - } - } - if ((cr = instance->GetCreature(_korthazzGUID))) - { - if (!cr->IsAlive()) - { - cr->SetPosition(cr->GetHomePosition()); - cr->Respawn(); - } - } - } - else if (state == IN_PROGRESS) - { - Creature* cr; - if ((cr = instance->GetCreature(_blaumeuxGUID))) - { - cr->SetInCombatWithZone(); - } - if ((cr = instance->GetCreature(_rivendareGUID))) - { - cr->SetInCombatWithZone(); - } - if ((cr = instance->GetCreature(_zeliekGUID))) - { - cr->SetInCombatWithZone(); - } - if ((cr = instance->GetCreature(_korthazzGUID))) - { - cr->SetInCombatWithZone(); - } - } - - if (state == NOT_STARTED) - { - _horsemanTimer = 0; - } - } - - if (!InstanceScript::SetBossState(bossId, state)) + return !GetPersistentData(PERSISTENT_DATA_IMMORTAL_FAIL); + default: return false; + } + } - // Bosses data - switch (bossId) + void SetData(uint32 id, uint32 data) override + { + switch (id) + { + case DATA_ABOMINATION_KILLED: + ++_abominationsKilled; + return; + case DATA_FRENZY_REMOVED: + _faerlinaAchievement = false; + return; + case DATA_CHARGES_CROSSED: + _thaddiusAchievement = false; + return; + case DATA_SPORE_KILLED: + _loathebAchievement = false; + return; + case DATA_HUNDRED_CLUB: + _sapphironAchievement = false; + return; + case DATA_DANCE_FAIL: + _heiganAchievement = false; + return; + case DATA_HEIGAN_ERUPTION: + HeiganEruptSections(data); + return; + default: + return; + } + } + + bool SetBossState(uint32 bossId, EncounterState state) override + { + switch (bossId) + { + case BOSS_PATCHWERK: { - case BOSS_KELTHUZAD: - if (state == NOT_STARTED) - { - abominationsKilled = 0; - } + if (state != IN_PROGRESS) break; - case BOSS_FAERLINA: - if (state == NOT_STARTED) - { - faerlinaAchievement = true; - } - break; - case BOSS_THADDIUS: - if (state == NOT_STARTED) - { - thaddiusAchievement = true; - } - break; - case BOSS_LOATHEB: - if (state == NOT_STARTED) - { - loathebAchievement = true; - } - break; - case BOSS_HEIGAN: - if (state == NOT_STARTED) - { - heiganAchievement = true; - } - break; - case BOSS_SAPPHIRON: - if (state == DONE) - { - _speakTimer = 1; - } - else if (state == NOT_STARTED) - { - sapphironAchievement = true; - } - break; - default: - break; - } - // Save instance and open gates - if (state == DONE) - { - SaveToDB(); - - switch (bossId) + // pull all the trash if not killed + if (Creature* patchwerk = GetCreature(DATA_PATCHWERK_BOSS)) { - case BOSS_PATCHWERK: - if (GameObject* go = instance->GetGameObject(_patchwerkGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } + for (auto& itr : _patchwerkRoomTrash) + { + Creature* trash = ObjectAccessor::GetCreature(*patchwerk, itr); + if (trash && trash->IsAlive() && !trash->IsInCombat()) + trash->AI()->AttackStart(patchwerk->GetVictim()); + } + } + + break; + } + case BOSS_HEIGAN: + { + if (state == NOT_STARTED) + _heiganAchievement = true; + + break; + } + case BOSS_LOATHEB: + { + switch (state) + { + case NOT_STARTED: + _loathebAchievement = true; break; - case BOSS_GLUTH: - if (GameObject* go = instance->GetGameObject(_gluthGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_thaddiusGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case BOSS_NOTH: - if (GameObject* go = instance->GetGameObject(_nothExitGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_heiganGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case BOSS_HEIGAN: - if (GameObject* go = instance->GetGameObject(_heiganGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_heiganGateExitGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case BOSS_LOATHEB: - if (GameObject* go = instance->GetGameObject(_loathebGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_loathebPortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - if (GameObject* go = instance->GetGameObject(_plagueEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_plagueGlowEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s); - break; - case BOSS_ANUB: - if (GameObject* go = instance->GetGameObject(_anubNextGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case BOSS_FAERLINA: - if (GameObject* go = instance->GetGameObject(_faerlinaGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_maexxnaGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case BOSS_MAEXXNA: - if (GameObject* go = instance->GetGameObject(_maexxnaGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_maexxnaPortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - if (GameObject* go = instance->GetGameObject(_spiderEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_spiderGlowEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s); - break; - case BOSS_GOTHIK: - if (GameObject* go = instance->GetGameObject(_gothikEnterGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_gothikExitGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_horsemanGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 10s); - break; - case BOSS_SAPPHIRON: - events.ScheduleEvent(EVENT_FROSTWYRM_WATERFALL_DOOR, 5s); - break; - case BOSS_THADDIUS: - if (GameObject* go = instance->GetGameObject(_thaddiusPortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - if (GameObject* go = instance->GetGameObject(_abomEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_abomGlowEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s); - break; - case BOSS_HORSEMAN: - if (GameObject* go = instance->GetGameObject(_horsemanPortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - } - if (GameObject* go = instance->GetGameObject(_deathknightEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - if (GameObject* go = instance->GetGameObject(_deathknightGlowEyePortalGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6s); + case DONE: + ActivateWingPortal(DATA_LOATHEB_PORTAL); break; default: break; } - } - return true; - } - void Update(uint32 diff) override - { - if (_speakTimer) + break; + } + case BOSS_FAERLINA: { - Creature* kel = instance->GetCreature(_kelthuzadGUID); - Creature* lich = instance->GetCreature(_lichkingGUID); - if (kel && lich) + if (state == NOT_STARTED) + _faerlinaAchievement = true; + + break; + } + case BOSS_MAEXXNA: + { + if (state == DONE) + ActivateWingPortal(DATA_MAEXXNA_PORTAL); + + break; + } + case BOSS_THADDIUS: + { + switch (state) { - _speakTimer += diff; + case NOT_STARTED: + _thaddiusAchievement = true; + break; + case DONE: + ActivateWingPortal(DATA_THADDIUS_PORTAL); + break; + default: + break; } - else + + break; + } + case BOSS_HORSEMAN: + { + uint32 horsemanKilled = std::count_if(HorsemanDataGroup.begin(), HorsemanDataGroup.end(), [this](auto&& entry) { - return; - } - if (_speakTimer > 10000 && _speakTimer < 20000) + Creature* cr = GetCreature(entry); + return cr && !cr->IsAlive(); + }); + + switch (state) { - kel->AI()->Talk(SAY_SAPP_DIALOG1); - _speakTimer = 20000; - } - else if (_speakTimer > 30000 && _speakTimer < 40000) - { - lich->AI()->Talk(SAY_SAPP_DIALOG2_LICH); - _speakTimer = 40000; - } - else if (_speakTimer > 54000 && _speakTimer < 60000) - { - kel->AI()->Talk(SAY_SAPP_DIALOG3); - _speakTimer = 60000; - } - else if (_speakTimer > 70000 && _speakTimer < 80000) - { - lich->AI()->Talk(SAY_SAPP_DIALOG4_LICH); - _speakTimer = 80000; - } - else if (_speakTimer > 92000 && _speakTimer < 100000) - { - kel->AI()->Talk(SAY_SAPP_DIALOG5); - _speakTimer = 100000; - } - else if (_speakTimer > 105000) - { - kel->AI()->Talk(SAY_SAPP_DIALOG6); - _speakTimer = 0; - if (GameObject* go = instance->GetGameObject(_kelthuzadGateGUID)) + case NOT_STARTED: { - go->SetGoState(GO_STATE_ACTIVE); + _horsemanAchievement = true; + + if (!horsemanKilled) + break; + + for (auto&& entry : HorsemanDataGroup) + { + if (Creature* cr = GetCreature(entry)) + { + cr->SetPosition(cr->GetHomePosition()); + cr->Respawn(); + } + } + + break; } + case IN_PROGRESS: + { + for (auto&& entry : HorsemanDataGroup) + if (Creature* cr = GetCreature(entry)) + cr->SetInCombatWithZone(); + + break; + } + case DONE: + { + _events.RescheduleEvent(EVENT_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER, 15s); + + if (horsemanKilled != HorsemanCount) + return false; + + // all horsemans are killed + if (Creature* cr = GetCreature(DATA_BARON_RIVENDARE_BOSS)) + cr->CastSpell(cr, SPELL_THE_FOUR_HORSEMAN_CREDIT, true); + + ActivateWingPortal(DATA_HORSEMAN_PORTAL); + break; + } + default: + break; } - } - // And They would all - if (_horsemanTimer) - { - _horsemanTimer += diff; + break; } - - if (_screamTimer && GetBossState(BOSS_THADDIUS) != DONE) + case BOSS_SAPPHIRON: { - if (_screamTimer <= diff) + switch (state) { - instance->PlayDirectSoundToMap(SOUND_SCREAM + urand(0, 3)); - _screamTimer = (2 * MINUTE + urand(0, 30)) * IN_MILLISECONDS; + case NOT_STARTED: + _sapphironAchievement = true; + break; + case DONE: + { + if (GetPersistentData(PERSISTENT_DATA_KELTHUZAD_DIALOG)) + break; + + StorePersistentData(PERSISTENT_DATA_KELTHUZAD_DIALOG, 1); + SetGoState(DATA_KELTHUZAD_GATE, GO_STATE_READY); + _events.ScheduleEvent(EVENT_FROSTWYRM_WATERFALL_DOOR, 5s); + break; + } + default: + break; } - else - { - _screamTimer -= diff; - } - } - events.Update(diff); - switch (events.ExecuteEvent()) + break; + } + case BOSS_KELTHUZAD: { - case EVENT_KELTHUZAD_WING_TAUNT: - if (Creature* kelthuzad = instance->GetCreature(_kelthuzadGUID)) - { - kelthuzad->AI()->Talk(_currentWingTaunt); - } - ++_currentWingTaunt; - break; - case EVENT_FROSTWYRM_WATERFALL_DOOR: - if (GameObject* go = instance->GetGameObject(_sapphironGateGUID)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - break; - case EVENT_HORSEMEN_INTRO: - switch (_currentHorsemenLine) - { - case 0: // To arms, ye roustabouts! We've got company! - if (Creature* korthazz = instance->GetCreature(_korthazzGUID)) - korthazz->AI()->Talk(SAY_HORSEMEN_DIALOG1); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 4500ms); - break; - case 1: // Invaders, cease this foolish venture at once! Turn away while you still can! - if (Creature* zeliek = instance->GetCreature(_zeliekGUID)) - zeliek->AI()->Talk(SAY_HORSEMEN_DIALOG1); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 2: // Come, Zeliek, do not drive them out. Not before we've had our fun! - if (Creature* blaumeux = instance->GetCreature(_blaumeuxGUID)) - blaumeux->AI()->Talk(SAY_HORSEMEN_DIALOG1); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 3: // Enough prattling. Let them come. We shall grind their bones to dust. - if (Creature* rivendare = instance->GetCreature(_rivendareGUID)) - rivendare->AI()->Talk(SAY_HORSEMEN_DIALOG1); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 4: // I do hope they stay alive long enough for me to... introduce myself. - if (Creature* blaumeux = instance->GetCreature(_blaumeuxGUID)) - blaumeux->AI()->Talk(SAY_HORSEMEN_DIALOG2); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 5: // Perhaps they will come to their senses... and run away as fast as they can. - if (Creature* zeliek = instance->GetCreature(_zeliekGUID)) - zeliek->AI()->Talk(SAY_HORSEMEN_DIALOG2); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 6: // I've heard about enough a' yer snivelin'! Shut yer flytrap before I shut it for ye'! - if (Creature* korthazz = instance->GetCreature(_korthazzGUID)) - korthazz->AI()->Talk(SAY_HORSEMEN_DIALOG2); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - case 7: // Conserve your anger. Harness your rage. You will all have outlets for your frustrations soon enough. - if (Creature* rivendare = instance->GetCreature(_rivendareGUID)) - rivendare->AI()->Talk(SAY_HORSEMEN_DIALOG2); - events.ScheduleEvent(EVENT_HORSEMEN_INTRO, 6500ms); - break; - } - ++_currentHorsemenLine; - break; + if (state == NOT_STARTED) + _abominationsKilled = 0; + + break; } + default: + break; } - ObjectGuid GetGuidData(uint32 id) const override - { - switch (id) - { - // GameObjects - case DATA_HEIGAN_ENTER_GATE: - return _heiganGateGUID; - case DATA_LOATHEB_GATE: - return _loathebGateGUID; - case DATA_FAERLINA_WEB: - return _faerlinaWebGUID; - case DATA_MAEXXNA_GATE: - return _maexxnaGateGUID; - case DATA_GOTHIK_ENTER_GATE: - return _gothikEnterGateGUID; - case DATA_GOTHIK_INNER_GATE: - return _gothikInnerGateGUID; - case DATA_GOTHIK_EXIT_GATE: - return _gothikExitGateGUID; - case DATA_HORSEMEN_GATE: - return _horsemanGateGUID; - case DATA_THADDIUS_GATE: - return _thaddiusGateGUID; - case DATA_NOTH_ENTRY_GATE: - return _nothEntryGateGUID; - case DATA_KELTHUZAD_FLOOR: - return _kelthuzadFloorGUID; - case DATA_KELTHUZAD_GATE: - return _kelthuzadGateGUID; - case DATA_KELTHUZAD_PORTAL_1: - return _kelthuzadPortal1GUID; - case DATA_KELTHUZAD_PORTAL_2: - return _kelthuzadPortal2GUID; - case DATA_KELTHUZAD_PORTAL_3: - return _kelthuzadPortal3GUID; - case DATA_KELTHUZAD_PORTAL_4: - return _kelthuzadPortal4GUID; - - // NPCs - case DATA_THADDIUS_BOSS: - return _thaddiusGUID; - case DATA_STALAGG_BOSS: - return _stalaggGUID; - case DATA_FEUGEN_BOSS: - return _feugenGUID; - case DATA_GOTHIK_BOSS: - return _gothikGUID; - case DATA_LICH_KING_BOSS: - return _lichkingGUID; - default: - break; - } - - return ObjectGuid::Empty; - } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> immortalAchievement; - } - - void WriteSaveDataMore(std::ostringstream& data) override - { - data << immortalAchievement; - } - }; -}; -class boss_naxxramas_misc : public CreatureScript -{ -public: - boss_naxxramas_misc() : CreatureScript("boss_naxxramas_misc") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetNaxxramasAI(pCreature); + return InstanceScript::SetBossState(bossId, state); } - struct boss_naxxramas_miscAI : public NullCreatureAI + void Update(uint32 diff) override { - explicit boss_naxxramas_miscAI(Creature* c) : NullCreatureAI(c) - { - timer = 0; - } + _events.Update(diff); - uint32 timer; - - void JustDied(Unit* /*killer*/) override + switch (_events.ExecuteEvent()) { - if (me->GetEntry() == NPC_MR_BIGGLESWORTH && me->GetInstanceScript()) + case EVENT_THADDIUS_SCREAMS: { - if (Creature* cr = me->SummonCreature(20350/*NPC_KELTHUZAD*/, *me, TEMPSUMMON_TIMED_DESPAWN, 1)) - { - cr->SetDisplayId(11686); - cr->AI()->Talk(SAY_CAT_DIED); - } - } - } + if (GetBossState(BOSS_THADDIUS) == DONE) + break; - void UpdateAI(uint32 diff) override - { - if (me->GetEntry() == NPC_NAXXRAMAS_TRIGGER) - { - timer += diff; - if (timer >= 5000) - { - if (Creature* cr = me->SummonCreature(NPC_LIVING_POISON, 3128.59, -3118.81, 293.346, 4.76754, TEMPSUMMON_TIMED_DESPAWN, 15200)) - { - cr->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - cr->GetMotionMaster()->MovePoint(0, 3130.322, -3156.51, 293.324, false); - } - if (Creature* cr = me->SummonCreature(NPC_LIVING_POISON, *me, TEMPSUMMON_TIMED_DESPAWN, 14800)) - { - cr->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - cr->GetMotionMaster()->MovePoint(0, 3144.779, -3158.416, 293.324, false); - } - if (Creature* cr = me->SummonCreature(NPC_LIVING_POISON, 3175.42, -3134.86, 293.34, 4.284, TEMPSUMMON_TIMED_DESPAWN, 14800)) - { - cr->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - cr->GetMotionMaster()->MovePoint(0, 3158.778, -3164.201, 293.312, false); - } - timer = 0; - } - } - else if (me->GetEntry() == NPC_LIVING_POISON) - { - Unit* target = nullptr; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 0.5f); - Acore::UnitLastSearcher searcher(me, target, u_check); - Cell::VisitAllObjects(me, searcher, 1.5f); - if (target) - { - me->CastSpell(me, SPELL_FROGGER_EXPLODE, true); - } + instance->PlayDirectSoundToMap(SOUND_SCREAM + urand(0, 3)); + return _events.ScheduleEvent(EVENT_THADDIUS_SCREAMS, 2min, 2min + 30s); } + case EVENT_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER: + _horsemanAchievement = false; + break; + case EVENT_KELTHUZAD_WING_TAUNT: + return CreatureTalk(DATA_KELTHUZAD_BOSS, _currentWingTaunt++); + case EVENT_HORSEMEN_INTRO1: + CreatureTalk(DATA_THANE_KORTHAZZ_BOSS, SAY_HORSEMEN_DIALOG1); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO2, 4500ms); + case EVENT_HORSEMEN_INTRO2: + CreatureTalk(DATA_SIR_ZELIEK_BOSS, SAY_HORSEMEN_DIALOG1); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO3, 6500ms); + case EVENT_HORSEMEN_INTRO3: + CreatureTalk(DATA_LADY_BLAUMEUX_BOSS, SAY_HORSEMEN_DIALOG1); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO4, 6500ms); + case EVENT_HORSEMEN_INTRO4: + CreatureTalk(DATA_BARON_RIVENDARE_BOSS, SAY_HORSEMEN_DIALOG1); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO5, 6500ms); + case EVENT_HORSEMEN_INTRO5: + CreatureTalk(DATA_LADY_BLAUMEUX_BOSS, SAY_HORSEMEN_DIALOG2); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO6, 6500ms); + case EVENT_HORSEMEN_INTRO6: + CreatureTalk(DATA_SIR_ZELIEK_BOSS, SAY_HORSEMEN_DIALOG2); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO7, 6500ms); + case EVENT_HORSEMEN_INTRO7: + CreatureTalk(DATA_THANE_KORTHAZZ_BOSS, SAY_HORSEMEN_DIALOG2); + return _events.ScheduleEvent(EVENT_HORSEMEN_INTRO8, 6500ms); + case EVENT_HORSEMEN_INTRO8: + return CreatureTalk(DATA_BARON_RIVENDARE_BOSS, SAY_HORSEMEN_DIALOG2); + case EVENT_FROSTWYRM_WATERFALL_DOOR: + SetGoState(DATA_SAPPHIRON_GATE, GO_STATE_ACTIVE); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK1, 5s); + case EVENT_KELTHUZAD_LICH_KING_TALK1: + CreatureTalk(DATA_KELTHUZAD_BOSS, SAY_SAPP_DIALOG1); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK2, 10s); + case EVENT_KELTHUZAD_LICH_KING_TALK2: + CreatureTalk(DATA_LICH_KING_BOSS, SAY_SAPP_DIALOG2_LICH); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK3, 14s); + case EVENT_KELTHUZAD_LICH_KING_TALK3: + CreatureTalk(DATA_KELTHUZAD_BOSS, SAY_SAPP_DIALOG3); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK4, 10s); + case EVENT_KELTHUZAD_LICH_KING_TALK4: + CreatureTalk(DATA_LICH_KING_BOSS, SAY_SAPP_DIALOG4_LICH); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK5, 12s); + case EVENT_KELTHUZAD_LICH_KING_TALK5: + CreatureTalk(DATA_KELTHUZAD_BOSS, SAY_SAPP_DIALOG5); + return _events.ScheduleEvent(EVENT_KELTHUZAD_LICH_KING_TALK6, 5s); + case EVENT_KELTHUZAD_LICH_KING_TALK6: + CreatureTalk(DATA_KELTHUZAD_BOSS, SAY_SAPP_DIALOG6); + return SetGoState(DATA_KELTHUZAD_GATE, GO_STATE_ACTIVE); + default: + break; } - }; + } + +private: + // Controls + EventMap _events; + uint8 _currentWingTaunt; + uint8 _horsemanLoaded; + + // GameObjects + std::set _heiganEruption[HeiganEruptSectionCount]; + + // NPCs + GuidList _patchwerkRoomTrash; + + // Achievements + uint8 _abominationsKilled; + bool _faerlinaAchievement; + bool _thaddiusAchievement; + bool _loathebAchievement; + bool _sapphironAchievement; + bool _heiganAchievement; + bool _horsemanAchievement; }; -const Position sapphironEntryTP = { 3498.300049f, -5349.490234f, 144.968002f, 1.3698910f }; +class npc_mr_bigglesworth : public NullCreatureAI +{ +public: + npc_mr_bigglesworth(Creature* c) : NullCreatureAI(c) { } + + void JustDied(Unit* /*killer*/) override + { + InstanceScript* instance = me->GetInstanceScript(); + if (!instance) + return; + + Creature* kelThuzard = instance->GetCreature(DATA_KELTHUZAD_BOSS); + if (!kelThuzard) + return; + + kelThuzard->AI()->Talk(SAY_CAT_DIED); + } +}; + +class npc_living_poison : public NullCreatureAI +{ +public: + npc_living_poison(Creature* c) : NullCreatureAI(c) { } + + void UpdateAI(uint32 /*diff*/) override + { + if (me->SelectNearestTarget(1.5f, true)) + me->CastSpell(me, SPELL_EXPLODE, true); + } +}; + +class npc_naxxramas_trigger : public NullCreatureAI +{ +public: + npc_naxxramas_trigger(Creature* c) : NullCreatureAI(c) { } + + void Reset() override + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SUMMON_LIVING_POISON, 5s); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + switch (_events.ExecuteEvent()) + { + case EVENT_SUMMON_LIVING_POISON: + { + for (LivingPoisonData const& entry : LivingPoisonDataList) + if (Creature* cr = me->SummonCreature(NPC_LIVING_POISON, entry.Start, TEMPSUMMON_TIMED_DESPAWN, entry.DespawnTime)) + { + cr->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + cr->GetMotionMaster()->MovePoint(0, entry.End, false); + } + + _events.Repeat(5s); + break; + } + default: + break; + } + } + +private: + EventMap _events; +}; class at_naxxramas_hub_portal : public AreaTriggerScript { @@ -1269,29 +767,29 @@ public: bool OnTrigger(Player* player, AreaTrigger const* /*trigger*/) override { - if (player->IsAlive() && !player->IsInCombat()) - { - if (InstanceScript *instance = player->GetInstanceScript()) - { - bool AreAllWingsCleared = instance->GetBossState(BOSS_MAEXXNA) == DONE - && (instance->GetBossState(BOSS_LOATHEB) == DONE) - && (instance->GetBossState(BOSS_THADDIUS) == DONE) - && (instance->GetBossState(BOSS_HORSEMAN) == DONE); + if (!player->IsAlive() || player->IsInCombat()) + return false; - if (AreAllWingsCleared) - { - player->TeleportTo(533, sapphironEntryTP.m_positionX, sapphironEntryTP.m_positionY, sapphironEntryTP.m_positionZ, sapphironEntryTP.m_orientation); - return true; - } - } - } - return false; + InstanceScript* instance = player->GetInstanceScript(); + if (!instance) + return false; + + if ((instance->GetBossState(BOSS_MAEXXNA) != DONE) || + (instance->GetBossState(BOSS_LOATHEB) != DONE) || + (instance->GetBossState(BOSS_THADDIUS) != DONE) || + (instance->GetBossState(BOSS_HORSEMAN) != DONE)) + return false; + + player->TeleportTo(SapphironTeleportPos); + return true; } }; void AddSC_instance_naxxramas() { - new instance_naxxramas(); - new boss_naxxramas_misc(); + RegisterInstanceScript(instance_naxxramas, NaxxramasMapId); + RegisterNaxxramasCreatureAI(npc_mr_bigglesworth); + RegisterNaxxramasCreatureAI(npc_living_poison); + RegisterNaxxramasCreatureAI(npc_naxxramas_trigger); new at_naxxramas_hub_portal(); } diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 981230f15..b77b124ea 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -18,68 +18,78 @@ #ifndef DEF_NAXXRAMAS_H #define DEF_NAXXRAMAS_H -#include "CreatureAIImpl.h" - #define DataHeader "NAX" #define NaxxramasScriptName "instance_naxxramas" -enum Encouters +enum NaxxramasEncouter { - BOSS_PATCHWERK = 0, - BOSS_GROBBULUS = 1, - BOSS_GLUTH = 2, - BOSS_NOTH = 3, - BOSS_HEIGAN = 4, - BOSS_LOATHEB = 5, - BOSS_ANUB = 6, - BOSS_FAERLINA = 7, - BOSS_MAEXXNA = 8, - BOSS_THADDIUS = 9, - BOSS_RAZUVIOUS = 10, - BOSS_GOTHIK = 11, - BOSS_HORSEMAN = 12, - BOSS_SAPPHIRON = 13, - BOSS_KELTHUZAD = 14, - MAX_ENCOUNTERS, + BOSS_PATCHWERK = 0, + BOSS_GROBBULUS = 1, + BOSS_GLUTH = 2, + BOSS_NOTH = 3, + BOSS_HEIGAN = 4, + BOSS_LOATHEB = 5, + BOSS_ANUB = 6, + BOSS_FAERLINA = 7, + BOSS_MAEXXNA = 8, + BOSS_THADDIUS = 9, + BOSS_RAZUVIOUS = 10, + BOSS_GOTHIK = 11, + BOSS_HORSEMAN = 12, + BOSS_SAPPHIRON = 13, + BOSS_KELTHUZAD = 14, + MAX_ENCOUNTERS }; -enum NXData +enum NaxxramasData { - DATA_NOTH_ENTRY_GATE = 100, - DATA_HEIGAN_ERUPTION = 101, - DATA_HEIGAN_ENTER_GATE = 102, - DATA_LOATHEB_GATE = 103, - DATA_FAERLINA_WEB = 105, - DATA_MAEXXNA_GATE = 106, - DATA_THADDIUS_BOSS = 107, - DATA_STALAGG_BOSS = 108, - DATA_FEUGEN_BOSS = 109, - DATA_THADDIUS_GATE = 110, - DATA_RAZUVIOUS = 111, - DATA_GOTHIK_BOSS = 112, - DATA_GOTHIK_ENTER_GATE = 113, - DATA_GOTHIK_INNER_GATE = 114, - DATA_GOTHIK_EXIT_GATE = 115, - DATA_HORSEMEN_GATE = 116, - DATA_LICH_KING_BOSS = 117, - DATA_KELTHUZAD_FLOOR = 118, - DATA_ABOMINATION_KILLED = 119, - DATA_FRENZY_REMOVED = 120, - DATA_CHARGES_CROSSED = 121, - DATA_SPORE_KILLED = 122, - DATA_HUNDRED_CLUB = 123, - DATA_DANCE_FAIL = 124, - DATA_IMMORTAL_FAIL = 125, - DATA_KELTHUZAD_GATE = 126, - DATA_HAD_THADDIUS_GREET = 127, - DATA_KELTHUZAD_PORTAL_1 = 128, - DATA_KELTHUZAD_PORTAL_2 = 129, - DATA_KELTHUZAD_PORTAL_3 = 130, - DATA_KELTHUZAD_PORTAL_4 = 131 + DATA_PATCHWERK_BOSS = 100, + DATA_STALAGG_BOSS = 101, + DATA_FEUGEN_BOSS = 102, + DATA_THADDIUS_BOSS = 103, + DATA_RAZUVIOUS_BOSS = 104, + DATA_GOTHIK_BOSS = 105, + DATA_BARON_RIVENDARE_BOSS = 106, + DATA_SIR_ZELIEK_BOSS = 107, + DATA_LADY_BLAUMEUX_BOSS = 108, + DATA_THANE_KORTHAZZ_BOSS = 109, + DATA_SAPPHIRON_BOSS = 110, + DATA_KELTHUZAD_BOSS = 111, + DATA_LICH_KING_BOSS = 112, + + DATA_LOATHEB_PORTAL = 200, + DATA_MAEXXNA_PORTAL = 201, + DATA_THADDIUS_PORTAL = 202, + DATA_HORSEMAN_PORTAL = 203, + DATA_GOTHIK_INNER_GATE = 204, + DATA_SAPPHIRON_GATE = 205, + DATA_KELTHUZAD_GATE = 206, + DATA_KELTHUZAD_FLOOR = 207, + DATA_KELTHUZAD_PORTAL_1 = 208, + DATA_KELTHUZAD_PORTAL_2 = 209, + DATA_KELTHUZAD_PORTAL_3 = 210, + DATA_KELTHUZAD_PORTAL_4 = 211, + + DATA_HEIGAN_ERUPTION = 300, + DATA_DANCE_FAIL = 301, + DATA_SPORE_KILLED = 302, + DATA_FRENZY_REMOVED = 303, + DATA_THADDIUS_INTRO = 304, + DATA_CHARGES_CROSSED = 305, + DATA_HUNDRED_CLUB = 306, + DATA_ABOMINATION_KILLED = 307, }; -enum NXGOs +enum NaxxramasPersistentData +{ + PERSISTENT_DATA_THADDIUS_INTRO = 0, + PERSISTENT_DATA_KELTHUZAD_DIALOG = 1, + PERSISTENT_DATA_IMMORTAL_FAIL = 2, + PERSISTENT_DATA_COUNT +}; + +enum NaxxramasGameObject { GO_PATCHWERK_GATE = 181123, GO_GLUTH_GATE = 181120, @@ -129,8 +139,25 @@ enum NXGOs GO_CONS_EYE_RAMP_BOSS = 181232 }; -enum NXNPCs +enum NaxxramasGameObjectsDisplayId { + GO_DISPLAY_ID_HEIGAN_ERUPTION1 = 1287, + GO_DISPLAY_ID_HEIGAN_ERUPTION2 = 6785 +}; + +enum NaxxramasCreatureId +{ + // Patchwerk + NPC_PATCHWERK = 16028, + NPC_PATCHWORK_GOLEM = 16017, + NPC_BILE_RETCHER = 16018, + NPC_MAD_SCIENTIST = 16020, + NPC_LIVING_MONSTROSITY = 16021, + NPC_SURGICAL_ASSIST = 16022, + NPC_SLUDGE_BELCHER = 16029, + + NPC_LIVING_POISON = 16027, + // Thaddius NPC_THADDIUS = 15928, NPC_STALAGG = 15929, @@ -139,6 +166,9 @@ enum NXNPCs // Razuvious NPC_RAZUVIOUS = 16061, + // Gothik + NPC_GOTHIK = 16060, + // Four horseman NPC_BARON_RIVENDARE = 30549, NPC_SIR_ZELIEK = 16063, @@ -150,30 +180,124 @@ enum NXNPCs // Kel'Thuzad NPC_KELTHUZAD = 15990, - NPC_LICH_KING = 16980, - - // Frogger - NPC_LIVING_POISON = 16027, - NPC_NAXXRAMAS_TRIGGER = 16082, - NPC_MR_BIGGLESWORTH = 16998, - - // Patchwerk - NPC_PATCHWERK = 16028, - NPC_PATCHWORK_GOLEM = 16017, - NPC_BILE_RETCHER = 16018, - NPC_MAD_SCIENTIST = 16020, - NPC_LIVING_MONSTROSITY = 16021, - NPC_SURGICAL_ASSIST = 16022, - NPC_SLUDGE_BELCHER = 16029, - - // Gothik - NPC_GOTHIK = 16060 + NPC_LICH_KING = 16980 }; -enum NXMisc +enum NaxxramasAchievemmentCriteria +{ + ACHIEV_CRITERIA_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER_10_PLAYER = 7600, // And They Would All Go Down Together (10 player) + ACHIEV_CRITERIA_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER_25_PLAYER = 7601, // And They Would All Go Down Together (25 player) + + ACHIEV_CRITERIA_JUST_CANT_GET_ENOUGH_10_PLAYER = 7614, // Just Can't Get Enough (10 player) + ACHIEV_CRITERIA_JUST_CANT_GET_ENOUGH_25_PLAYER = 7615, // Just Can't Get Enough (25 player) + + ACHIEV_CRITERIA_MOMMA_SAID_KNOCK_YOU_OUT_10_PLAYER = 7265, // Momma Said Knock You Out (10 player) + ACHIEV_CRITERIA_MOMMA_SAID_KNOCK_YOU_OUT_25_PLAYER = 7549, // Momma Said Knock You Out (25 player) + + ACHIEV_CRITERIA_SHOKING_10_PLAYER = 7604, // Shocking! (10 player) + ACHIEV_CRITERIA_SHOKING_25_PLAYER = 7605, // Shocking! (25 player) + + ACHIEV_CRITERIA_SPORE_LOSER_10_PLAYER = 7612, // Spore Loser (10 player) + ACHIEV_CRITERIA_SPORE_LOSER_25_PLAYER = 7613, // Spore Loser (25 player) + + ACHIEV_CRITERIA_THE_SAFETY_DANCE_10_PLAYER = 7264, // The Safety Dance (10 player) + ACHIEV_CRITERIA_THE_SAFETY_DANCE_25_PLAYER = 7548, // The Safety Dance (25 player) + + ACHIEV_CRITERIA_SUBTRACTION_10_PLAYER = 7608, // Subtraction (10 player) + ACHIEV_CRITERIA_SUBTRACTION_25_PLAYER = 7609, // Subtraction (25 player) + + ACHIEV_CRITERIA_THE_HUNDRED_CLUB_10_PLAYER = 7567, // The Hundred Club (10 player) + ACHIEV_CRITERIA_THE_HUNDRED_CLUB_25_PLAYER = 7568, // The Hundred Club (25 player) + + ACHIEV_CRITERIA_THE_DEDICATED_FEW_ANUB_10_PLAYER = 7146, // The Dedicated Few (25 player) - Anub'Rekhan + ACHIEV_CRITERIA_THE_DEDICATED_FEW_FAERLINA_10_PLAYER = 7147, // The Dedicated Few (25 player) - Grand Widow Faerlina + ACHIEV_CRITERIA_THE_DEDICATED_FEW_MAEXXNA_10_PLAYER = 7148, // The Dedicated Few (25 player) - Maexxna + ACHIEV_CRITERIA_THE_DEDICATED_FEW_PATCHWERK_10_PLAYER = 7149, // The Dedicated Few (25 player) - Patchwerk + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GROBBULUS_10_PLAYER = 7150, // The Dedicated Few (25 player) - Grobbulus + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GLUTH_10_PLAYER = 7151, // The Dedicated Few (25 player) - Gluth + ACHIEV_CRITERIA_THE_DEDICATED_FEW_THADDIUS_10_PLAYER = 7152, // The Dedicated Few (25 player) - Thaddius + ACHIEV_CRITERIA_THE_DEDICATED_FEW_NOTH_10_PLAYER = 7153, // The Dedicated Few (25 player) - Noth the Plaguebringer + ACHIEV_CRITERIA_THE_DEDICATED_FEW_HEIGAN_10_PLAYER = 7154, // The Dedicated Few (25 player) - Heigan the Unclean + ACHIEV_CRITERIA_THE_DEDICATED_FEW_LOATHEB_10_PLAYER = 7155, // The Dedicated Few (25 player) - Loatheb + ACHIEV_CRITERIA_THE_DEDICATED_FEW_RAZUVIOUS_10_PLAYER = 7156, // The Dedicated Few (25 player) - Instructor Razuvious + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GOTHIK_10_PLAYER = 7157, // The Dedicated Few (25 player) - Gothik the Harvester + ACHIEV_CRITERIA_THE_DEDICATED_FEW_SAPPHIRON_10_PLAYER = 7158, // The Dedicated Few (25 player) - Sapphiron + ACHIEV_CRITERIA_THE_DEDICATED_FEW_KELTHUZAD_10_PLAYER = 6802, // The Dedicated Few (25 player) - Kel'Thuzad + + ACHIEV_CRITERIA_THE_DEDICATED_FEW_ANUB_25_PLAYER = 7159, // The Dedicated Few (25 player) - Anub'Rekhan + ACHIEV_CRITERIA_THE_DEDICATED_FEW_FAERLINA_25_PLAYER = 7160, // The Dedicated Few (25 player) - Grand Widow Faerlina + ACHIEV_CRITERIA_THE_DEDICATED_FEW_MAEXXNA_25_PLAYER = 7161, // The Dedicated Few (25 player) - Maexxna + ACHIEV_CRITERIA_THE_DEDICATED_FEW_PATCHWERK_25_PLAYER = 7162, // The Dedicated Few (25 player) - Patchwerk + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GROBBULUS_25_PLAYER = 7163, // The Dedicated Few (25 player) - Grobbulus + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GLUTH_25_PLAYER = 7164, // The Dedicated Few (25 player) - Gluth + ACHIEV_CRITERIA_THE_DEDICATED_FEW_THADDIUS_25_PLAYER = 7165, // The Dedicated Few (25 player) - Thaddius + ACHIEV_CRITERIA_THE_DEDICATED_FEW_NOTH_25_PLAYER = 7166, // The Dedicated Few (25 player) - Noth the Plaguebringer + ACHIEV_CRITERIA_THE_DEDICATED_FEW_HEIGAN_25_PLAYER = 7167, // The Dedicated Few (25 player) - Heigan the Unclean + ACHIEV_CRITERIA_THE_DEDICATED_FEW_LOATHEB_25_PLAYER = 7168, // The Dedicated Few (25 player) - Loatheb + ACHIEV_CRITERIA_THE_DEDICATED_FEW_RAZUVIOUS_25_PLAYER = 7169, // The Dedicated Few (25 player) - Instructor Razuvious + ACHIEV_CRITERIA_THE_DEDICATED_FEW_GOTHIK_25_PLAYER = 7170, // The Dedicated Few (25 player) - Gothik the Harvester + ACHIEV_CRITERIA_THE_DEDICATED_FEW_SAPPHIRON_25_PLAYER = 7171, // The Dedicated Few (25 player) - Sapphiron + ACHIEV_CRITERIA_THE_DEDICATED_FEW_KELTHUZAD_25_PLAYER = 7172, // The Dedicated Few (25 player) - Kel'Thuzad + + ACHIEV_CRITERIA_THE_UNDYING_KELTHUZAD = 7617, // The Undying - Kel'Thuzad + ACHIEV_CRITERIA_THE_UNDYING_THE_FOUR_HORSEMEN = 13237, // The Undying - The Four Horsemen + ACHIEV_CRITERIA_THE_UNDYING_MAEXXNA = 13238, // The Undying - Maexxna + ACHIEV_CRITERIA_THE_UNDYING_LOATHEB = 13239, // The Undying - Loatheb + ACHIEV_CRITERIA_THE_UNDYING_THADDIUS = 13240, // The Undying - Thaddius + + ACHIEV_CRITERIA_THE_IMMORTAL_KELTHUZAD = 7616, // The Immortal - Kel'Thuzad + ACHIEV_CRITERIA_THE_IMMORTAL_THE_FOUR_HORSEMEN = 13233, // The Immortal - The Four Horsemen + ACHIEV_CRITERIA_THE_IMMORTAL_MAEXXNA = 13234, // The Immortal - Maexxna + ACHIEV_CRITERIA_THE_IMMORTAL_LOATHEB = 13235, // The Immortal - Loatheb + ACHIEV_CRITERIA_THE_IMMORTAL_THADDIUS = 13236 // The Immortal - Thaddius +}; + +enum NaxxramasSay +{ + SAY_HORSEMEN_DIALOG1 = 5, + SAY_HORSEMEN_DIALOG2 = 6, + + SAY_SAPP_DIALOG1 = 0, + SAY_SAPP_DIALOG2_LICH = 1, + SAY_SAPP_DIALOG3 = 2, + SAY_SAPP_DIALOG4_LICH = 2, + SAY_SAPP_DIALOG5 = 4, + SAY_SAPP_DIALOG6 = 20, + + SAY_CAT_DIED = 5, // No!!! A curse upon you, interlopers! The armies of the Lich King will hunt you down. You will not escape your fate... + SAY_FIRST_WING_TAUNT = 16 +}; + +enum NaxxramasEvent +{ + EVENT_SUMMON_LIVING_POISON = 1, + EVENT_THADDIUS_SCREAMS = 2, + EVENT_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER = 3, + EVENT_KELTHUZAD_WING_TAUNT = 4, + + EVENT_HORSEMEN_INTRO1 = 5, // Thane Korth'azz: To arms, ye roustabouts! We've got company! + EVENT_HORSEMEN_INTRO2 = 6, // Sir Zeliek: Invaders, cease this foolish venture at once! Turn away while you still can! + EVENT_HORSEMEN_INTRO3 = 7, // Lady Blaumeux: Come, Zeliek, do not drive them out. Not before we've had our fun! + EVENT_HORSEMEN_INTRO4 = 8, // Baron Rivendare: Enough prattling. Let them come. We shall grind their bones to dust. + EVENT_HORSEMEN_INTRO5 = 9, // Lady Blaumeux: I do hope they stay alive long enough for me to... introduce myself. + EVENT_HORSEMEN_INTRO6 = 10, // Sir Zeliek: Perhaps they will come to their senses... and run away as fast as they can. + EVENT_HORSEMEN_INTRO7 = 11, // Thane Korth'azz: I've heard about enough a' yer snivelin'! Shut yer flytrap before I shut it for ye'! + EVENT_HORSEMEN_INTRO8 = 12, // Baron Rivendare: Conserve your anger. Harness your rage. You will all have outlets for your frustrations soon enough. + + EVENT_FROSTWYRM_WATERFALL_DOOR = 13, + EVENT_KELTHUZAD_LICH_KING_TALK1 = 14, + EVENT_KELTHUZAD_LICH_KING_TALK2 = 15, + EVENT_KELTHUZAD_LICH_KING_TALK3 = 16, + EVENT_KELTHUZAD_LICH_KING_TALK4 = 17, + EVENT_KELTHUZAD_LICH_KING_TALK5 = 18, + EVENT_KELTHUZAD_LICH_KING_TALK6 = 19 +}; + +enum NaxxramasMisc { SPELL_ERUPTION = 29371, - SPELL_FROGGER_EXPLODE = 28433, + SPELL_EXPLODE = 28433, + SPELL_THE_FOUR_HORSEMAN_CREDIT = 59450, ACTION_SAPPHIRON_BIRTH = 1, @@ -181,32 +305,19 @@ enum NXMisc SOUND_SCREAM = 8873 }; -enum NXSays -{ - SAY_SAPP_DIALOG1 = 0, - SAY_SAPP_DIALOG2_LICH = 1, - SAY_SAPP_DIALOG3 = 2, - SAY_SAPP_DIALOG4_LICH = 2, - SAY_SAPP_DIALOG5 = 4, - SAY_SAPP_DIALOG6 = 20, - SAY_CAT_DIED = 5, - SAY_FIRST_WING_TAUNT = 16, - SAY_HORSEMEN_DIALOG1 = 5, - SAY_HORSEMEN_DIALOG2 = 6 -}; +static constexpr uint32 NaxxramasMapId = 533; +static constexpr uint8 HeiganEruptSectionCount = 4; +static constexpr uint8 HorsemanCount = 4; +static constexpr uint8 AbominationKillCountReq = 18; +static constexpr uint8 TheDedicatedFew10PlayerReq = 9; +static constexpr uint8 TheDedicatedFew25PlayerReq = 21; -enum NXEvents -{ - EVENT_THADDIUS_SCREAMS = 0, - EVENT_KELTHUZAD_WING_TAUNT = 1, - EVENT_FROSTWYRM_WATERFALL_DOOR = 2, - EVENT_HORSEMEN_INTRO = 3 -}; - -template +template inline AI* GetNaxxramasAI(T* obj) { return GetInstanceAI(obj, NaxxramasScriptName); } +#define RegisterNaxxramasCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetNaxxramasAI) + #endif