mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-18 00:18:43 +01:00
Scripts/Naxxramas: Update Gluth to new model (#26380)
Co-authored-by: offl <offl@users.noreply.github.com>
(cherry picked from commit 44686c3c50)
This commit is contained in:
@@ -89,404 +89,356 @@ enum Misc
|
||||
ACTION_DECIMATE_EVENT = 2,
|
||||
};
|
||||
|
||||
class boss_gluth : public CreatureScript
|
||||
struct boss_gluth : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_gluth() : CreatureScript("boss_gluth") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_gluth(Creature* creature) : BossAI(creature, BOSS_GLUTH), state(STATE_GLUTH_NORMAL) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
return GetNaxxramasAI<boss_gluthAI>(creature);
|
||||
_Reset();
|
||||
zombieToBeEatenGUID.Clear();
|
||||
state = STATE_GLUTH_NORMAL;
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetSpeed(UnitMoveType::MOVE_RUN, 12.0f);
|
||||
}
|
||||
|
||||
struct boss_gluthAI : public BossAI
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_WOUND, 10s);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, randtime(Seconds(16), Seconds(22)));
|
||||
events.ScheduleEvent(EVENT_DECIMATE, randtime(Minutes(1)+Seconds(50), Minutes(2)));
|
||||
events.ScheduleEvent(EVENT_BERSERK, 8min);
|
||||
events.ScheduleEvent(EVENT_SUMMON, 15s);
|
||||
events.ScheduleEvent(EVENT_SEARCH_ZOMBIE_SINGLE, 12s);
|
||||
}
|
||||
|
||||
boss_gluthAI(Creature* creature) : BossAI(creature, BOSS_GLUTH), state(STATE_GLUTH_NORMAL) {}
|
||||
void SummonedCreatureDies(Creature* summoned, Unit* /* who */) override
|
||||
{
|
||||
summons.Despawn(summoned); // needed or else dead zombies not despawned yet will still be in the list
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
_Reset();
|
||||
zombieToBeEatenGUID.Clear();
|
||||
state = STATE_GLUTH_NORMAL;
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetSpeed(UnitMoveType::MOVE_RUN, 12.0f);
|
||||
}
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_WOUND:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(3));
|
||||
break;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_WOUND, 10s);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, randtime(Seconds(16), Seconds(22)));
|
||||
events.ScheduleEvent(EVENT_DECIMATE, randtime(Minutes(1)+Seconds(50), Minutes(2)));
|
||||
events.ScheduleEvent(EVENT_BERSERK, 8min);
|
||||
events.ScheduleEvent(EVENT_SUMMON, 15s);
|
||||
events.ScheduleEvent(EVENT_SEARCH_ZOMBIE_SINGLE, 12s);
|
||||
}
|
||||
DoCastVictim(SPELL_MORTAL_WOUND);
|
||||
events.Repeat(Seconds(10));
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(5));
|
||||
break;
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summoned, Unit* /* who */) override
|
||||
{
|
||||
summons.Despawn(summoned); // needed or else dead zombies not despawned yet will still be in the list
|
||||
}
|
||||
Talk(EMOTE_ENRAGE);
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
events.Repeat(randtime(Seconds(16), Seconds(22)));
|
||||
break;
|
||||
case EVENT_DECIMATE:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(4));
|
||||
break;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
return;
|
||||
Talk(EMOTE_DECIMATE);
|
||||
DoCastAOE(SPELL_DECIMATE);
|
||||
for (int i = 1; i <= 20; i++)
|
||||
events.ScheduleEvent(EVENT_SEARCH_ZOMBIE_MULTI, Seconds(3*i));
|
||||
events.ScheduleEvent(EVENT_DECIMATE, randtime(Minutes(1)+Seconds(50), Minutes(2)));
|
||||
break;
|
||||
case EVENT_BERSERK:
|
||||
Talk(EMOTE_BERSERKER);
|
||||
DoCast(me, SPELL_BERSERK);
|
||||
events.Repeat(Minutes(5)); //refresh the hard enrage buff
|
||||
break;
|
||||
case EVENT_SUMMON:
|
||||
if (Is25ManRaid()) // one wave each 10s. one wave=1 zombie in 10man and 2 zombies in 25man.
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_CHOW_25MAN);
|
||||
else
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_CHOW_10MAN);
|
||||
events.Repeat(Seconds(10));
|
||||
break;
|
||||
case EVENT_SEARCH_ZOMBIE_SINGLE:
|
||||
{
|
||||
Creature* zombie = nullptr;
|
||||
for (SummonList::const_iterator itr = summons.begin(); !zombie && itr != summons.end(); ++itr)
|
||||
{
|
||||
zombie = ObjectAccessor::GetCreature(*me, *itr);
|
||||
if (!zombie || !zombie->IsAlive() || !zombie->IsWithinDistInMap(me, 10.0))
|
||||
zombie = nullptr;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
if (zombie)
|
||||
{
|
||||
zombieToBeEatenGUID = zombie->GetGUID(); // save for later use
|
||||
|
||||
// the soon-to-be-eaten zombie should stop moving and stop attacking
|
||||
zombie->AI()->SetData(DATA_ZOMBIE_STATE, STATE_ZOMBIE_TOBE_EATEN);
|
||||
|
||||
// gluth should stop AAs on his primary target and turn toward the zombie (2 yards away). He then pauses for a few seconds.
|
||||
me->SetSpeed(MOVE_RUN, 36.0f);
|
||||
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
|
||||
Talk(EMOTE_SPOTS_ONE);
|
||||
|
||||
//me->SetTarget(ObjectGuid::Empty);
|
||||
|
||||
me->GetMotionMaster()->MoveCloserAndStop(1, zombie, 2.0f);
|
||||
|
||||
state = STATE_GLUTH_EATING;
|
||||
}
|
||||
|
||||
events.Repeat(RAID_MODE(Seconds(7), Seconds(5)));
|
||||
break;
|
||||
}
|
||||
case EVENT_KILL_ZOMBIE_SINGLE:
|
||||
{
|
||||
Creature* zombieToBeEaten = ObjectAccessor::GetCreature(*me, zombieToBeEatenGUID);
|
||||
if (zombieToBeEaten && zombieToBeEaten->IsAlive() && zombieToBeEaten->IsWithinDistInMap(me, 10.0))
|
||||
DoCast(zombieToBeEaten, SPELL_ZOMBIE_CHOW_SEARCH_SINGLE); // do the killing + healing in done inside by spell script see below.
|
||||
|
||||
zombieToBeEatenGUID = ObjectGuid::Empty;
|
||||
state = STATE_GLUTH_NORMAL;
|
||||
me->SetSpeed(UnitMoveType::MOVE_RUN, 12.0f);
|
||||
|
||||
// and then return on primary target
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
break;
|
||||
}
|
||||
case EVENT_SEARCH_ZOMBIE_MULTI:
|
||||
{
|
||||
if (state == STATE_GLUTH_EATING) // skip and simply wait for the next occurence
|
||||
break;
|
||||
|
||||
Creature* zombie = nullptr;
|
||||
for (SummonList::const_iterator itr = summons.begin(); !zombie && itr != summons.end(); ++itr)
|
||||
{
|
||||
zombie = ObjectAccessor::GetCreature(*me, *itr);
|
||||
if (zombie && zombie->IsAlive() && zombie->GetExactDist2d(me) > 18.0)
|
||||
zombie = nullptr;
|
||||
}
|
||||
|
||||
if (zombie) // cast the aoe spell only if at least one zombie is found nearby
|
||||
{
|
||||
Talk(EMOTE_DEVOURS_ALL);
|
||||
DoCastAOE(SPELL_ZOMBIE_CHOW_SEARCH_MULTI);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 /*type*/, uint32 id) override
|
||||
{
|
||||
if (id == 1){
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
events.ScheduleEvent(EVENT_KILL_ZOMBIE_SINGLE, 1s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_DECIMATE_EVENT:
|
||||
for (ObjectGuid zombieGuid : summons)
|
||||
{
|
||||
case EVENT_WOUND:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(3));
|
||||
break;
|
||||
}
|
||||
|
||||
DoCastVictim(SPELL_MORTAL_WOUND);
|
||||
events.Repeat(Seconds(10));
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(5));
|
||||
break;
|
||||
}
|
||||
|
||||
Talk(EMOTE_ENRAGE);
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
events.Repeat(randtime(Seconds(16), Seconds(22)));
|
||||
break;
|
||||
case EVENT_DECIMATE:
|
||||
if (state == STATE_GLUTH_EATING)
|
||||
{
|
||||
events.Repeat(Seconds(4));
|
||||
break;
|
||||
}
|
||||
|
||||
Talk(EMOTE_DECIMATE);
|
||||
DoCastAOE(SPELL_DECIMATE);
|
||||
for (int i = 1; i <= 20; i++)
|
||||
events.ScheduleEvent(EVENT_SEARCH_ZOMBIE_MULTI, Seconds(3*i));
|
||||
events.ScheduleEvent(EVENT_DECIMATE, randtime(Minutes(1)+Seconds(50), Minutes(2)));
|
||||
break;
|
||||
case EVENT_BERSERK:
|
||||
Talk(EMOTE_BERSERKER);
|
||||
DoCast(me, SPELL_BERSERK);
|
||||
events.Repeat(Minutes(5)); //refresh the hard enrage buff
|
||||
break;
|
||||
case EVENT_SUMMON:
|
||||
if (Is25ManRaid()) // one wave each 10s. one wave=1 zombie in 10man and 2 zombies in 25man.
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_CHOW_25MAN);
|
||||
else
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_CHOW_10MAN);
|
||||
events.Repeat(Seconds(10));
|
||||
break;
|
||||
case EVENT_SEARCH_ZOMBIE_SINGLE:
|
||||
{
|
||||
Creature* zombie = nullptr;
|
||||
for (SummonList::const_iterator itr = summons.begin(); !zombie && itr != summons.end(); ++itr)
|
||||
{
|
||||
zombie = ObjectAccessor::GetCreature(*me, *itr);
|
||||
if (!zombie || !zombie->IsAlive() || !zombie->IsWithinDistInMap(me, 10.0))
|
||||
zombie = nullptr;
|
||||
}
|
||||
|
||||
if (zombie)
|
||||
{
|
||||
zombieToBeEatenGUID = zombie->GetGUID(); // save for later use
|
||||
|
||||
// the soon-to-be-eaten zombie should stop moving and stop attacking
|
||||
zombie->AI()->SetData(DATA_ZOMBIE_STATE, STATE_ZOMBIE_TOBE_EATEN);
|
||||
|
||||
// gluth should stop AAs on his primary target and turn toward the zombie (2 yards away). He then pauses for a few seconds.
|
||||
me->SetSpeed(MOVE_RUN, 36.0f);
|
||||
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
|
||||
Talk(EMOTE_SPOTS_ONE);
|
||||
|
||||
//me->SetTarget(ObjectGuid::Empty);
|
||||
|
||||
me->GetMotionMaster()->MoveCloserAndStop(1, zombie, 2.0f);
|
||||
|
||||
state = STATE_GLUTH_EATING;
|
||||
}
|
||||
|
||||
events.Repeat(RAID_MODE(Seconds(7), Seconds(5)));
|
||||
break;
|
||||
}
|
||||
case EVENT_KILL_ZOMBIE_SINGLE:
|
||||
{
|
||||
Creature* zombieToBeEaten = ObjectAccessor::GetCreature(*me, zombieToBeEatenGUID);
|
||||
if (zombieToBeEaten && zombieToBeEaten->IsAlive() && zombieToBeEaten->IsWithinDistInMap(me, 10.0))
|
||||
DoCast(zombieToBeEaten, SPELL_ZOMBIE_CHOW_SEARCH_SINGLE); // do the killing + healing in done inside by spell script see below.
|
||||
|
||||
zombieToBeEatenGUID = ObjectGuid::Empty;
|
||||
state = STATE_GLUTH_NORMAL;
|
||||
me->SetSpeed(UnitMoveType::MOVE_RUN, 12.0f);
|
||||
|
||||
// and then return on primary target
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
break;
|
||||
}
|
||||
case EVENT_SEARCH_ZOMBIE_MULTI:
|
||||
{
|
||||
if (state == STATE_GLUTH_EATING) // skip and simply wait for the next occurence
|
||||
break;
|
||||
|
||||
Creature* zombie = nullptr;
|
||||
for (SummonList::const_iterator itr = summons.begin(); !zombie && itr != summons.end(); ++itr)
|
||||
{
|
||||
zombie = ObjectAccessor::GetCreature(*me, *itr);
|
||||
if (zombie && zombie->IsAlive() && zombie->GetExactDist2d(me) > 18.0)
|
||||
zombie = nullptr;
|
||||
}
|
||||
|
||||
if (zombie) // cast the aoe spell only if at least one zombie is found nearby
|
||||
{
|
||||
Talk(EMOTE_DEVOURS_ALL);
|
||||
DoCastAOE(SPELL_ZOMBIE_CHOW_SEARCH_MULTI);
|
||||
}
|
||||
break;
|
||||
}
|
||||
Creature* zombie = ObjectAccessor::GetCreature(*me, zombieGuid);
|
||||
if (zombie && zombie->IsAlive())
|
||||
zombie->AI()->SetData(DATA_ZOMBIE_STATE, STATE_ZOMBIE_DECIMATED);
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 /*type*/, uint32 id) override
|
||||
{
|
||||
if (id == 1){
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
events.ScheduleEvent(EVENT_KILL_ZOMBIE_SINGLE, 1s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_DECIMATE_EVENT:
|
||||
for (ObjectGuid zombieGuid : summons)
|
||||
{
|
||||
Creature* zombie = ObjectAccessor::GetCreature(*me, zombieGuid);
|
||||
if (zombie && zombie->IsAlive())
|
||||
zombie->AI()->SetData(DATA_ZOMBIE_STATE, STATE_ZOMBIE_DECIMATED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid zombieToBeEatenGUID;
|
||||
uint8 state;
|
||||
};
|
||||
|
||||
private:
|
||||
ObjectGuid zombieToBeEatenGUID;
|
||||
uint8 state;
|
||||
};
|
||||
|
||||
// spell 28374 (10man) / 54426 (25man) - Decimate
|
||||
class spell_gluth_decimate : public SpellScriptLoader
|
||||
class spell_gluth_decimate : public SpellScript
|
||||
{
|
||||
public:
|
||||
spell_gluth_decimate() : SpellScriptLoader("spell_gluth_decimate") { }
|
||||
PrepareSpellScript(spell_gluth_decimate);
|
||||
|
||||
class spell_gluth_decimate_SpellScript : public SpellScript
|
||||
// handles the damaging effect of the decimate spell.
|
||||
void HandleScriptEffect(SpellEffIndex /* index */)
|
||||
{
|
||||
PrepareSpellScript(spell_gluth_decimate_SpellScript);
|
||||
|
||||
// handles the damaging effect of the decimate spell.
|
||||
void HandleScriptEffect(SpellEffIndex /* index */)
|
||||
if (Unit *unit = GetHitUnit())
|
||||
{
|
||||
if (Unit *unit = GetHitUnit())
|
||||
int32 damage = int32(unit->GetHealth()) - int32(unit->CountPctFromMaxHealth(5));
|
||||
if (damage > 0)
|
||||
{
|
||||
int32 damage = int32(unit->GetHealth()) - int32(unit->CountPctFromMaxHealth(5));
|
||||
if (damage > 0)
|
||||
{
|
||||
CastSpellExtraArgs args(TRIGGERED_FULL_MASK);
|
||||
args.AddSpellBP0(damage);
|
||||
GetCaster()->CastSpell(unit, SPELL_DECIMATE_DMG, args);
|
||||
}
|
||||
CastSpellExtraArgs args(TRIGGERED_FULL_MASK);
|
||||
args.AddSpellBP0(damage);
|
||||
GetCaster()->CastSpell(unit, SPELL_DECIMATE_DMG, args);
|
||||
}
|
||||
}
|
||||
|
||||
// handles the change of zombies behavior after the decimate spell
|
||||
void HandleEvent(SpellEffIndex /* index */)
|
||||
{
|
||||
GetCaster()->GetAI()->DoAction(ACTION_DECIMATE_EVENT);
|
||||
}
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_DECIMATE_DMG });
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
OnEffectHit += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleEvent, EFFECT_2, SPELL_EFFECT_SEND_EVENT);
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster() && GetCaster()->GetEntry() == NPC_GLUTH;
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_gluth_decimate_SpellScript();
|
||||
}
|
||||
|
||||
// handles the change of zombies behavior after the decimate spell
|
||||
void HandleEvent(SpellEffIndex /* index */)
|
||||
{
|
||||
GetCaster()->GetAI()->DoAction(ACTION_DECIMATE_EVENT);
|
||||
}
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_DECIMATE_DMG });
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
OnEffectHit += SpellEffectFn(spell_gluth_decimate::HandleEvent, EFFECT_2, SPELL_EFFECT_SEND_EVENT);
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster() && GetCaster()->GetEntry() == NPC_GLUTH;
|
||||
}
|
||||
};
|
||||
|
||||
// used by both 28239 & 28404 (single target and aoe zombie-kill spell) to heal Gluth on each target hit.
|
||||
|
||||
class spell_gluth_zombiechow_search : public SpellScriptLoader
|
||||
class spell_gluth_zombiechow_search : public SpellScript
|
||||
{
|
||||
public:
|
||||
spell_gluth_zombiechow_search() : SpellScriptLoader("spell_gluth_zombiechow_search") { }
|
||||
PrepareSpellScript(spell_gluth_zombiechow_search);
|
||||
|
||||
class spell_gluth_zombiechow_search_SpellScript : public SpellScript
|
||||
void HealForEachTargetHit()
|
||||
{
|
||||
PrepareSpellScript(spell_gluth_zombiechow_search_SpellScript);
|
||||
|
||||
void HealForEachTargetHit()
|
||||
{
|
||||
GetCaster()->ModifyHealth(int32(GetCaster()->CountPctFromMaxHealth(5)));
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterHit += SpellHitFn(spell_gluth_zombiechow_search_SpellScript::HealForEachTargetHit);
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster() && GetCaster()->GetEntry() == NPC_GLUTH;
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const
|
||||
{
|
||||
return new spell_gluth_zombiechow_search_SpellScript();
|
||||
GetCaster()->ModifyHealth(int32(GetCaster()->CountPctFromMaxHealth(5)));
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterHit += SpellHitFn(spell_gluth_zombiechow_search::HealForEachTargetHit);
|
||||
}
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster() && GetCaster()->GetEntry() == NPC_GLUTH;
|
||||
}
|
||||
};
|
||||
|
||||
// creature 16360 (10man) / 30303 (25man)
|
||||
class npc_zombie_chow : public CreatureScript
|
||||
struct npc_zombie_chow : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
|
||||
npc_zombie_chow() : CreatureScript("npc_zombie_chow") { }
|
||||
|
||||
struct npc_zombie_chowAI : public ScriptedAI
|
||||
npc_zombie_chow(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
npc_zombie_chowAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
GluthGUID = creature->GetInstanceScript()->GetGuidData(DATA_GLUTH);
|
||||
GluthGUID = creature->GetInstanceScript()->GetGuidData(DATA_GLUTH);
|
||||
|
||||
DoCast(me, SPELL_INFECTED_WOUND);
|
||||
timer = 0;
|
||||
state = STATE_ZOMBIE_NORMAL;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (state == STATE_ZOMBIE_DECIMATED)
|
||||
{
|
||||
timer += diff;
|
||||
if (Creature* gluth = ObjectAccessor::GetCreature(*me, GluthGUID))
|
||||
{
|
||||
// Putting this in the UpdateAI loop fixes an issue where death gripping a decimated zombie would make the zombie stand still until the rest of the fight.
|
||||
// Also fix the issue where if one or more zombie is rooted when decimates hits (and MovePoint() is called), the zombie teleport to the boss. pretty weird behavior.
|
||||
if (timer > 1600 && me->GetExactDist2d(gluth) > 10.0f && me->CanFreeMove()) // it takes about 1600 ms for the animation to cycle. This way, the animation looks relatively smooth.
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(0, gluth->GetPosition()); // isn't dynamic. So, to take into account Gluth's movement, it must be called periodicly.
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
if (me->GetExactDist2d(gluth) <= 10.0f)
|
||||
me->StopMoving();
|
||||
}
|
||||
}
|
||||
else if (state == STATE_ZOMBIE_NORMAL)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void SetData(uint32 id, uint32 value) override
|
||||
{
|
||||
if (id == DATA_ZOMBIE_STATE) // change of state
|
||||
{
|
||||
state = value;
|
||||
if (value == STATE_ZOMBIE_DECIMATED)
|
||||
{
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
// at this point, the zombie should be non attacking and non moving.
|
||||
|
||||
me->SetWalk(true); // it doesnt seem to work with MoveFollow() (but it does work with MovePoint()).
|
||||
|
||||
timer = 1000;
|
||||
}
|
||||
else if (value == STATE_ZOMBIE_TOBE_EATEN)
|
||||
{
|
||||
// forced to stand still
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->StopMoving();
|
||||
|
||||
// and loose aggro behavior
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true); // not sure if this is blizz-like but this is very convenient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 index) const override
|
||||
{
|
||||
if (index == DATA_ZOMBIE_STATE)
|
||||
return state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 timer;
|
||||
uint8 state;
|
||||
ObjectGuid GluthGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetNaxxramasAI<npc_zombie_chowAI>(creature);
|
||||
DoCast(me, SPELL_INFECTED_WOUND);
|
||||
timer = 0;
|
||||
state = STATE_ZOMBIE_NORMAL;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (state == STATE_ZOMBIE_DECIMATED)
|
||||
{
|
||||
timer += diff;
|
||||
if (Creature* gluth = ObjectAccessor::GetCreature(*me, GluthGUID))
|
||||
{
|
||||
// Putting this in the UpdateAI loop fixes an issue where death gripping a decimated zombie would make the zombie stand still until the rest of the fight.
|
||||
// Also fix the issue where if one or more zombie is rooted when decimates hits (and MovePoint() is called), the zombie teleport to the boss. pretty weird behavior.
|
||||
if (timer > 1600 && me->GetExactDist2d(gluth) > 10.0f && me->CanFreeMove()) // it takes about 1600 ms for the animation to cycle. This way, the animation looks relatively smooth.
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(0, gluth->GetPosition()); // isn't dynamic. So, to take into account Gluth's movement, it must be called periodicly.
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
if (me->GetExactDist2d(gluth) <= 10.0f)
|
||||
me->StopMoving();
|
||||
}
|
||||
}
|
||||
else if (state == STATE_ZOMBIE_NORMAL)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void SetData(uint32 id, uint32 value) override
|
||||
{
|
||||
if (id == DATA_ZOMBIE_STATE) // change of state
|
||||
{
|
||||
state = value;
|
||||
if (value == STATE_ZOMBIE_DECIMATED)
|
||||
{
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
// at this point, the zombie should be non attacking and non moving.
|
||||
|
||||
me->SetWalk(true); // it doesnt seem to work with MoveFollow() (but it does work with MovePoint()).
|
||||
|
||||
timer = 1000;
|
||||
}
|
||||
else if (value == STATE_ZOMBIE_TOBE_EATEN)
|
||||
{
|
||||
// forced to stand still
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->StopMoving();
|
||||
|
||||
// and loose aggro behavior
|
||||
me->SetReactState(ReactStates::REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
me->SetTarget(ObjectGuid::Empty);
|
||||
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true); // not sure if this is blizz-like but this is very convenient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 index) const override
|
||||
{
|
||||
if (index == DATA_ZOMBIE_STATE)
|
||||
return state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 timer;
|
||||
uint8 state;
|
||||
ObjectGuid GluthGUID;
|
||||
};
|
||||
|
||||
void AddSC_boss_gluth()
|
||||
{
|
||||
new boss_gluth();
|
||||
new spell_gluth_decimate();
|
||||
new spell_gluth_zombiechow_search();
|
||||
new npc_zombie_chow();
|
||||
RegisterNaxxramasCreatureAI(boss_gluth);
|
||||
RegisterSpellScript(spell_gluth_decimate);
|
||||
RegisterSpellScript(spell_gluth_zombiechow_search);
|
||||
RegisterNaxxramasCreatureAI(npc_zombie_chow);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user