diff --git a/data/sql/updates/pending_db_world/rev_1698463311896667349.sql b/data/sql/updates/pending_db_world/rev_1698463311896667349.sql
new file mode 100644
index 000000000..a72da09e5
--- /dev/null
+++ b/data/sql/updates/pending_db_world/rev_1698463311896667349.sql
@@ -0,0 +1,18 @@
+-- Thekal (14509)
+-- Update SAY_AGGRO to include emote ONESHOT_ROAR
+-- Update comments
+UPDATE `creature_text` SET `Emote`=15, `comment`='High Priest Thekal - SAY_AGGRO' WHERE `CreatureID`=14509 AND `GroupID`=0 AND `ID`=0;
+UPDATE `creature_text` SET `comment`='High Priest Thekal - SAY_DEATH' WHERE `CreatureID`=14509 AND `GroupID`=1 AND `ID`=0;
+UPDATE `creature_text` SET `comment`='High Priest Thekal - EMOTE_DIES' WHERE `CreatureID`=14509 AND `GroupID`=2 AND `ID`=0;
+
+-- Thekal (14509)
+-- Remove static idle (talking) emote
+UPDATE `creature_addon` SET `emote`=0 WHERE `guid`=49310;
+
+-- Zealot Lor'Khan (11347)
+-- Update comments
+UPDATE `creature_text` SET `comment`='Zealot LorKhan - EMOTE_ZEALOT_DIES' WHERE `CreatureID`=11347 AND `GroupID`=0 AND `ID`=0;
+
+-- Zealot Zath (11348)
+-- Update comments
+UPDATE `creature_text` SET `comment`='Zealot Zath - EMOTE_ZEALOT_DIES' WHERE `CreatureID`=11348 AND `GroupID`=0 AND `ID`=0;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index c310b5e53..0fc3038c8 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1541,7 +1541,6 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
case 2584: // Waiting to Resurrect
case 22011: // Spirit Heal Channel
case 22012: // Spirit Heal
- case 24171: // Resurrection Impact Visual
case 42792: // Recently Dropped Flag
case 43681: // Inactive
case 44535: // Spirit Heal (mana)
diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp
index ea6c77f97..62a5e6ef9 100644
--- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp
+++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#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(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(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(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);
}