mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-18 00:18:43 +01:00
Script/ZulGurub: rewrite High Priest Thekal's encounter script (#23429)
This commit is contained in:
7
sql/updates/world/3.3.5/2019_06_27_03_world.sql
Normal file
7
sql/updates/world/3.3.5/2019_06_27_03_world.sql
Normal 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");
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user