mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-17 10:55:43 +00:00
(Scripts/AI) ZG20: Improvements to Thekal (Tiger Boss) (#17603)
Co-authored-by: AG <43139552+AGandrup@users.noreply.github.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user