fix(Scripts/MagtheridonsLair): prevent Hellfire Channelers from respawning during boss fight (#25603)

Co-authored-by: sogla <sogladev@gmail.com>
This commit is contained in:
Florent
2026-05-30 13:08:38 +02:00
committed by GitHub
parent e675151983
commit f7019beda4
4 changed files with 91 additions and 39 deletions
@@ -0,0 +1,13 @@
-- Hellfire Channelers formation: groupAI = 3 (MEMBER_ASSIST_LEADER | LEADER_ASSIST_MEMBER), pack-aggro only. Wipe handling lives in the instance script's hard reset.
DELETE FROM `creature_formations` WHERE `leaderGUID`=90978;
INSERT INTO `creature_formations`
(`leaderGUID`,`memberGUID`,`dist`,`angle`,`groupAI`,`point_1`,`point_2`)
VALUES
(90978, 90978, 0, 0, 3, 0, 0),
(90978, 90979, 0, 0, 3, 0, 0),
(90978, 90980, 0, 0, 3, 0, 0),
(90978, 90981, 0, 0, 3, 0, 0),
(90978, 90982, 0, 0, 3, 0, 0);
-- Hellfire Channeler SAI: drop id=6. Death tracking moved to the instance script (OnUnitDeath).
DELETE FROM `smart_scripts` WHERE `entryorguid`=17256 AND `source_type`=0 AND `id`=6;
@@ -70,12 +70,6 @@ enum Groups
GROUP_EARLY_RELEASE_CHECK = 0 GROUP_EARLY_RELEASE_CHECK = 0
}; };
enum Actions
{
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1,
ACTION_BANISH_SELF = 2
};
struct boss_magtheridon : public BossAI struct boss_magtheridon : public BossAI
{ {
boss_magtheridon(Creature* creature) : BossAI(creature, DATA_MAGTHERIDON) boss_magtheridon(Creature* creature) : BossAI(creature, DATA_MAGTHERIDON)
@@ -84,7 +78,6 @@ struct boss_magtheridon : public BossAI
void Reset() override void Reset() override
{ {
BossAI::Reset(); BossAI::Reset();
_channelersKilled = 0;
_currentPhase = 0; _currentPhase = 0;
_castingQuake = false; _castingQuake = false;
_recentlySpoken = false; _recentlySpoken = false;
@@ -194,21 +187,19 @@ struct boss_magtheridon : public BossAI
void DoAction(int32 action) override void DoAction(int32 action) override
{ {
if (action == ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT) if (action == ACTION_RELEASE_MAGTHERIDON)
{ {
_channelersKilled++; if (_magReleased)
return;
if (_channelersKilled >= 5 && !_magReleased) Talk(SAY_EMOTE_FREE);
Talk(SAY_FREE);
scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown
_magReleased = true;
scheduler.Schedule(3s, [this](TaskContext)
{ {
Talk(SAY_EMOTE_FREE); ScheduleCombatEvents();
Talk(SAY_FREE); });
scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown
_magReleased = true;
scheduler.Schedule(3s, [this](TaskContext)
{
ScheduleCombatEvents();
});
}
} }
else if (action == ACTION_BANISH_SELF) else if (action == ACTION_BANISH_SELF)
{ {
@@ -222,10 +213,6 @@ struct boss_magtheridon : public BossAI
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
Talk(SAY_EMOTE_BEGIN); Talk(SAY_EMOTE_BEGIN);
instance->DoForAllMinions(DATA_MAGTHERIDON, [&](Creature* creature) {
creature->SetInCombatWithZone();
});
scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/) scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{ {
Talk(SAY_EMOTE_NEARLY); Talk(SAY_EMOTE_NEARLY);
@@ -260,7 +247,6 @@ private:
bool _recentlySpoken; bool _recentlySpoken;
bool _magReleased; bool _magReleased;
uint8 _currentPhase; uint8 _currentPhase;
uint8 _channelersKilled;
TaskScheduler _interruptScheduler; TaskScheduler _interruptScheduler;
}; };
@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "CreatureAI.h"
#include "InstanceMapScript.h" #include "InstanceMapScript.h"
#include "InstanceScript.h" #include "InstanceScript.h"
#include "magtheridons_lair.h" #include "magtheridons_lair.h"
@@ -30,12 +31,6 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM } // END { 0, 0, DOOR_TYPE_ROOM } // END
}; };
MinionData const minionData[] =
{
{ NPC_HELLFIRE_CHANNELER, DATA_MAGTHERIDON },
{ 0, 0 } // END
};
class instance_magtheridons_lair : public InstanceMapScript class instance_magtheridons_lair : public InstanceMapScript
{ {
public: public:
@@ -48,17 +43,28 @@ public:
SetHeaders(DataHeader); SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER); SetBossNumber(MAX_ENCOUNTER);
LoadDoorData(doorData); LoadDoorData(doorData);
LoadMinionData(minionData);
LoadBossBoundaries(boundaries); LoadBossBoundaries(boundaries);
} }
void Initialize() override void Initialize() override
{ {
_channelersSet.clear();
_wardersSet.clear(); _wardersSet.clear();
_burningAbyssalsSet.clear();
_cubesSet.clear(); _cubesSet.clear();
_columnSet.clear(); _columnSet.clear();
} }
bool IsAnyChannelerAlive()
{
return std::ranges::any_of(_channelersSet, [&](ObjectGuid const& guid)
{
if (Creature* channeler = instance->GetCreature(guid))
return channeler->IsAlive();
return false;
});
}
void OnCreatureCreate(Creature* creature) override void OnCreatureCreate(Creature* creature) override
{ {
switch (creature->GetEntry()) switch (creature->GetEntry())
@@ -67,22 +73,42 @@ public:
_magtheridonGUID = creature->GetGUID(); _magtheridonGUID = creature->GetGUID();
break; break;
case NPC_HELLFIRE_CHANNELER: case NPC_HELLFIRE_CHANNELER:
AddMinion(creature); _channelersSet.insert(creature->GetGUID());
break; break;
case NPC_HELLFIRE_WARDER: case NPC_HELLFIRE_WARDER:
_wardersSet.insert(creature->GetGUID()); _wardersSet.insert(creature->GetGUID());
break; break;
case NPC_BURNING_ABYSSAL:
_burningAbyssalsSet.insert(creature->GetGUID());
break;
} }
} }
void OnCreatureRemove(Creature* creature) override void OnCreatureRemove(Creature* creature) override
{ {
switch (creature->GetEntry()) if (creature->GetEntry() == NPC_BURNING_ABYSSAL)
{ _burningAbyssalsSet.erase(creature->GetGUID());
case NPC_HELLFIRE_CHANNELER: }
RemoveMinion(creature);
break; void OnUnitDeath(Unit* unit) override
} {
Creature* creature = unit ? unit->ToCreature() : nullptr;
if (!creature || creature->GetEntry() != NPC_HELLFIRE_CHANNELER)
return;
// IN_PROGRESS guard: stays inert during the hard-reset Respawn(true) cycle.
if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS || IsAnyChannelerAlive())
return;
if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID))
magtheridon->AI()->DoAction(ACTION_RELEASE_MAGTHERIDON);
}
void OnCreatureEvade(Creature* creature) override
{
// Phase-1 wipe signal: Mag is ImmuneToPC so BossAI evade does not fire; a Channeler evade is the trigger.
if (creature->GetEntry() == NPC_HELLFIRE_CHANNELER && GetBossState(DATA_MAGTHERIDON) == IN_PROGRESS)
SetBossState(DATA_MAGTHERIDON, NOT_STARTED);
} }
void OnGameObjectCreate(GameObject* go) override void OnGameObjectCreate(GameObject* go) override
@@ -154,6 +180,18 @@ public:
if (state == NOT_STARTED) if (state == NOT_STARTED)
SetData(DATA_COLLAPSE, GO_READY); SetData(DATA_COLLAPSE, GO_READY);
// Hard reset: vanish Channelers and their lingering Burning Abyssal summons.
if (state == NOT_STARTED || state == FAIL)
{
for (ObjectGuid const& guid : _channelersSet)
if (Creature* channeler = instance->GetCreature(guid))
channeler->Respawn(true);
for (ObjectGuid const& guid : _burningAbyssalsSet)
if (Creature* abyssal = instance->GetCreature(guid))
abyssal->DespawnOrUnsummon();
}
} }
} }
return true; return true;
@@ -164,9 +202,13 @@ public:
switch (type) switch (type)
{ {
case DATA_CHANNELER_COMBAT: case DATA_CHANNELER_COMBAT:
// Force the encounter start: Mag is ImmuneToPC so SetInCombatWithZone alone may miss JustEngagedWith.
if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS) if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS)
{
SetBossState(DATA_MAGTHERIDON, IN_PROGRESS);
if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID)) if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID))
magtheridon->SetInCombatWithZone(); magtheridon->SetInCombatWithZone();
}
break; break;
case DATA_ACTIVATE_CUBES: case DATA_ACTIVATE_CUBES:
for (ObjectGuid const& guid : _cubesSet) for (ObjectGuid const& guid : _cubesSet)
@@ -178,12 +220,16 @@ public:
if (GameObject* column = instance->GetGameObject(guid)) if (GameObject* column = instance->GetGameObject(guid))
column->SetGoState(GOState(data)); column->SetGoState(GOState(data));
break; break;
default:
break;
} }
} }
private: private:
ObjectGuid _magtheridonGUID; ObjectGuid _magtheridonGUID;
GuidSet _channelersSet;
GuidSet _wardersSet; GuidSet _wardersSet;
GuidSet _burningAbyssalsSet;
GuidSet _cubesSet; GuidSet _cubesSet;
GuidSet _columnSet; GuidSet _columnSet;
}; };
@@ -39,7 +39,14 @@ enum NpcIds
NPC_HELLFIRE_CHANNELER = 17256, NPC_HELLFIRE_CHANNELER = 17256,
NPC_HELLFIRE_WARDER = 18829, NPC_HELLFIRE_WARDER = 18829,
NPC_HELLFIRE_RAID_TRIGGER = 17376, NPC_HELLFIRE_RAID_TRIGGER = 17376,
NPC_TARGET_TRIGGER = 17474 NPC_TARGET_TRIGGER = 17474,
NPC_BURNING_ABYSSAL = 17454
};
enum MagtheridonActions
{
ACTION_RELEASE_MAGTHERIDON = 1,
ACTION_BANISH_SELF = 2
}; };
enum GoIds enum GoIds