/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "CreatureScript.h"
#include "GameObjectScript.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "zulgurub.h"
enum Says
{
SAY_AGGRO = 0,
SAY_FEAST_PROWLER = 1,
SAY_DEATH = 2
};
enum Spells
{
SPELL_SHADOW_WORD_PAIN = 24212, // Corrected
SPELL_GOUGE = 12540, // Corrected
SPELL_MARK_OF_ARLOKK = 24210, // triggered spell 24211 Added to spell_dbc
SPELL_RAVAGE = 24213, // Corrected
SPELL_CLEAVE = 25174, // Searching for right spell
SPELL_PANTHER_TRANSFORM = 24190, // Transform to panther now used
SPELL_SUMMON_PROWLER = 24246, // Added to Spell_dbc
SPELL_VANISH_VISUAL = 24222, // Added
SPELL_VANISH = 24223, // Added
SPELL_SUPER_INVIS = 24235 // Added to Spell_dbc
};
enum Events
{
EVENT_SHADOW_WORD_PAIN = 1,
EVENT_GOUGE = 2,
EVENT_MARK_OF_ARLOKK = 3,
EVENT_RAVAGE = 4,
EVENT_TRANSFORM = 5,
EVENT_VANISH = 6,
EVENT_VANISH_2 = 7,
EVENT_TRANSFORM_BACK = 8,
EVENT_VISIBLE = 9,
EVENT_SUMMON_PROWLERS = 10
};
enum Phases
{
PHASE_ALL = 0,
PHASE_ONE = 1,
PHASE_TWO = 2
};
enum Weapon
{
WEAPON_DAGGER = 10616
};
enum Misc
{
MAX_PROWLERS_PER_SIDE = 15
};
Position const PosMoveOnSpawn[1] =
{
{ -11561.9f, -1627.868f, 41.29941f, 0.0f }
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
class boss_arlokk : public CreatureScript
{
public:
boss_arlokk() : CreatureScript("boss_arlokk") { }
struct boss_arlokkAI : public BossAI
{
boss_arlokkAI(Creature* creature) : BossAI(creature, DATA_ARLOKK) { }
void Reset() override
{
if (events.IsInPhase(PHASE_TWO))
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
_Reset();
_summonCountA = 0;
_summonCountB = 0;
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
me->SetWalk(false);
me->SetHomePosition(PosMoveOnSpawn[0]);
me->GetMotionMaster()->MoveTargetedHome();
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 7s, 9s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, 12s, 15s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6s, 0, PHASE_ALL);
events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, 9s, 11s, 0, PHASE_ALL);
events.ScheduleEvent(EVENT_TRANSFORM, 30s, 0, PHASE_ONE);
Talk(SAY_AGGRO);
// Sets up list of Panther spawners to cast on
std::list triggerList;
GetCreatureListWithEntryInGrid(triggerList, me, NPC_PANTHER_TRIGGER, 100.0f);
if (!triggerList.empty())
{
uint8 sideA = 0;
uint8 sideB = 0;
for (auto const& trigger : triggerList)
{
if (trigger->GetPositionY() < -1625.0f)
{
_triggersSideAGUID[sideA] = trigger->GetGUID();
++sideA;
}
else
{
_triggersSideBGUID[sideB] = trigger->GetGUID();
++sideB;
}
}
}
}
void JustReachedHome() override
{
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_GONG_OF_BETHEKK)))
object->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
me->DespawnOrUnsummon();
}
void EnterEvadeMode(EvadeReason why) override
{
BossAI::EnterEvadeMode(why);
std::list panthers;
GetCreatureListWithEntryInGrid(panthers, me, NPC_ZULIAN_PROWLER, 200.f);
for (auto const& panther : panthers)
panther->DespawnOrUnsummon();
}
void SetData(uint32 id, uint32 /*value*/) override
{
if (id == 1)
--_summonCountA;
else if (id == 2)
--_summonCountB;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADOW_WORD_PAIN:
DoCastVictim(SPELL_SHADOW_WORD_PAIN, true);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 5s, 7s, 0, PHASE_ONE);
break;
case EVENT_GOUGE:
DoCastVictim(SPELL_GOUGE, true);
break;
case EVENT_SUMMON_PROWLERS:
if (_summonCountA < MAX_PROWLERS_PER_SIDE)
{
if (Unit* trigger = ObjectAccessor::GetUnit(*me, _triggersSideAGUID[urand(0, 4)]))
{
trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER);
++_summonCountA;
}
}
if (_summonCountB < MAX_PROWLERS_PER_SIDE)
{
if (Unit* trigger = ObjectAccessor::GetUnit(*me, _triggersSideBGUID[urand(0, 4)]))
{
trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER);
++_summonCountB;
}
}
events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6s, 0, PHASE_ALL);
break;
case EVENT_MARK_OF_ARLOKK:
{
Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, urand(1, 3), 0.0f, false, true, -SPELL_MARK_OF_ARLOKK);
if (!target)
target = me->GetVictim();
if (target)
{
DoCast(target, SPELL_MARK_OF_ARLOKK, true);
Talk(SAY_FEAST_PROWLER, target);
}
events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, 120s, 130s);
break;
}
case EVENT_TRANSFORM:
{
DoCastSelf(SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(EQUIP_UNEQUIP));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(EQUIP_UNEQUIP));
me->AttackStop();
DoResetThreatList();
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
DoCastSelf(SPELL_VANISH_VISUAL);
DoCastSelf(SPELL_VANISH);
events.ScheduleEvent(EVENT_VANISH, 1s, 0, PHASE_ONE);
break;
}
case EVENT_VANISH:
DoCastSelf(SPELL_SUPER_INVIS);
me->SetWalk(false);
me->GetMotionMaster()->MovePoint(0, frand(-11551.0f, -11508.0f), frand(-1638.0f, -1617.0f), me->GetPositionZ());
events.ScheduleEvent(EVENT_VANISH_2, 9s, 0, PHASE_ONE);
break;
case EVENT_VANISH_2:
DoCastSelf(SPELL_VANISH);
DoCastSelf(SPELL_SUPER_INVIS);
events.ScheduleEvent(EVENT_VISIBLE, 41s, 47s, 0, PHASE_ONE);
break;
case EVENT_VISIBLE:
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
AttackStart(target);
me->RemoveAura(SPELL_SUPER_INVIS);
me->RemoveAura(SPELL_VANISH);
events.ScheduleEvent(EVENT_RAVAGE, 10s, 14s, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 30s, 40s, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease); // hack
break;
case EVENT_RAVAGE:
DoCastVictim(SPELL_RAVAGE, true);
events.ScheduleEvent(EVENT_RAVAGE, 10s, 14s, 0, PHASE_TWO);
break;
case EVENT_TRANSFORM_BACK:
{
me->RemoveAura(SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
DoCast(me, SPELL_VANISH_VISUAL);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 4s, 7s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, 12s, 15s, 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, 30s, 0, PHASE_ONE);
events.SetPhase(PHASE_ONE);
break;
}
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
uint8 _summonCountA;
uint8 _summonCountB;
ObjectGuid _triggersSideAGUID[5];
ObjectGuid _triggersSideBGUID[5];
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI(creature);
}
};
/*######
## npc_zulian_prowler
######*/
enum ZulianProwlerSpells
{
SPELL_SNEAK_RANK_1_1 = 22766,
SPELL_SNEAK_RANK_1_2 = 7939, // Added to Spell_dbc
SPELL_MARK_OF_ARLOKK_TRIGGER = 24211 // Added to Spell_dbc
};
enum ZulianProwlerEvents
{
EVENT_ATTACK = 1
};
class npc_zulian_prowler : public CreatureScript
{
public:
npc_zulian_prowler() : CreatureScript("npc_zulian_prowler") { }
struct npc_zulian_prowlerAI : public ScriptedAI
{
npc_zulian_prowlerAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
void Reset() override
{
if (me->GetPositionY() < -1625.0f)
_sideData = 1;
else
_sideData = 2;
DoCast(me, SPELL_SNEAK_RANK_1_1);
DoCast(me, SPELL_SNEAK_RANK_1_2);
if (Unit* arlokk = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(NPC_ARLOKK)))
me->GetMotionMaster()->MovePoint(0, arlokk->GetPositionX(), arlokk->GetPositionY(), arlokk->GetPositionZ());
_events.ScheduleEvent(EVENT_ATTACK, 6s);
}
void JustEngagedWith(Unit* /*who*/) override
{
me->GetMotionMaster()->Clear(false);
me->RemoveAura(SPELL_SNEAK_RANK_1_1);
me->RemoveAura(SPELL_SNEAK_RANK_1_2);
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id == SPELL_MARK_OF_ARLOKK_TRIGGER) // Should only hit if line of sight
{
AttackStart(caster);
}
}
void JustDied(Unit* /*killer*/) override
{
if (Unit* arlokk = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(NPC_ARLOKK)))
{
if (arlokk->IsAlive())
arlokk->GetAI()->SetData(_sideData, 0);
}
me->DespawnOrUnsummon(4s);
}
void UpdateAI(uint32 diff) override
{
if (UpdateVictim())
{
DoMeleeAttackIfReady();
return;
}
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ATTACK:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0.0f, 100, false))
{
AttackStart(target);
}
break;
default:
break;
}
}
}
private:
int32 _sideData;
EventMap _events;
InstanceScript* _instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI(creature);
}
};
/*######
## go_gong_of_bethekk
######*/
Position const PosSummonArlokk[1] =
{
{ -11507.22f, -1628.062f, 41.38264f, 3.159046f }
};
class go_gong_of_bethekk : public GameObjectScript
{
public:
go_gong_of_bethekk() : GameObjectScript("go_gong_of_bethekk") { }
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
if (go->GetInstanceScript() && !go->FindNearestCreature(NPC_ARLOKK, 25.0f))
{
go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
go->SendCustomAnim(0);
go->SummonCreature(NPC_ARLOKK, PosSummonArlokk[0], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 600000);
}
return true;
}
};
void AddSC_boss_arlokk()
{
new boss_arlokk();
new npc_zulian_prowler();
new go_gong_of_bethekk();
}