mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-28 08:06:23 +00:00
546 lines
21 KiB
C++
546 lines
21 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2
|
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*/
|
|
|
|
/* ScriptData
|
|
SDName: Boss_Thekal
|
|
SD%Complete: 95
|
|
SDComment: Almost finished.
|
|
SDCategory: Zul'Gurub
|
|
EndScriptData */
|
|
|
|
#include "ScriptMgr.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "zulgurub.h"
|
|
|
|
enum Says
|
|
{
|
|
SAY_AGGRO = 0,
|
|
SAY_DEATH = 1
|
|
};
|
|
|
|
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_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
|
|
};
|
|
|
|
enum Events
|
|
{
|
|
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
|
|
};
|
|
|
|
enum Phases
|
|
{
|
|
PHASE_ONE = 1,
|
|
PHASE_TWO = 2
|
|
};
|
|
|
|
class boss_thekal : public CreatureScript
|
|
{
|
|
public: boss_thekal() : CreatureScript("boss_thekal") { }
|
|
|
|
struct boss_thekalAI : public BossAI
|
|
{
|
|
boss_thekalAI(Creature* creature) : BossAI(creature, DATA_THEKAL) { }
|
|
|
|
bool Enraged;
|
|
bool WasDead;
|
|
|
|
void Reset()
|
|
{
|
|
if (events.IsInPhase(PHASE_TWO))
|
|
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
|
|
_Reset();
|
|
Enraged = false;
|
|
WasDead = false;
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
_JustDied();
|
|
Talk(SAY_DEATH);
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/)
|
|
{
|
|
_EnterCombat();
|
|
events.ScheduleEvent(EVENT_MORTALCLEAVE, 4000, 0, PHASE_ONE); // Phase 1
|
|
events.ScheduleEvent(EVENT_SILENCE, 9000, 0, PHASE_ONE); // Phase 1
|
|
events.ScheduleEvent(EVENT_CHECK_TIMER, 10000, 0, PHASE_ONE); // Phase 1
|
|
events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10000, 0, PHASE_ONE); // Phase 1
|
|
Talk(SAY_AGGRO);
|
|
}
|
|
|
|
void JustReachedHome()
|
|
{
|
|
instance->SetBossState(DATA_THEKAL, NOT_STARTED);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
events.Update(diff);
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
while (uint32 eventId = events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_MORTALCLEAVE:
|
|
DoCastVictim(SPELL_MORTALCLEAVE, true);
|
|
events.ScheduleEvent(EVENT_MORTALCLEAVE, urand(15000, 20000), 0, PHASE_ONE);
|
|
break;
|
|
case EVENT_SILENCE:
|
|
DoCastVictim(SPELL_SILENCE, true);
|
|
events.ScheduleEvent(EVENT_SILENCE, urand(20000, 25000), 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);
|
|
/*
|
|
const CreatureTemplate* 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->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 40.0f, true); // hack
|
|
DoResetThreat();
|
|
events.ScheduleEvent(EVENT_FRENZY, 30000, 0, PHASE_TWO); // Phase 2
|
|
events.ScheduleEvent(EVENT_FORCEPUNCH, 4000, 0, PHASE_TWO); // Phase 2
|
|
events.ScheduleEvent(EVENT_SPELL_CHARGE, 12000, 0, PHASE_TWO); // Phase 2
|
|
events.ScheduleEvent(EVENT_ENRAGE, 32000, 0, PHASE_TWO); // Phase 2
|
|
events.ScheduleEvent(EVENT_SUMMONTIGERS, 25000, 0, PHASE_TWO); // Phase 2
|
|
events.SetPhase(PHASE_TWO);
|
|
}
|
|
events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10000, 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 (Unit* pLorKhan = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_LORKHAN)))
|
|
{
|
|
pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pLorKhan->setFaction(14);
|
|
pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pLorKhan->SetFullHealth();
|
|
instance->SetData(DATA_LORKHAN, DONE);
|
|
}
|
|
}
|
|
|
|
if (instance->GetBossState(DATA_ZATH) == SPECIAL)
|
|
{
|
|
//Resurrect Zath
|
|
if (Unit* pZath = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_ZATH)))
|
|
{
|
|
pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pZath->setFaction(14);
|
|
pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pZath->SetFullHealth();
|
|
instance->SetBossState(DATA_ZATH, DONE);
|
|
}
|
|
}
|
|
}
|
|
events.ScheduleEvent(EVENT_CHECK_TIMER, 5000, 0, PHASE_ONE);
|
|
break;
|
|
case EVENT_FRENZY:
|
|
DoCast(me, SPELL_FRENZY);
|
|
events.ScheduleEvent(EVENT_FRENZY, 30000, 0, PHASE_TWO);
|
|
break;
|
|
case EVENT_FORCEPUNCH:
|
|
DoCastVictim(SPELL_FORCEPUNCH, true);
|
|
events.ScheduleEvent(EVENT_FORCEPUNCH, urand(16000, 21000), 0, PHASE_TWO);
|
|
break;
|
|
case EVENT_CHARGE:
|
|
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
|
{
|
|
DoCast(target, SPELL_CHARGE);
|
|
DoResetThreat();
|
|
AttackStart(target);
|
|
}
|
|
events.ScheduleEvent(EVENT_CHARGE, urand(15000, 22000), 0, PHASE_TWO);
|
|
break;
|
|
case EVENT_ENRAGE:
|
|
if (HealthBelowPct(11) && !Enraged)
|
|
{
|
|
DoCast(me, SPELL_ENRAGE);
|
|
Enraged = true;
|
|
}
|
|
events.ScheduleEvent(EVENT_ENRAGE, 30000);
|
|
break;
|
|
case EVENT_SUMMONTIGERS:
|
|
DoCastVictim(SPELL_SUMMONTIGERS, true);
|
|
events.ScheduleEvent(EVENT_SUMMONTIGERS, urand(10000, 14000), 0, PHASE_TWO);
|
|
break;
|
|
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;
|
|
}
|
|
}
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetInstanceAI<boss_thekalAI>(creature);
|
|
}
|
|
};
|
|
|
|
//Zealot Lor'Khan
|
|
class npc_zealot_lorkhan : public CreatureScript
|
|
{
|
|
public: npc_zealot_lorkhan() : CreatureScript("npc_zealot_lorkhan") { }
|
|
|
|
struct npc_zealot_lorkhanAI : public ScriptedAI
|
|
{
|
|
npc_zealot_lorkhanAI(Creature* creature) : ScriptedAI(creature)
|
|
{
|
|
instance = creature->GetInstanceScript();
|
|
}
|
|
|
|
uint32 Shield_Timer;
|
|
uint32 BloodLust_Timer;
|
|
uint32 GreaterHeal_Timer;
|
|
uint32 Disarm_Timer;
|
|
uint32 Check_Timer;
|
|
|
|
bool FakeDeath;
|
|
|
|
InstanceScript* instance;
|
|
|
|
void Reset()
|
|
{
|
|
Shield_Timer = 1000;
|
|
BloodLust_Timer = 16000;
|
|
GreaterHeal_Timer = 32000;
|
|
Disarm_Timer = 6000;
|
|
Check_Timer = 10000;
|
|
|
|
FakeDeath = false;
|
|
|
|
instance->SetBossState(DATA_LORKHAN, NOT_STARTED);
|
|
|
|
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/)
|
|
{
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
//Shield_Timer
|
|
if (Shield_Timer <= diff)
|
|
{
|
|
DoCast(me, SPELL_SHIELD);
|
|
Shield_Timer = 61000;
|
|
} else Shield_Timer -= diff;
|
|
|
|
//BloodLust_Timer
|
|
if (BloodLust_Timer <= diff)
|
|
{
|
|
DoCast(me, SPELL_BLOODLUST);
|
|
BloodLust_Timer = 20000+rand()%8000;
|
|
} else BloodLust_Timer -= diff;
|
|
|
|
//Casting Greaterheal to Thekal or Zath if they are in meele range.
|
|
if (GreaterHeal_Timer <= diff)
|
|
{
|
|
Unit* pThekal = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_THEKAL));
|
|
Unit* pZath = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_ZATH));
|
|
|
|
if (!pThekal || !pZath)
|
|
return;
|
|
|
|
switch (urand(0, 1))
|
|
{
|
|
case 0:
|
|
if (me->IsWithinMeleeRange(pThekal))
|
|
DoCast(pThekal, SPELL_GREATERHEAL);
|
|
break;
|
|
case 1:
|
|
if (me->IsWithinMeleeRange(pZath))
|
|
DoCast(pZath, SPELL_GREATERHEAL);
|
|
break;
|
|
}
|
|
|
|
GreaterHeal_Timer = 15000+rand()%5000;
|
|
} else GreaterHeal_Timer -= diff;
|
|
|
|
//Disarm_Timer
|
|
if (Disarm_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_DISARM);
|
|
Disarm_Timer = 15000+rand()%10000;
|
|
} else Disarm_Timer -= diff;
|
|
|
|
//Check_Timer for the death of LorKhan and Zath.
|
|
if (!FakeDeath && Check_Timer <= diff)
|
|
{
|
|
if (instance->GetBossState(DATA_THEKAL) == SPECIAL)
|
|
{
|
|
//Resurrect Thekal
|
|
if (Unit* pThekal = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_THEKAL)))
|
|
{
|
|
pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pThekal->setFaction(14);
|
|
pThekal->SetFullHealth();
|
|
}
|
|
}
|
|
|
|
if (instance->GetBossState(DATA_ZATH) == SPECIAL)
|
|
{
|
|
//Resurrect Zath
|
|
if (Unit* pZath = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_ZATH)))
|
|
{
|
|
pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pZath->setFaction(14);
|
|
pZath->SetFullHealth();
|
|
}
|
|
}
|
|
|
|
Check_Timer = 5000;
|
|
} else Check_Timer -= 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_LORKHAN, SPECIAL);
|
|
|
|
FakeDeath = true;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetInstanceAI<npc_zealot_lorkhanAI>(creature);
|
|
}
|
|
};
|
|
|
|
//Zealot Zath
|
|
class npc_zealot_zath : public CreatureScript
|
|
{
|
|
public:
|
|
|
|
npc_zealot_zath()
|
|
: CreatureScript("npc_zealot_zath")
|
|
{
|
|
}
|
|
|
|
struct npc_zealot_zathAI : public ScriptedAI
|
|
{
|
|
npc_zealot_zathAI(Creature* creature) : ScriptedAI(creature)
|
|
{
|
|
instance = creature->GetInstanceScript();
|
|
}
|
|
|
|
uint32 SweepingStrikes_Timer;
|
|
uint32 SinisterStrike_Timer;
|
|
uint32 Gouge_Timer;
|
|
uint32 Kick_Timer;
|
|
uint32 Blind_Timer;
|
|
uint32 Check_Timer;
|
|
|
|
bool FakeDeath;
|
|
|
|
InstanceScript* instance;
|
|
|
|
void Reset()
|
|
{
|
|
SweepingStrikes_Timer = 13000;
|
|
SinisterStrike_Timer = 8000;
|
|
Gouge_Timer = 25000;
|
|
Kick_Timer = 18000;
|
|
Blind_Timer = 5000;
|
|
Check_Timer = 10000;
|
|
|
|
FakeDeath = false;
|
|
|
|
instance->SetBossState(DATA_ZATH, NOT_STARTED);
|
|
|
|
me->SetStandState(UNIT_STAND_STATE_STAND);
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/)
|
|
{
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
//SweepingStrikes_Timer
|
|
if (SweepingStrikes_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_SWEEPINGSTRIKES);
|
|
SweepingStrikes_Timer = 22000+rand()%4000;
|
|
} else SweepingStrikes_Timer -= diff;
|
|
|
|
//SinisterStrike_Timer
|
|
if (SinisterStrike_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_SINISTERSTRIKE);
|
|
SinisterStrike_Timer = 8000+rand()%8000;
|
|
} else SinisterStrike_Timer -= diff;
|
|
|
|
//Gouge_Timer
|
|
if (Gouge_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_GOUGE);
|
|
|
|
if (DoGetThreat(me->GetVictim()))
|
|
DoModifyThreatPercent(me->GetVictim(), -100);
|
|
|
|
Gouge_Timer = 17000+rand()%10000;
|
|
} else Gouge_Timer -= diff;
|
|
|
|
//Kick_Timer
|
|
if (Kick_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_KICK);
|
|
Kick_Timer = 15000+rand()%10000;
|
|
} else Kick_Timer -= diff;
|
|
|
|
//Blind_Timer
|
|
if (Blind_Timer <= diff)
|
|
{
|
|
DoCastVictim(SPELL_BLIND);
|
|
Blind_Timer = 10000+rand()%10000;
|
|
} else Blind_Timer -= diff;
|
|
|
|
//Check_Timer for the death of LorKhan and Zath.
|
|
if (!FakeDeath && Check_Timer <= diff)
|
|
{
|
|
if (instance->GetBossState(DATA_LORKHAN) == SPECIAL)
|
|
{
|
|
//Resurrect LorKhan
|
|
if (Unit* pLorKhan = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_LORKHAN)))
|
|
{
|
|
pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pLorKhan->setFaction(14);
|
|
pLorKhan->SetFullHealth();
|
|
}
|
|
}
|
|
|
|
if (instance->GetBossState(DATA_THEKAL) == SPECIAL)
|
|
{
|
|
//Resurrect Thekal
|
|
if (Unit* pThekal = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_THEKAL)))
|
|
{
|
|
pThekal->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
|
pThekal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
|
pThekal->setFaction(14);
|
|
pThekal->SetFullHealth();
|
|
}
|
|
}
|
|
|
|
Check_Timer = 5000;
|
|
} else Check_Timer -= 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();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return GetInstanceAI<npc_zealot_zathAI>(creature);
|
|
}
|
|
};
|
|
|
|
void AddSC_boss_thekal()
|
|
{
|
|
new boss_thekal();
|
|
new npc_zealot_lorkhan();
|
|
new npc_zealot_zath();
|
|
}
|