Files
azerothcore-wotlk/src/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp
2016-08-17 17:58:45 +02:00

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();
}