fix(Scripts/Naxxramas): modernise Heigan (#24234)

This commit is contained in:
Dan
2025-12-29 04:47:02 +01:00
committed by GitHub
parent f1dadadfb9
commit 5dbc6e07ba
3 changed files with 118 additions and 154 deletions

View File

@@ -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<boss_heiganAI>(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);
}

View File

@@ -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)

View File

@@ -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,