(Scripts/AI) ZG20: Improvements to Thekal (Tiger Boss) (#17603)

Co-authored-by: AG <43139552+AGandrup@users.noreply.github.com>
This commit is contained in:
KJack
2023-11-11 02:13:43 -05:00
committed by GitHub
parent f7fdc7cb6c
commit 896e7c5656
3 changed files with 459 additions and 370 deletions

View File

@@ -15,6 +15,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SharedDefines.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
@@ -22,36 +23,40 @@
enum Says
{
SAY_AGGRO = 0,
SAY_DEATH = 1,
SAY_AGGRO = 0,
SAY_DEATH = 1,
EMOTE_DIES = 2,
EMOTE_ZEALOT_DIES = 0,
EMOTE_THEKAL_DIES = 2
EMOTE_ZEALOT_DIES = 0
};
enum Spells
{
SPELL_MORTALCLEAVE = 22859,
SPELL_SILENCE = 22666,
SPELL_TIGER_FORM = 24169,
SPELL_RESURRECT = 24173,
SPELL_FRENZY = 8269,
SPELL_FORCEPUNCH = 24189,
SPELL_CHARGE = 24193,
SPELL_ENRAGE = 8269,
SPELL_SUMMONTIGERS = 24183,
// Boss - pre-fight
SPELL_SUMMONTIGERS = 24183,
// Boss
SPELL_CHARGE = 24193,
SPELL_ENRAGE = 8269,
SPELL_FORCEPUNCH = 24189,
SPELL_FRENZY = 8269,
SPELL_MORTALCLEAVE = 22859,
SPELL_RESURRECTION_IMPACT_VISUAL = 24171,
SPELL_SILENCE = 22666,
SPELL_TIGER_FORM = 24169,
// Zealot Lor'Khan Spells
SPELL_SHIELD = 20545,
SPELL_BLOODLUST = 24185,
SPELL_GREATERHEAL = 24208,
SPELL_DISARM = 6713,
SPELL_SHIELD = 20545,
SPELL_BLOODLUST = 24185,
SPELL_GREATERHEAL = 24208,
SPELL_DISARM = 6713,
// Zealot Zath Spells
SPELL_SWEEPINGSTRIKES = 18765,
SPELL_SINISTERSTRIKE = 15581,
SPELL_GOUGE = 12540,
SPELL_KICK = 15614,
SPELL_BLIND = 21060
SPELL_SWEEPINGSTRIKES = 18765,
SPELL_SINISTERSTRIKE = 15581,
SPELL_GOUGE = 12540,
SPELL_KICK = 15614,
SPELL_BLIND = 21060
};
enum Actions
@@ -59,399 +64,466 @@ enum Actions
ACTION_RESSURRECT = 1
};
class boss_thekal : public CreatureScript
struct boss_thekal : public BossAI
{
public:
boss_thekal() : CreatureScript("boss_thekal") { }
struct boss_thekalAI : public BossAI
boss_thekal(Creature* creature) : BossAI(creature, DATA_THEKAL)
{
boss_thekalAI(Creature* creature) : BossAI(creature, DATA_THEKAL)
Initialize();
}
void Initialize()
{
_enraged = false;
_wasDead = false;
_lorkhanDied = false;
_zathDied = false;
}
void Reset() override
{
_Reset();
Initialize();
scheduler.CancelAll();
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveAurasDueToSpell(SPELL_FRENZY);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->LoadEquipment(1, true);
if (Creature* zealot = instance->GetCreature(DATA_LORKHAN))
{
Initialize();
zealot->AI()->Reset();
}
void Initialize()
if (Creature* zealot = instance->GetCreature(DATA_ZATH))
{
Enraged = false;
WasDead = false;
_lorkhanDied = false;
_zathDied = false;
zealot->AI()->Reset();
}
void Reset() override
// emote idle loop
scheduler.Schedule(5s, 25s, [this](TaskContext context)
{
_Reset();
Initialize();
// pick a random emote from the list of available emotes
me->HandleEmoteCommand(
RAND(
EMOTE_ONESHOT_TALK,
EMOTE_ONESHOT_FLEX,
EMOTE_ONESHOT_POINT
)
);
context.Repeat(5s, 25s);
});
me->SetStandState(UNIT_STAND_STATE_STAND);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
if (Creature* zealot = instance->GetCreature(DATA_LORKHAN))
{
zealot->Kill(zealot, zealot);
}
if (Creature* zealot = instance->GetCreature(DATA_ZATH))
{
zealot->Kill(zealot, zealot);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
scheduler.CancelAll();
scheduler.Schedule(4s, [this](TaskContext context)
{
DoCastVictim(SPELL_MORTALCLEAVE);
context.Repeat(15s, 20s);
}).Schedule(9s, [this](TaskContext context)
{
DoCastVictim(SPELL_SILENCE);
context.Repeat(20s, 25s);
}).Schedule(16s, [this](TaskContext context)
{
DoCastSelf(SPELL_BLOODLUST);
context.Repeat(20s, 28s);
});
}
void SetData(uint32 /*type*/, uint32 data) override
{
UpdateZealotStatus(data, true);
CheckPhaseTransition();
scheduler.Schedule(10s, [this, data](TaskContext /*context*/)
{
if (!_lorkhanDied || !_zathDied || !_wasDead)
{
ReviveZealot(data);
}
});
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damageEffectType, SpellSchoolMask spellSchoolMask) override
{
if (!me->HasAura(SPELL_TIGER_FORM) && damage >= me->GetHealth())
{
damage = me->GetHealth() - 1;
if (!_wasDead)
{
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_DEAD);
me->AttackStop();
DoResetThreatList();
_wasDead = true;
CheckPhaseTransition();
Talk(EMOTE_DIES);
}
}
BossAI::DamageTaken(attacker, damage, damageEffectType, spellSchoolMask);
}
void DoAction(int32 action) override
{
if (action == ACTION_RESSURRECT)
{
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RestoreFaction();
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->LoadEquipment(1, true);
if (Creature* zealot = instance->GetCreature(DATA_LORKHAN))
{
zealot->AI()->Reset();
}
if (Creature* zealot = instance->GetCreature(DATA_ZATH))
{
zealot->AI()->Reset();
}
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
me->SetFullHealth();
_wasDead = false;
}
}
void JustDied(Unit* /*killer*/) override
void UpdateAI(uint32 diff) override
{
if (me->IsInCombat() && !UpdateVictim())
{
_JustDied();
Talk(SAY_DEATH);
if (Creature* zealot = instance->GetCreature(DATA_LORKHAN))
{
zealot->Kill(zealot, zealot);
}
if (Creature* zealot = instance->GetCreature(DATA_ZATH))
{
zealot->Kill(zealot, zealot);
}
return;
}
void JustEngagedWith(Unit* /*who*/) override
else if (me->IsInCombat())
{
_JustEngagedWith();
_scheduler.CancelAll();
_scheduler.Schedule(4s, [this](TaskContext context) {
DoCastVictim(SPELL_MORTALCLEAVE);
context.Repeat(15s, 20s);
}).Schedule(9s, [this](TaskContext context) {
DoCastVictim(SPELL_SILENCE);
context.Repeat(20s, 25s);
}).Schedule(16s, [this](TaskContext context) {
DoCastSelf(SPELL_BLOODLUST);
context.Repeat(20s, 28s);
});
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void SetData(uint32 /*type*/, uint32 data) override
else
{
UpdateZealotStatus(data, true);
CheckPhaseTransition();
scheduler.Update(diff);
}
}
_scheduler.Schedule(10s, [this, data](TaskContext /*context*/) {
if (!_lorkhanDied || !_zathDied || !WasDead)
void ReviveZealot(uint32 zealotData)
{
if (Creature* zealot = instance->GetCreature(zealotData))
{
zealot->Respawn(true);
zealot->SetInCombatWithZone();
UpdateZealotStatus(zealotData, false);
}
}
void UpdateZealotStatus(uint32 data, bool dead)
{
if (data == DATA_LORKHAN)
{
_lorkhanDied = dead;
}
else if (data == DATA_ZATH)
{
_zathDied = dead;
}
}
void CheckPhaseTransition()
{
if (_wasDead && _lorkhanDied && _zathDied)
{
scheduler.Schedule(3s, [this](TaskContext /*context*/)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
DoCastSelf(SPELL_RESURRECTION_IMPACT_VISUAL, true);
scheduler.Schedule(50ms, [this](TaskContext /*context*/)
{
ReviveZealot(data);
}
});
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!me->HasAura(SPELL_TIGER_FORM) && damage >= me->GetHealth())
{
damage = me->GetHealth() - 1;
if (!WasDead)
{
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SLEEP);
me->AttackStop();
DoResetThreatList();
WasDead = true;
CheckPhaseTransition();
Talk(EMOTE_THEKAL_DIES);
}
}
if (!Enraged && me->HealthBelowPctDamaged(20, damage) && me->HasAura(SPELL_TIGER_FORM))
{
DoCastSelf(SPELL_ENRAGE);
Enraged = true;
}
}
void DoAction(int32 action) override
{
if (action == ACTION_RESSURRECT)
{
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RestoreFaction();
me->SetReactState(REACT_AGGRESSIVE);
me->SetFullHealth();
WasDead = false;
}
}
void UpdateAI(uint32 diff) override
{
if (me->GetReactState() != REACT_PASSIVE && !UpdateVictim())
return;
_scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void ReviveZealot(uint32 zealotData)
{
if (Creature* zealot = instance->GetCreature(zealotData))
{
zealot->Respawn(true);
zealot->SetInCombatWithZone();
UpdateZealotStatus(zealotData, false);
}
}
void UpdateZealotStatus(uint32 data, bool dead)
{
if (data == DATA_LORKHAN)
{
_lorkhanDied = dead;
}
else if (data == DATA_ZATH)
{
_zathDied = dead;
}
}
void CheckPhaseTransition()
{
if (WasDead && _lorkhanDied && _zathDied)
{
_scheduler.Schedule(3s, [this](TaskContext /*context*/) {
Talk(SAY_AGGRO);
me->SetStandState(UNIT_STAND_STATE_STAND);
});
scheduler.Schedule(6s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_TIGER_FORM);
me->LoadEquipment(0, true);
me->SetFullHealth();
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
_scheduler.Schedule(6s, [this](TaskContext /*context*/) {
DoCastSelf(SPELL_TIGER_FORM);
me->LoadEquipment(0, true);
me->SetReactState(REACT_AGGRESSIVE);
scheduler.Schedule(30s, [this](TaskContext context)
{
DoCastSelf(SPELL_FRENZY);
context.Repeat();
}).Schedule(4s, [this](TaskContext context)
{
DoCastVictim(SPELL_FORCEPUNCH);
context.Repeat(16s, 21s);
}).Schedule(12s, [this](TaskContext context)
{
// charge a random target that is at least 8 yards away (min range of charge is 8 yards)
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -8.0f))
{
DoCast(target, SPELL_CHARGE);
DoResetThreatList();
AttackStart(target);
}
context.Repeat(15s, 22s);
}).Schedule(25s, [this](TaskContext context)
{
DoCastVictim(SPELL_SUMMONTIGERS, true);
context.Repeat(10s, 14s);
});
_scheduler.Schedule(30s, [this](TaskContext context) {
DoCastSelf(SPELL_FRENZY);
context.Repeat();
}).Schedule(4s, [this](TaskContext context) {
DoCastVictim(SPELL_FORCEPUNCH);
context.Repeat(16s, 21s);
}).Schedule(12s, [this](TaskContext context) {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
DoCast(target, SPELL_CHARGE);
DoResetThreatList();
AttackStart(target);
}
context.Repeat(15s, 22s);
}).Schedule(25s, [this](TaskContext context) {
DoCastVictim(SPELL_SUMMONTIGERS, true);
context.Repeat(10s, 14s);
});
// schedule Enrage at 20% health
ScheduleHealthCheckEvent(20, [this]
{
DoCastSelf(SPELL_ENRAGE);
});
});
});
}
else
{
scheduler.Schedule(10s, [this](TaskContext /*context*/)
{
if (!(_wasDead && _lorkhanDied && _zathDied))
{
DoAction(ACTION_RESSURRECT);
}
});
}
}
private:
bool _lorkhanDied;
bool _zathDied;
bool _enraged;
bool _wasDead;
};
struct npc_zealot_lorkhan : public ScriptedAI
{
npc_zealot_lorkhan(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
void Reset() override
{
_scheduler.CancelAll();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
// emote idle loop
_scheduler.Schedule(5s, 25s, [this](TaskContext context)
{
// pick a random emote from the list of available emotes
me->HandleEmoteCommand(
RAND(
EMOTE_ONESHOT_QUESTION,
EMOTE_ONESHOT_YES,
EMOTE_ONESHOT_NO
)
);
context.Repeat(5s, 25s);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.CancelAll();
_scheduler.Schedule(1s, [this](TaskContext context)
{
DoCastSelf(SPELL_SHIELD);
context.Repeat(1min);
}).Schedule(32s, [this](TaskContext context)
{
Unit* thekal = instance->GetCreature(DATA_THEKAL);
Unit* zath = instance->GetCreature(DATA_ZATH);
if (!thekal || !zath)
return;
if ((me->GetHealthPct() <= thekal->GetHealthPct()) || (me->GetHealthPct() <= zath->GetHealthPct()))
{
DoCastSelf(SPELL_GREATERHEAL);
}
else if (zath->GetHealthPct() <= thekal->GetHealthPct())
{
DoCast(zath, SPELL_GREATERHEAL);
}
else
{
_scheduler.Schedule(10s, [this](TaskContext /*context*/) {
if (!(WasDead && _lorkhanDied && _zathDied))
{
DoAction(ACTION_RESSURRECT);
}
});
DoCast(thekal, SPELL_GREATERHEAL);
}
}
private:
TaskScheduler _scheduler;
GuidVector _catGuids;
bool _lorkhanDied;
bool _zathDied;
bool Enraged;
bool WasDead;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<boss_thekalAI>(creature);
context.Repeat(15s, 20s);
}).Schedule(6s, [this](TaskContext context)
{
DoCastVictim(SPELL_DISARM);
context.Repeat(15s, 25s);
});
}
void JustDied(Unit* /*killer*/) override
{
Talk(EMOTE_ZEALOT_DIES);
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
{
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_LORKHAN);
}
}
void UpdateAI(uint32 diff) override
{
if (me->IsInCombat() && !UpdateVictim())
{
return;
}
else if (me->IsInCombat())
{
_scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
else
{
_scheduler.Update(diff);
}
}
private:
TaskScheduler _scheduler;
};
class npc_zealot_lorkhan : public CreatureScript
struct npc_zealot_zath : public ScriptedAI
{
public:
npc_zealot_lorkhan() : CreatureScript("npc_zealot_lorkhan") { }
struct npc_zealot_lorkhanAI : public ScriptedAI
npc_zealot_zath(Creature* creature) : ScriptedAI(creature)
{
npc_zealot_lorkhanAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
void Reset() override
{
_scheduler.CancelAll();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(1s, [this](TaskContext context) {
DoCastSelf(SPELL_SHIELD);
context.Repeat(1min);
}).Schedule(32s, [this](TaskContext context) {
Unit* thekal = instance->GetCreature(DATA_THEKAL);
Unit* zath = instance->GetCreature(DATA_ZATH);
if (!thekal || !zath)
return;
if ((me->GetHealthPct() <= thekal->GetHealthPct()) || (me->GetHealthPct() <= zath->GetHealthPct()))
{
DoCastSelf(SPELL_GREATERHEAL);
}
else if (zath->GetHealthPct() <= thekal->GetHealthPct())
{
DoCast(zath, SPELL_GREATERHEAL);
}
else
{
DoCast(thekal, SPELL_GREATERHEAL);
}
context.Repeat(15s, 20s);
}).Schedule(6s, [this](TaskContext context) {
DoCastVictim(SPELL_DISARM);
context.Repeat(15s, 25s);
});
}
void JustDied(Unit* /*killer*/) override
{
Talk(EMOTE_ZEALOT_DIES);
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
{
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_LORKHAN);
}
}
void UpdateAI(uint32 diff) override
{
if (me->GetReactState() != REACT_PASSIVE && !UpdateVictim())
return;
_scheduler.Update(diff,
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
}
private:
TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<npc_zealot_lorkhanAI>(creature);
instance = creature->GetInstanceScript();
}
};
class npc_zealot_zath : public CreatureScript
{
public:
npc_zealot_zath() : CreatureScript("npc_zealot_zath") { }
InstanceScript* instance;
struct npc_zealot_zathAI : public ScriptedAI
void Reset() override
{
npc_zealot_zathAI(Creature* creature) : ScriptedAI(creature)
_scheduler.CancelAll();
_scheduler.SetValidator([this]
{
instance = creature->GetInstanceScript();
}
return !me->HasUnitState(UNIT_STATE_CASTING);
});
InstanceScript* instance;
void Reset() override
// emote idle loop
_scheduler.Schedule(5s, 25s, [this](TaskContext context)
{
_scheduler.CancelAll();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING) && !me->HasReactState(REACT_PASSIVE);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(13s, [this](TaskContext context) {
DoCastSelf(SPELL_SWEEPINGSTRIKES);
context.Repeat(1min);
}).Schedule(16s, [this](TaskContext context) {
DoCastSelf(SPELL_BLOODLUST);
context.Repeat(22s, 26s);
}).Schedule(8s, [this](TaskContext context) {
DoCastVictim(SPELL_SINISTERSTRIKE);
context.Repeat(8s, 16s);
}).Schedule(25s, [this](TaskContext context) {
DoCastVictim(SPELL_GOUGE);
if (DoGetThreat(me->GetVictim()))
{
DoModifyThreatByPercent(me->GetVictim(), -100);
}
context.Repeat(17s, 27s);
}).Schedule(18s, [this](TaskContext context) {
DoCastVictim(SPELL_KICK);
context.Repeat(15s, 25s);
}).Schedule(5s, [this](TaskContext context) {
DoCastVictim(SPELL_BLIND);
context.Repeat(10s, 20s);
});
}
void JustDied(Unit* /*killer*/) override
{
Talk(EMOTE_ZEALOT_DIES);
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
{
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_ZATH);
}
}
void UpdateAI(uint32 diff) override
{
if (me->GetReactState() != REACT_PASSIVE && !UpdateVictim())
return;
_scheduler.Update(diff,
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
}
private:
TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<npc_zealot_zathAI>(creature);
// pick a random emote from the list of available emotes
me->HandleEmoteCommand(
RAND(
EMOTE_ONESHOT_TALK,
EMOTE_ONESHOT_BEG,
EMOTE_ONESHOT_YES
)
);
context.Repeat(5s, 25s);
});
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.CancelAll();
_scheduler.Schedule(13s, [this](TaskContext context)
{
DoCastSelf(SPELL_SWEEPINGSTRIKES);
context.Repeat(1min);
}).Schedule(16s, [this](TaskContext context)
{
DoCastSelf(SPELL_BLOODLUST);
context.Repeat(22s, 26s);
}).Schedule(8s, [this](TaskContext context)
{
DoCastVictim(SPELL_SINISTERSTRIKE);
context.Repeat(8s, 16s);
}).Schedule(25s, [this](TaskContext context)
{
DoCastVictim(SPELL_GOUGE);
if (DoGetThreat(me->GetVictim()))
{
DoModifyThreatByPercent(me->GetVictim(), -100);
}
context.Repeat(17s, 27s);
}).Schedule(18s, [this](TaskContext context)
{
DoCastVictim(SPELL_KICK);
context.Repeat(15s, 25s);
}).Schedule(5s, [this](TaskContext context)
{
DoCastVictim(SPELL_BLIND);
context.Repeat(10s, 20s);
});
}
void JustDied(Unit* /*killer*/) override
{
Talk(EMOTE_ZEALOT_DIES);
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
{
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_ZATH);
}
}
void UpdateAI(uint32 diff) override
{
if (me->IsInCombat() && !UpdateVictim())
{
return;
}
else if (me->IsInCombat())
{
_scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
else
{
_scheduler.Update(diff);
}
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_thekal()
{
new boss_thekal();
new npc_zealot_lorkhan();
new npc_zealot_zath();
RegisterCreatureAI(boss_thekal);
RegisterCreatureAI(npc_zealot_lorkhan);
RegisterCreatureAI(npc_zealot_zath);
}