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

View File

@@ -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;
};

View File

@@ -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;
};

View File

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