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
};
enum Actions
{
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1,
ACTION_BANISH_SELF = 2
};
struct boss_magtheridon : public BossAI
{
boss_magtheridon(Creature* creature) : BossAI(creature, DATA_MAGTHERIDON)
@@ -84,7 +78,6 @@ struct boss_magtheridon : public BossAI
void Reset() override
{
BossAI::Reset();
_channelersKilled = 0;
_currentPhase = 0;
_castingQuake = false;
_recentlySpoken = false;
@@ -194,21 +187,19 @@ struct boss_magtheridon : public BossAI
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);
Talk(SAY_FREE);
scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown
_magReleased = true;
scheduler.Schedule(3s, [this](TaskContext)
{
ScheduleCombatEvents();
});
}
ScheduleCombatEvents();
});
}
else if (action == ACTION_BANISH_SELF)
{
@@ -222,10 +213,6 @@ struct boss_magtheridon : public BossAI
BossAI::JustEngagedWith(who);
Talk(SAY_EMOTE_BEGIN);
instance->DoForAllMinions(DATA_MAGTHERIDON, [&](Creature* creature) {
creature->SetInCombatWithZone();
});
scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
Talk(SAY_EMOTE_NEARLY);
@@ -260,7 +247,6 @@ private:
bool _recentlySpoken;
bool _magReleased;
uint8 _currentPhase;
uint8 _channelersKilled;
TaskScheduler _interruptScheduler;
};
@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureAI.h"
#include "InstanceMapScript.h"
#include "InstanceScript.h"
#include "magtheridons_lair.h"
@@ -30,12 +31,6 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM } // END
};
MinionData const minionData[] =
{
{ NPC_HELLFIRE_CHANNELER, DATA_MAGTHERIDON },
{ 0, 0 } // END
};
class instance_magtheridons_lair : public InstanceMapScript
{
public:
@@ -48,17 +43,28 @@ public:
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER);
LoadDoorData(doorData);
LoadMinionData(minionData);
LoadBossBoundaries(boundaries);
}
void Initialize() override
{
_channelersSet.clear();
_wardersSet.clear();
_burningAbyssalsSet.clear();
_cubesSet.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
{
switch (creature->GetEntry())
@@ -67,22 +73,42 @@ public:
_magtheridonGUID = creature->GetGUID();
break;
case NPC_HELLFIRE_CHANNELER:
AddMinion(creature);
_channelersSet.insert(creature->GetGUID());
break;
case NPC_HELLFIRE_WARDER:
_wardersSet.insert(creature->GetGUID());
break;
case NPC_BURNING_ABYSSAL:
_burningAbyssalsSet.insert(creature->GetGUID());
break;
}
}
void OnCreatureRemove(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_HELLFIRE_CHANNELER:
RemoveMinion(creature);
break;
}
if (creature->GetEntry() == NPC_BURNING_ABYSSAL)
_burningAbyssalsSet.erase(creature->GetGUID());
}
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
@@ -154,6 +180,18 @@ public:
if (state == NOT_STARTED)
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;
@@ -164,9 +202,13 @@ public:
switch (type)
{
case DATA_CHANNELER_COMBAT:
// Force the encounter start: Mag is ImmuneToPC so SetInCombatWithZone alone may miss JustEngagedWith.
if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS)
{
SetBossState(DATA_MAGTHERIDON, IN_PROGRESS);
if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID))
magtheridon->SetInCombatWithZone();
}
break;
case DATA_ACTIVATE_CUBES:
for (ObjectGuid const& guid : _cubesSet)
@@ -178,12 +220,16 @@ public:
if (GameObject* column = instance->GetGameObject(guid))
column->SetGoState(GOState(data));
break;
default:
break;
}
}
private:
ObjectGuid _magtheridonGUID;
GuidSet _channelersSet;
GuidSet _wardersSet;
GuidSet _burningAbyssalsSet;
GuidSet _cubesSet;
GuidSet _columnSet;
};
@@ -39,7 +39,14 @@ enum NpcIds
NPC_HELLFIRE_CHANNELER = 17256,
NPC_HELLFIRE_WARDER = 18829,
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