diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp index b7a3822d5..e06c78c62 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp @@ -55,174 +55,126 @@ enum Misc PHASE_FAST_DANCE = 1 }; -class boss_heigan : public CreatureScript -{ -public: - boss_heigan() : CreatureScript("boss_heigan") { } +float const heiganFastDanceFaceDirection = 2.40f; - CreatureAI* GetAI(Creature* pCreature) const override +struct boss_heigan : public BossAI +{ + boss_heigan(Creature* creature) : BossAI(creature, DATA_HEIGAN_BOSS) { } + + void Reset() override { - return GetNaxxramasAI(pCreature); + BossAI::Reset(); + _currentPhase = 0; + _currentSection = 3; + _moveRight = true; } - struct boss_heiganAI : public BossAI + void KilledUnit(Unit* who) override { - explicit boss_heiganAI(Creature* c) : BossAI(c, BOSS_HEIGAN) - {} + if (!who->IsPlayer()) + return; - EventMap events; - uint8 currentPhase{}; - uint8 currentSection{}; - bool moveRight{}; + Talk(SAY_SLAY); + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); + } - void Reset() override + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + Talk(EMOTE_DEATH); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + me->SetInCombatWithZone(); + Talk(SAY_AGGRO); + StartFightPhase(PHASE_SLOW_DANCE); + } + + void StartFightPhase(uint8 phase) + { + _currentSection = 3; + _currentPhase = phase; + scheduler.CancelAll(); + if (phase == PHASE_SLOW_DANCE) { - BossAI::Reset(); - events.Reset(); - currentPhase = 0; - currentSection = 3; - moveRight = true; + me->CastStop(); + me->SetReactState(REACT_AGGRESSIVE); + DoZoneInCombat(); + ScheduleTimedEvent(12s, 15s, [&] { + DoCastSelf(SPELL_ERUPTION); + }, 10s); + ScheduleTimedEvent(17s, [&] { + DoCastSelf(SPELL_DECREPIT_FEVER); + }, 22s, 25s); + ScheduleTimedEvent(15s, [&] { + instance->SetData(DATA_HEIGAN_ERUPTION, _currentSection); + if (_currentSection == 3) + _moveRight = false; + else if (_currentSection == 0) + _moveRight = true; + + _moveRight ? _currentSection++ : _currentSection--; + Talk(SAY_TAUNT); + }, 10s); + scheduler.Schedule(90s, [this](TaskContext /*context*/) { + StartFightPhase(PHASE_FAST_DANCE); + }); } - - void KilledUnit(Unit* who) override + else // if (phase == PHASE_FAST_DANCE) { - if (!who->IsPlayer()) - return; + Talk(EMOTE_DANCE); + Talk(SAY_DANCE); + me->AttackStop(); + me->StopMoving(); + me->SetReactState(REACT_PASSIVE); + me->CastSpell(me, SPELL_TELEPORT_SELF, false); + me->SetFacingTo(heiganFastDanceFaceDirection); + scheduler.Schedule(1s, [this](TaskContext /*context*/) { + DoCastSelf(SPELL_PLAGUE_CLOUD); + }); + ScheduleTimedEvent(7s, [&] { + instance->SetData(DATA_HEIGAN_ERUPTION, _currentSection); + if (_currentSection == 3) + _moveRight = false; + else if (_currentSection == 0) + _moveRight = true; - Talk(SAY_SLAY); - instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); + _moveRight ? _currentSection++ : _currentSection--; + }, 4s); + scheduler.Schedule(45s, [this](TaskContext /*context*/) { + StartFightPhase(PHASE_SLOW_DANCE); + Talk(EMOTE_DANCE_END); // avoid play the emote on aggro + }); } + ScheduleTimedEvent(5s, [&] { + CheckSafetyDance(); + }, 5s); + } - void JustDied(Unit* killer) override + void CheckSafetyDance() + { + if (Map* map = me->GetMap()) { - BossAI::JustDied(killer); - Talk(EMOTE_DEATH); - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - me->SetInCombatWithZone(); - Talk(SAY_AGGRO); - StartFightPhase(PHASE_SLOW_DANCE); - } - - void StartFightPhase(uint8 phase) - { - currentSection = 3; - currentPhase = phase; - events.Reset(); - if (phase == PHASE_SLOW_DANCE) + map->DoForAllPlayers([&](Player* p) { - me->CastStop(); - me->SetReactState(REACT_AGGRESSIVE); - DoZoneInCombat(); - events.ScheduleEvent(EVENT_DISRUPTION, 12s, 15s); - events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17s); - events.ScheduleEvent(EVENT_ERUPT_SECTION, 15s); - events.ScheduleEvent(EVENT_SWITCH_PHASE, 90s); - } - else // if (phase == PHASE_FAST_DANCE) - { - Talk(EMOTE_DANCE); - Talk(SAY_DANCE); - me->AttackStop(); - me->StopMoving(); - me->SetReactState(REACT_PASSIVE); - me->CastSpell(me, SPELL_TELEPORT_SELF, false); - me->SetFacingTo(2.40f); - events.ScheduleEvent(EVENT_PLAGUE_CLOUD, 1s); - events.ScheduleEvent(EVENT_ERUPT_SECTION, 7s); - events.ScheduleEvent(EVENT_SWITCH_PHASE, 45s); - } - events.ScheduleEvent(EVENT_SAFETY_DANCE, 5s); - } - - bool IsInRoom(Unit* who) - { - if (who->GetPositionX() > 2826 || who->GetPositionX() < 2723 || who->GetPositionY() > -3641 || who->GetPositionY() < -3736) - { - if (who->GetGUID() == me->GetGUID()) - EnterEvadeMode(); - - return false; - } - return true; - } - - void UpdateAI(uint32 diff) override - { - if (!IsInRoom(me)) - return; - - if (!UpdateVictim()) - return; - - events.Update(diff); - - switch (events.ExecuteEvent()) - { - case EVENT_DISRUPTION: - me->CastSpell(me, SPELL_SPELL_DISRUPTION, false); - events.Repeat(10s); - break; - case EVENT_DECEPIT_FEVER: - me->CastSpell(me, SPELL_DECREPIT_FEVER, false); - events.Repeat(22s, 25s); - break; - case EVENT_PLAGUE_CLOUD: - me->CastSpell(me, SPELL_PLAGUE_CLOUD, false); - break; - case EVENT_SWITCH_PHASE: - if (currentPhase == PHASE_SLOW_DANCE) - { - StartFightPhase(PHASE_FAST_DANCE); - } - else - { - StartFightPhase(PHASE_SLOW_DANCE); - Talk(EMOTE_DANCE_END); // avoid play the emote on aggro - } - break; - case EVENT_ERUPT_SECTION: + if (IsInBoundary(p) && !p->IsAlive()) { - 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) - { - if (IsInRoom(itr.GetSource()) && !itr.GetSource()->IsAlive()) - { - instance->SetData(DATA_DANCE_FAIL, 0); - instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); - return; - } - } - events.Repeat(5s); + instance->SetData(DATA_DANCE_FAIL, 0); + instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1); return; } - } - - DoMeleeAttackIfReady(); + }); } - }; + } +private: + uint8 _currentPhase{}; + uint8 _currentSection{}; + bool _moveRight{true}; }; void AddSC_boss_heigan() { - new boss_heigan(); + RegisterNaxxramasCreatureAI(boss_heigan); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 24f96f3cd..7d4fa4546 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -109,6 +109,7 @@ static ObjectData const creatureData[] { NPC_THADDIUS, DATA_THADDIUS_BOSS }, { NPC_RAZUVIOUS, DATA_RAZUVIOUS_BOSS }, { NPC_GOTHIK, DATA_GOTHIK_BOSS }, + { NPC_HEIGAN, DATA_HEIGAN_BOSS }, { NPC_BARON_RIVENDARE, DATA_BARON_RIVENDARE_BOSS }, { NPC_SIR_ZELIEK, DATA_SIR_ZELIEK_BOSS }, { NPC_LADY_BLAUMEUX, DATA_LADY_BLAUMEUX_BOSS }, @@ -136,6 +137,12 @@ static ObjectData const gameObjectData[] { 0, 0 } }; +BossBoundaryData const boundaries = +{ + { DATA_HEIGAN_BOSS, new RectangleBoundary(2723.0f, 2826.0f, -3736.0f, -3641.0f) }, + { 0, 0 } +}; + class instance_naxxramas : public InstanceScript { public: @@ -146,6 +153,7 @@ public: SetPersistentDataCount(PERSISTENT_DATA_COUNT); LoadDoorData(doorData); LoadObjectData(creatureData, gameObjectData); + LoadBossBoundaries(boundaries); // GameObjects for (auto& i : _heiganEruption) diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 4b790f1cc..c28bc2ee4 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -50,13 +50,14 @@ enum NaxxramasData 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_HEIGAN_BOSS = 106, + DATA_BARON_RIVENDARE_BOSS = 107, + DATA_SIR_ZELIEK_BOSS = 108, + DATA_LADY_BLAUMEUX_BOSS = 109, + DATA_THANE_KORTHAZZ_BOSS = 110, + DATA_SAPPHIRON_BOSS = 111, + DATA_KELTHUZAD_BOSS = 112, + DATA_LICH_KING_BOSS = 113, DATA_LOATHEB_PORTAL = 200, DATA_MAEXXNA_PORTAL = 201, @@ -167,6 +168,9 @@ enum NaxxramasCreatureId // Gothik NPC_GOTHIK = 16060, + // Heigan the Unclean + NPC_HEIGAN = 15936, + // Four horseman NPC_BARON_RIVENDARE = 30549, NPC_SIR_ZELIEK = 16063,