This commit is contained in:
Jelle Meeus
2025-07-13 10:29:10 +02:00
parent e0aebbbd81
commit 01036ef134

View File

@@ -15,45 +15,48 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "CreatureScript.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellScript.h" #include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "naxxramas.h" #include "naxxramas.h"
enum Spells enum Spells
{ {
SPELL_MORTAL_WOUND = 25646, SPELL_MORTAL_WOUND = 25646,
SPELL_ENRAGE = 28371, SPELL_ENRAGE_10 = 28371,
SPELL_DECIMATE = 28374, SPELL_ENRAGE_25 = 54427,
SPELL_DECIMATE_DAMAGE = 28375, SPELL_DECIMATE_10 = 28374,
SPELL_BERSERK = 26662, SPELL_DECIMATE_25 = 54426,
SPELL_INFECTED_WOUND = 29306, SPELL_DECIMATE_DAMAGE = 28375,
SPELL_CHOW_SEARCHER = 28404 SPELL_BERSERK = 26662,
SPELL_INFECTED_WOUND = 29306,
SPELL_CHOW_SEARCHER = 28404
}; };
enum Events enum Events
{ {
EVENT_MORTAL_WOUND = 1, EVENT_MORTAL_WOUND = 1,
EVENT_ENRAGE = 2, EVENT_ENRAGE = 2,
EVENT_DECIMATE = 3, EVENT_DECIMATE = 3,
EVENT_BERSERK = 4, EVENT_BERSERK = 4,
EVENT_SUMMON_ZOMBIE = 5, EVENT_SUMMON_ZOMBIE = 5,
EVENT_CAN_EAT_ZOMBIE = 6 EVENT_CAN_EAT_ZOMBIE = 6
}; };
enum Misc enum Misc
{ {
NPC_ZOMBIE_CHOW = 351069 // NPC_ZOMBIE_CHOW = 16360
}; };
enum Emotes enum Emotes
{ {
EMOTE_SPOTS_ONE = 0, EMOTE_SPOTS_ONE = 0,
EMOTE_DECIMATE = 1, EMOTE_DECIMATE = 1,
EMOTE_ENRAGE = 2, EMOTE_ENRAGE = 2,
EMOTE_DEVOURS_ALL = 3, EMOTE_DEVOURS_ALL = 3,
EMOTE_BERSERK = 4 EMOTE_BERSERK = 4
}; };
const Position zombiePos[3] = const Position zombiePos[3] =
@@ -76,13 +79,10 @@ public:
struct boss_gluth_40AI : public BossAI struct boss_gluth_40AI : public BossAI
{ {
explicit boss_gluth_40AI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me) explicit boss_gluth_40AI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me)
{ {}
pInstance = me->GetInstanceScript();
}
EventMap events; EventMap events;
SummonList summons; SummonList summons;
InstanceScript* pInstance;
void Reset() override void Reset() override
{ {
@@ -113,12 +113,12 @@ public:
{ {
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
me->SetInCombatWithZone(); me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_MORTAL_WOUND, 10000); events.ScheduleEvent(EVENT_MORTAL_WOUND, 10s);
events.ScheduleEvent(EVENT_ENRAGE, 22000); events.ScheduleEvent(EVENT_ENRAGE, 22s);
events.ScheduleEvent(EVENT_DECIMATE, 105000); events.ScheduleEvent(EVENT_DECIMATE, RAID_MODE(110000, 90000, 110000, 90000));
events.ScheduleEvent(EVENT_BERSERK, 360000); events.ScheduleEvent(EVENT_BERSERK, 6min);
events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10000); events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10s);
events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1000); events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1s);
} }
void JustSummoned(Creature* summon) override void JustSummoned(Creature* summon) override
@@ -135,16 +135,13 @@ public:
void KilledUnit(Unit* who) override void KilledUnit(Unit* who) override
{ {
if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW) if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW)
{
me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f)); me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f));
}
if (who->GetTypeId() == TYPEID_PLAYER && pInstance) if (who->IsPlayer())
{ instance->StorePersistentData(PERSISTENT_DATA_IMMORTAL_FAIL, 1);
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
}
} }
void JustDied(Unit* killer) override void JustDied(Unit* killer) override
{ {
BossAI::JustDied(killer); BossAI::JustDied(killer);
summons.DespawnAll(); summons.DespawnAll();
@@ -156,7 +153,7 @@ public:
return false; return false;
Map::PlayerList const& pList = me->GetMap()->GetPlayers(); Map::PlayerList const& pList = me->GetMap()->GetPlayers();
for (const auto& itr : pList) for (auto const& itr : pList)
{ {
Player* player = itr.GetSource(); Player* player = itr.GetSource();
if (!player || !player->IsAlive()) if (!player || !player->IsAlive())
@@ -182,69 +179,78 @@ public:
switch (events.ExecuteEvent()) switch (events.ExecuteEvent())
{ {
case EVENT_BERSERK: case EVENT_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true); me->CastSpell(me, SPELL_BERSERK, true);
break; break;
case EVENT_ENRAGE: case EVENT_ENRAGE:
{
Talk(EMOTE_ENRAGE);
int32 bp1 = 99; // Enrage melee haste
int32 bp2 = 49; // Enrage damage percent
me->CastCustomSpell(me, SPELL_ENRAGE, &bp1, &bp2, 0, true);
events.RepeatEvent(22000);
break;
}
case EVENT_MORTAL_WOUND:
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
events.RepeatEvent(10000);
break;
case EVENT_DECIMATE:
Talk(EMOTE_DECIMATE);
me->CastSpell(me, SPELL_DECIMATE, false);
// Apply Decimate effect to zombies
{ {
std::list<Creature*> zombies; Talk(EMOTE_ENRAGE);
me->GetCreatureListWithEntryInGrid(zombies, NPC_ZOMBIE_CHOW, 150.0f); int32 bp1 = 99; // Enrage melee haste
for (Creature* zombie : zombies) int32 bp2 = 49; // Enrage damage percent
me->CastCustomSpell(me, SPELL_ENRAGE_10, &bp1, &bp2, 0, true);
events.Repeat(22s);
break;
}
case EVENT_MORTAL_WOUND:
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
events.Repeat(10s);
break;
case EVENT_DECIMATE:
Talk(EMOTE_DECIMATE);
me->CastSpell(me, SPELL_DECIMATE_10, false);
// Apply Decimate effect to zombies
// TODO: Is this block required?
{ {
if (zombie->IsAlive()) std::list<Creature*> zombies;
me->GetCreatureListWithEntryInGrid(zombies, NPC_ZOMBIE_CHOW, 150.0f);
for (Creature* zombie : zombies)
{ {
uint32 reduceHp = uint32(zombie->GetMaxHealth() * 0.05f); if (zombie->IsAlive())
if (zombie->GetHealth() > reduceHp) {
zombie->SetHealth(reduceHp); // Reduce HP to 5% uint32 reduceHp = uint32(zombie->GetMaxHealth() * 0.05f);
zombie->SetWalk(true); // Set to walk if (zombie->GetHealth() > reduceHp)
zombie->GetMotionMaster()->MoveFollow(me, 0.0f, 0.0f, MOTION_SLOT_CONTROLLED); // Move to boss zombie->SetHealth(reduceHp); // Reduce HP to 5%
zombie->SetReactState(REACT_PASSIVE); // Set to passive zombie->SetWalk(true); // Set to walk
zombie->GetMotionMaster()->MoveFollow(me,
0.0f,
0.0f,
MOTION_SLOT_CONTROLLED); // Move to boss
zombie->SetReactState(REACT_PASSIVE); // Set to passive
}
} }
} }
} events.RepeatEvent(105000);
events.RepeatEvent(105000); break;
break; case EVENT_SUMMON_ZOMBIE:
case EVENT_SUMMON_ZOMBIE:
{
uint8 rand = urand(0, 2);
for (int32 i = 0; i < 1; ++i)
{
// In 40 man raid, use all gates
me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[urand(0, 2)]);
(rand == 2 ? rand = 0 : rand++);
}
events.RepeatEvent(10000);
break;
}
case EVENT_CAN_EAT_ZOMBIE:
events.RepeatEvent(1000);
if (me->GetVictim() && me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim()))
{
if (me->GetVictim()->GetHealth() > 0) // Check if the zombie is alive
{ {
me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f)); // Heal for 5% of max health uint8 rand = urand(0, 2);
for (int32 i = 0; i < RAID_MODE(1, 2, 2, 2); ++i)
{
// In 10 man raid, normal mode - should spawn only from mid gate
// \1 |0 /2 pos
// In 25 man raid - should spawn from all 3 gates
if (me->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
{
me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[0]);
}
else
{
me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[urand(0, 2)]);
}
(rand == 2 ? rand = 0 : rand++);
}
events.Repeat(10s);
break;
}
case EVENT_CAN_EAT_ZOMBIE:
events.RepeatEvent(1000);
if (me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim()))
{
me->CastCustomSpell(SPELL_CHOW_SEARCHER, SPELLVALUE_RADIUS_MOD, 20000, me, true);
Talk(EMOTE_DEVOURS_ALL); Talk(EMOTE_DEVOURS_ALL);
Unit::DealDamage(me, me->GetVictim(), me->GetVictim()->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); // Kill the zombie
return; // leave it to skip DoMeleeAttackIfReady return; // leave it to skip DoMeleeAttackIfReady
} }
} break;
break;
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }