Script/ZulGurub: rewrite High Priest Thekal's encounter script (#23429)

This commit is contained in:
Wyrserth
2019-06-27 21:03:29 +02:00
committed by GitHub
parent cb524a06b7
commit 365e2f191e
3 changed files with 393 additions and 357 deletions

View File

@@ -0,0 +1,7 @@
DELETE FROM `creature_text` WHERE `CreatureID` IN (14509, 11347, 11348) AND `GroupId`=2;
DELETE FROM `creature_text` WHERE `CreatureID`=14509 AND `GroupId`=3;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(14509, 2, 0, "%s dies.", 16, 0, 100, 0, 0, 0, 12195, 0, "High Priest Thekal"),
(14509, 3, 0, "%s goes into a frenzy!", 16, 0, 100, 0, 0, 0, 1191, 0, "High Priest Thekal"),
(11347, 2, 0, "%s dies.", 16, 0, 100, 0, 0, 0, 10453, 0, "Zealoth Lor'khan"),
(11348, 2, 0, "%s dies.", 16, 0, 100, 0, 0, 0, 12195, 0, "Zealot Zath");

View File

@@ -1573,7 +1573,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)

View File

@@ -17,52 +17,66 @@
*/
#include "zulgurub.h"
#include "CellImpl.h"
#include "GridNotifiersImpl.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
enum Says
{
SAY_AGGRO = 0,
SAY_DEATH = 1
TALK_TIGER_PHASE = 0,
TALK_DEATH = 1,
TALK_FAKE_DEATH = 2,
TALK_FRENZY = 3
};
enum Spells
{
SPELL_MORTALCLEAVE = 22859, // Phase 1
SPELL_SILENCE = 22666, // Phase 1
SPELL_TIGER_FORM = 24169, // Phase 1
SPELL_RESURRECT = 24173, // Phase 1 // Not used in script.
SPELL_FRENZY = 8269, // Phase 2
SPELL_FORCEPUNCH = 24189, // Phase 2
SPELL_CHARGE = 24193, // Phase 2
SPELL_ENRAGE = 8269, // Phase 2
SPELL_SUMMONTIGERS = 24183, // Phase 2
// Zealot Lor'Khan Spells
SPELL_RESURRECT = 24173, // ToDo: find out how this should be used
SPELL_RESURRECT_VISUAL = 24171,
// High Priest Thekal
// Phase 1
SPELL_MORTALCLEAVE = 22859,
SPELL_SILENCE = 22666,
// Phase 2
SPELL_TIGER_FORM = 24169,
SPELL_FRENZY = 8269,
SPELL_FORCEPUNCH = 24189,
SPELL_CHARGE = 24193,
SPELL_SUMMONTIGERS = 24183,
// Zealot Lor'Khan
SPELL_SHIELD = 20545,
SPELL_BLOODLUST = 24185,
SPELL_GREATERHEAL = 24208,
SPELL_DISARM = 6713,
// Zealot Zath Spells
// Zealot Zath
SPELL_SWEEPINGSTRIKES = 18765,
SPELL_SINISTERSTRIKE = 15581,
SPELL_GOUGE = 12540,
SPELL_KICK = 15614,
SPELL_BLIND = 21060
SPELL_BLIND = 21060,
SPELL_PERMANENT_FEIGN_DEATH = 29266
};
enum Events
enum ThekalEvents
{
EVENT_MORTALCLEAVE = 1, // Phase 1
EVENT_SILENCE = 2, // Phase 1
EVENT_CHECK_TIMER = 3, // Phase 1
EVENT_RESURRECT_TIMER = 4, // Phase 1
EVENT_FRENZY = 5, // Phase 2
EVENT_FORCEPUNCH = 6, // Phase 2
EVENT_SPELL_CHARGE = 7, // Phase 2
EVENT_ENRAGE = 8, // Phase 2
EVENT_SUMMONTIGERS = 9 // Phase 2
EVENT_MORTALCLEAVE = 1,
EVENT_SILENCE,
EVENT_RESURRECT_TIMER,
EVENT_CHANGE_PHASE_1,
EVENT_CHANGE_PHASE_2,
EVENT_CHANGE_PHASE_3,
EVENT_FORCEPUNCH,
EVENT_SPELL_CHARGE,
EVENT_SUMMONTIGERS
};
enum Phases
@@ -71,10 +85,13 @@ enum Phases
PHASE_TWO = 2
};
// AWFUL HACK WARNING
// To whoever reads this: Zul'Gurub needs your love
// Need to do this calculation to increase/decrease Thekal's damage by 40% (probably some aura missing)
// This is only to compile the scripts after the aura calculation revamp
// Resurrection is handled by the main boss' script, dispatching resurrection as needed
enum Data
{
DATA_FAKE_DEATH = 1,
DATA_RESURRECTED
};
float const DamageIncrease = 40.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
@@ -93,43 +110,134 @@ class boss_thekal : public CreatureScript
void Initialize()
{
_enraged = false;
_wasDead = false;
_isThekalDead = false;
_isLorkhanDead = false;
_isZathDead = false;
_isResurrectTimerActive = false;
_isChangingPhase = false;
}
void EnterEvadeMode(EvadeReason why) override
{
if (!_EnterEvadeMode(why))
return;
me->AddUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->MoveTargetedHome();
Reset();
}
void Reset() override
{
if (events.IsInPhase(PHASE_TWO))
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
me->SetControlled(false, UNIT_STATE_ROOT);
events.Reset();
_Reset();
Initialize();
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
Talk(TALK_DEATH);
// Adds are still feign-deathing, so kill them when the encounter is over
if (Creature* creature = instance->GetCreature(DATA_LORKHAN))
creature->KillSelf();
if (Creature* creature = instance->GetCreature(DATA_ZATH))
creature->KillSelf();
instance->SetBossState(DATA_LORKHAN, DONE);
instance->SetBossState(DATA_ZATH, DONE);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_MORTALCLEAVE, 4s, 0, PHASE_ONE); // Phase 1
events.ScheduleEvent(EVENT_SILENCE, 9s, 0, PHASE_ONE); // Phase 1
events.ScheduleEvent(EVENT_CHECK_TIMER, 10s, 0, PHASE_ONE); // Phase 1
events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10s, 0, PHASE_ONE); // Phase 1
Talk(SAY_AGGRO);
events.SetPhase(PHASE_ONE);
events.ScheduleEvent(EVENT_MORTALCLEAVE, 4s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_SILENCE, 9s, 0, PHASE_ONE);
}
void JustReachedHome() override
void SetData(uint32 type, uint32 data) override
{
instance->SetBossState(DATA_THEKAL, NOT_STARTED);
if (type == DATA_FAKE_DEATH)
{
// A mob died
switch (data)
{
case NPC_HIGH_PRIEST_THEKAL:
_isThekalDead = true;
break;
case NPC_ZEALOT_LORKHAN:
_isLorkhanDead = true;
break;
case NPC_ZEALOT_ZATH:
_isZathDead = true;
break;
}
if (_isThekalDead && _isLorkhanDead && _isZathDead)
{
_isResurrectTimerActive = false;
events.Reset();
events.ScheduleEvent(EVENT_CHANGE_PHASE_1, 3s);
}
else
{
// Start resurrection timer if not already started, otherwise ignore
if (!_isResurrectTimerActive)
{
events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10s);
_isResurrectTimerActive = true;
}
}
}
else if (type == DATA_RESURRECTED)
{
Creature* creature = nullptr;
if (data == NPC_HIGH_PRIEST_THEKAL)
creature = me;
else if (data == NPC_ZEALOT_LORKHAN)
creature = instance->GetCreature(DATA_LORKHAN);
else if (data == NPC_ZEALOT_ZATH)
creature = instance->GetCreature(DATA_ZATH);
// Resurrect
if (creature)
{
creature->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
creature->SetFullHealth();
creature->SetImmuneToPC(false, true);
creature->SetImmuneToNPC(false, true);
}
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth() && events.IsInPhase(PHASE_ONE))
{
Talk(TALK_FAKE_DEATH);
me->RemoveAllAuras();
me->SetImmuneToPC(true, true);
me->SetImmuneToNPC(true, true);
DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH, true);
events.DelayEvents(10s);
SetData(DATA_FAKE_DEATH, me->GetEntry());
damage = 0;
}
else if (events.IsInPhase(PHASE_TWO) && !_enraged && me->HealthBelowPct(10))
{
DoCastSelf(SPELL_FRENZY);
Talk(TALK_FRENZY);
_enraged = true;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -140,74 +248,72 @@ class boss_thekal : public CreatureScript
switch (eventId)
{
case EVENT_MORTALCLEAVE:
DoCastVictim(SPELL_MORTALCLEAVE, true);
DoCastVictim(SPELL_MORTALCLEAVE);
events.ScheduleEvent(EVENT_MORTALCLEAVE, 15s, 20s, 0, PHASE_ONE);
break;
case EVENT_SILENCE:
DoCastVictim(SPELL_SILENCE, true);
DoCastVictim(SPELL_SILENCE);
events.ScheduleEvent(EVENT_SILENCE, 20s, 25s, 0, PHASE_ONE);
break;
case EVENT_RESURRECT_TIMER:
// Thekal will transform to Tiger if he died and was not resurrected after 10 seconds.
if (_wasDead)
{
DoCast(me, SPELL_TIGER_FORM); // SPELL_AURA_TRANSFORM
me->SetObjectScale(2.00f);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 40)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 40)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease); // hack
ResetThreatList();
events.ScheduleEvent(EVENT_FRENZY, 30s, 0, PHASE_TWO); // Phase 2
events.ScheduleEvent(EVENT_FORCEPUNCH, 4s, 0, PHASE_TWO); // Phase 2
events.ScheduleEvent(EVENT_SPELL_CHARGE, 12s, 0, PHASE_TWO); // Phase 2
events.ScheduleEvent(EVENT_ENRAGE, 32s, 0, PHASE_TWO); // Phase 2
events.ScheduleEvent(EVENT_SUMMONTIGERS, 25s, 0, PHASE_TWO); // Phase 2
events.SetPhase(PHASE_TWO);
}
events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10s, 0, PHASE_ONE);
break;
case EVENT_CHECK_TIMER:
// Check_Timer for the death of LorKhan and Zath.
if (!_wasDead)
{
if (instance->GetBossState(DATA_LORKHAN) == SPECIAL)
{
// Resurrect LorKhan
if (Creature* lorKhan = instance->GetCreature(DATA_LORKHAN))
{
lorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
lorKhan->SetFaction(FACTION_MONSTER);
lorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
lorKhan->SetFullHealth();
instance->SetData(DATA_LORKHAN, DONE);
}
}
{
// If only one or two of the three mobs were killed, resurrect them
_isResurrectTimerActive = false;
if (instance->GetBossState(DATA_ZATH) == SPECIAL)
{
// Resurrect Zath
if (Creature* zath = instance->GetCreature(DATA_ZATH))
{
zath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
zath->SetFaction(FACTION_MONSTER);
zath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
zath->SetFullHealth();
instance->SetBossState(DATA_ZATH, DONE);
}
}
if (_isThekalDead)
{
DoCastSelf(SPELL_RESURRECT_VISUAL);
SetData(DATA_RESURRECTED, me->GetEntry());
_isThekalDead = false;
}
if (_isLorkhanDead)
{
if (Creature* lorkhan = instance->GetCreature(DATA_LORKHAN))
{
lorkhan->AI()->DoCastSelf(SPELL_RESURRECT_VISUAL);
SetData(DATA_RESURRECTED, lorkhan->GetEntry());
}
_isLorkhanDead = false;
}
if (_isZathDead)
{
if (Creature* zath = instance->GetCreature(DATA_ZATH))
{
zath->AI()->DoCastSelf(SPELL_RESURRECT_VISUAL);
SetData(DATA_RESURRECTED, zath->GetEntry());
}
_isZathDead = false;
}
events.ScheduleEvent(EVENT_CHECK_TIMER, 5s, 0, PHASE_ONE);
break;
case EVENT_FRENZY:
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 30s, 0, PHASE_TWO);
}
case EVENT_CHANGE_PHASE_1:
_isChangingPhase = true;
me->SetControlled(true, UNIT_STATE_ROOT);
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
me->SetFullHealth();
DoCastSelf(SPELL_RESURRECT_VISUAL);
events.ScheduleEvent(EVENT_CHANGE_PHASE_2, 1s);
break;
case EVENT_CHANGE_PHASE_2:
Talk(TALK_TIGER_PHASE);
events.ScheduleEvent(EVENT_CHANGE_PHASE_3, 1s);
break;
case EVENT_CHANGE_PHASE_3:
{
// Trigger phase change
_isChangingPhase = false;
DoCastSelf(SPELL_TIGER_FORM);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease);
ResetThreatList();
me->SetControlled(false, UNIT_STATE_ROOT);
events.ScheduleEvent(EVENT_FORCEPUNCH, 4s, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_SPELL_CHARGE, 12s, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_SUMMONTIGERS, 25s, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
}
case EVENT_FORCEPUNCH:
DoCastVictim(SPELL_FORCEPUNCH, true);
events.ScheduleEvent(EVENT_FORCEPUNCH, 16s, 21s, 0, PHASE_TWO);
@@ -221,14 +327,6 @@ class boss_thekal : public CreatureScript
}
events.ScheduleEvent(EVENT_CHARGE, 15s, 22s, 0, PHASE_TWO);
break;
case EVENT_ENRAGE:
if (HealthBelowPct(11) && !_enraged)
{
DoCast(me, SPELL_ENRAGE);
_enraged = true;
}
events.ScheduleEvent(EVENT_ENRAGE, 30s);
break;
case EVENT_SUMMONTIGERS:
DoCastVictim(SPELL_SUMMONTIGERS, true);
events.ScheduleEvent(EVENT_SUMMONTIGERS, 10s, 14s, 0, PHASE_TWO);
@@ -236,32 +334,24 @@ class boss_thekal : public CreatureScript
default:
break;
}
if (me->IsFullHealth() && _wasDead)
_wasDead = false;
if ((events.IsInPhase(PHASE_ONE)) && !_wasDead && !HealthAbovePct(5))
{
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_SLEEP);
me->AttackStop();
instance->SetBossState(DATA_THEKAL, SPECIAL);
_wasDead = true;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
if (_isChangingPhase)
return;
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
bool _enraged;
bool _wasDead;
bool _isThekalDead;
bool _isLorkhanDead;
bool _isZathDead;
bool _isResurrectTimerActive;
bool _isChangingPhase;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -270,147 +360,135 @@ class boss_thekal : public CreatureScript
}
};
enum LorkhanEvents
{
EVENT_SHIELD = 1,
EVENT_BLOODLUST,
EVENT_GREATER_HEAL,
EVENT_DISARM
};
// Find which one of the three creatures Lor'Khan should heal (self, Thekal or Zath)
class LorKhanSelectTargetToHeal
{
public:
LorKhanSelectTargetToHeal(Unit const* obj, float range) : i_obj(obj), i_range(range), i_hp(0) { }
bool operator()(Unit* u)
{
if (u->GetTypeId() != TYPEID_UNIT || !u->IsAlive() || !u->IsInCombat())
return false;
if (u->ToCreature()->GetEntry() != NPC_HIGH_PRIEST_THEKAL && u->GetEntry() != NPC_ZEALOT_LORKHAN && u->GetEntry() != NPC_ZEALOT_ZATH)
return false;
// Don't allow to heal a target that is waiting for resurrection
if (u->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
return false;
if ((u->GetMaxHealth() - u->GetHealth() > i_hp) && i_obj->IsWithinDistInMap(u, i_range))
{
i_hp = u->GetMaxHealth() - u->GetHealth();
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_hp;
};
// Zealot Lor'Khan
class npc_zealot_lorkhan : public CreatureScript
{
public: npc_zealot_lorkhan() : CreatureScript("npc_zealot_lorkhan") { }
public: npc_zealot_lorkhan() : CreatureScript("npc_zealot_lorkhan") { }
struct npc_zealot_lorkhanAI : public ScriptedAI
{
npc_zealot_lorkhanAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript())
{
Initialize();
}
void Initialize()
{
_shieldTimer = 1000;
_bloodLustTimer = 16000;
_greaterHealTimer = 32000;
_disarmTimer = 6000;
_checkTimer = 10000;
_fakeDeath = false;
}
npc_zealot_lorkhanAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
Initialize();
_events.Reset();
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC);
}
_instance->SetBossState(DATA_LORKHAN, NOT_STARTED);
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth())
{
Talk(TALK_FAKE_DEATH);
me->RemoveAllAuras();
me->SetImmuneToPC(true, true);
me->SetImmuneToNPC(true, true);
DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH, true);
me->AttackStop();
if (Creature* thekal = _instance->GetCreature(DATA_THEKAL))
thekal->AI()->SetData(DATA_FAKE_DEATH, me->GetEntry());
_events.DelayEvents(10s);
damage = 0;
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_SHIELD, 1s);
_events.ScheduleEvent(EVENT_BLOODLUST, 16s);
_events.ScheduleEvent(EVENT_GREATER_HEAL, 32s);
_events.ScheduleEvent(EVENT_DISARM, 6s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (_shieldTimer <= diff)
if (uint32 eventId = _events.ExecuteEvent())
{
DoCast(me, SPELL_SHIELD);
_shieldTimer = 61000;
}
else
_shieldTimer -= diff;
if (_bloodLustTimer <= diff)
{
DoCast(me, SPELL_BLOODLUST);
_bloodLustTimer = 20000 + rand32() % 8000;
}
else
_bloodLustTimer -= diff;
// Casting Greaterheal to Thekal or Zath if they are in meele range.
if (_greaterHealTimer <= diff)
{
Creature* thekal = _instance->GetCreature(DATA_THEKAL);
Creature* zath = _instance->GetCreature(DATA_ZATH);
if (!thekal && !zath)
return;
bool roll = roll_chance_i(50);
Creature* target = roll ? (thekal ? thekal : zath) : (zath ? zath : thekal);
// As we check already above to ensure at least 1 out of Thekal/Zath is not null, target must be not null
ASSERT(target);
if (!me->IsWithinMeleeRange(target))
target = roll ? zath : thekal;
if (me->IsWithinMeleeRange(target))
DoCast(target, SPELL_GREATERHEAL);
_greaterHealTimer = 15000 + rand32() % 5000;
}
else
_greaterHealTimer -= diff;
if (_disarmTimer <= diff)
{
DoCastVictim(SPELL_DISARM);
_disarmTimer = 15000 + rand32() % 10000;
}
else
_disarmTimer -= diff;
// Check for the death of LorKhan and Zath.
if (!_fakeDeath && _checkTimer <= diff)
{
if (_instance->GetBossState(DATA_THEKAL) == SPECIAL)
switch (eventId)
{
// Resurrect Thekal
if (Creature* thekal = _instance->GetCreature(DATA_THEKAL))
case EVENT_SHIELD:
DoCastSelf(SPELL_SHIELD);
_events.ScheduleEvent(EVENT_SHIELD, 61s);
break;
case EVENT_BLOODLUST:
DoCastSelf(SPELL_BLOODLUST);
_events.ScheduleEvent(EVENT_BLOODLUST, 20s, 28s);
break;
case EVENT_GREATER_HEAL:
{
thekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
thekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
thekal->SetFaction(FACTION_MONSTER);
thekal->SetFullHealth();
Unit* target = nullptr;
LorKhanSelectTargetToHeal check(me, 100.0f);
Trinity::UnitLastSearcher<LorKhanSelectTargetToHeal> searcher(me, target, check);
Cell::VisitAllObjects(me, searcher, 100.0f);
if (target)
DoCast(target, SPELL_GREATERHEAL);
_events.ScheduleEvent(EVENT_GREATER_HEAL, 15s, 20s);
break;
}
case EVENT_DISARM:
DoCastVictim(SPELL_DISARM);
_events.ScheduleEvent(EVENT_DISARM, 15s, 25s);
break;
}
if (_instance->GetBossState(DATA_ZATH) == SPECIAL)
{
// Resurrect Zath
if (Creature* zath = _instance->GetCreature(DATA_ZATH))
{
zath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
zath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
zath->SetFaction(FACTION_MONSTER);
zath->SetFullHealth();
}
}
_checkTimer = 5000;
}
else
_checkTimer -= diff;
if (!HealthAbovePct(5))
{
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_SLEEP);
me->SetFaction(FACTION_FRIENDLY);
me->AttackStop();
_instance->SetBossState(DATA_LORKHAN, SPECIAL);
_fakeDeath = true;
}
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
uint32 _shieldTimer;
uint32 _bloodLustTimer;
uint32 _greaterHealTimer;
uint32 _disarmTimer;
uint32 _checkTimer;
bool _fakeDeath;
EventMap _events;
InstanceScript* _instance;
};
@@ -420,6 +498,15 @@ class npc_zealot_lorkhan : public CreatureScript
}
};
enum ZathEvents
{
EVENT_SWEEPING_STRIKES = 1,
EVENT_SINISTER_STRIKE,
EVENT_GOUGE,
EVENT_KICK,
EVENT_BLIND,
};
// Zealot Zath
class npc_zealot_zath : public CreatureScript
{
@@ -428,139 +515,82 @@ class npc_zealot_zath : public CreatureScript
struct npc_zealot_zathAI : public ScriptedAI
{
npc_zealot_zathAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript())
{
Initialize();
}
void Initialize()
{
_sweepingStrikesTimer = 13000;
_sinisterStrikeTimer = 8000;
_gougeTimer = 25000;
_kickTimer = 18000;
_blindTimer = 5000;
_checkTimer = 10000;
_fakeDeath = false;
}
npc_zealot_zathAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
Initialize();
_events.Reset();
me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
}
_instance->SetBossState(DATA_ZATH, NOT_STARTED);
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (damage >= me->GetHealth())
{
Talk(TALK_FAKE_DEATH);
me->RemoveAllAuras();
me->SetImmuneToPC(true, true);
me->SetImmuneToNPC(true, true);
DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH, true);
me->AttackStop();
if (Creature* thekal = _instance->GetCreature(DATA_THEKAL))
thekal->AI()->SetData(DATA_FAKE_DEATH, me->GetEntry());
_events.DelayEvents(10s);
damage = 0;
}
}
me->SetStandState(UNIT_STAND_STATE_STAND);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_SWEEPING_STRIKES, 13s);
_events.ScheduleEvent(EVENT_SINISTER_STRIKE, 8s);
_events.ScheduleEvent(EVENT_GOUGE, 25s);
_events.ScheduleEvent(EVENT_KICK, 18s);
_events.ScheduleEvent(EVENT_BLIND, 5s);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SWEEPING_STRIKES:
DoCastVictim(SPELL_SWEEPINGSTRIKES);
_events.ScheduleEvent(EVENT_SWEEPING_STRIKES, 22s, 26s);
break;
case EVENT_SINISTER_STRIKE:
DoCastVictim(SPELL_SINISTERSTRIKE);
_events.ScheduleEvent(EVENT_SINISTER_STRIKE, 8s, 16s);
break;
case EVENT_GOUGE:
DoCastVictim(SPELL_GOUGE);
if (GetThreat(me->GetVictim()))
ModifyThreatByPercent(me->GetVictim(), -100);
_events.ScheduleEvent(EVENT_GOUGE, 17s, 27s);
break;
case EVENT_KICK:
DoCastVictim(SPELL_KICK);
_events.ScheduleEvent(EVENT_KICK, 15s, 25s);
break;
case EVENT_BLIND:
DoCastVictim(SPELL_BLIND);
_events.ScheduleEvent(EVENT_BLIND, 10s, 20s);
break;
}
}
if (!UpdateVictim())
return;
if (_sweepingStrikesTimer <= diff)
{
DoCastVictim(SPELL_SWEEPINGSTRIKES);
_sweepingStrikesTimer = 22000 + rand32() % 4000;
}
else
_sweepingStrikesTimer -= diff;
if (_sinisterStrikeTimer <= diff)
{
DoCastVictim(SPELL_SINISTERSTRIKE);
_sinisterStrikeTimer = 8000 + rand32() % 8000;
}
else
_sinisterStrikeTimer -= diff;
if (_gougeTimer <= diff)
{
DoCastVictim(SPELL_GOUGE);
if (GetThreat(me->GetVictim()))
ModifyThreatByPercent(me->GetVictim(), -100);
_gougeTimer = 17000 + rand32() % 10000;
}
else
_gougeTimer -= diff;
if (_kickTimer <= diff)
{
DoCastVictim(SPELL_KICK);
_kickTimer = 15000 + rand32() % 10000;
}
else
_kickTimer -= diff;
if (_blindTimer <= diff)
{
DoCastVictim(SPELL_BLIND);
_blindTimer = 10000 + rand32() % 10000;
}
else
_blindTimer -= diff;
// Check for the death of LorKhan and Thekal.
if (!_fakeDeath && _checkTimer <= diff)
{
if (_instance->GetBossState(DATA_LORKHAN) == SPECIAL)
{
// Resurrect LorKhan
if (Creature* lorkhan = _instance->GetCreature(DATA_LORKHAN))
{
lorkhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
lorkhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
lorkhan->SetFaction(14);
lorkhan->SetFullHealth();
}
}
if (_instance->GetBossState(DATA_THEKAL) == SPECIAL)
{
// Resurrect Thekal
if (Creature* thekal = _instance->GetCreature(DATA_THEKAL))
{
thekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
thekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
thekal->SetFaction(FACTION_MONSTER);
thekal->SetFullHealth();
}
}
_checkTimer = 5000;
}
else
_checkTimer -= diff;
if (!HealthAbovePct(5))
{
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
me->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_SLEEP);
me->SetFaction(35);
me->AttackStop();
_instance->SetBossState(DATA_ZATH, SPECIAL);
_fakeDeath = true;
}
DoMeleeAttackIfReady();
}
private:
uint32 _sweepingStrikesTimer;
uint32 _sinisterStrikeTimer;
uint32 _gougeTimer;
uint32 _kickTimer;
uint32 _blindTimer;
uint32 _checkTimer;
bool _fakeDeath;
EventMap _events;
InstanceScript* _instance;
};