Skip to content

Instantly share code, notes, and snippets.

@Keader
Last active July 4, 2016 01:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Keader/30fef24fde8f0823dc13bede6d42642c to your computer and use it in GitHub Desktop.
Save Keader/30fef24fde8f0823dc13bede6d42642c to your computer and use it in GitHub Desktop.
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "PassiveAI.h"
#include "ScriptedGossip.h"
#include "GridNotifiers.h"
#include "black_temple.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
/* Coisas a fazer:
Formula do slow
Movimento dos Trash mobs da sala do Akama
*/
enum Says
{
// Akama ending little event texts
SAY_BROKEN_FREE_0 = 0,
SAY_BROKEN_FREE_1 = 1,
SAY_BROKEN_FREE_2 = 2,
SAY_LOW_HEALTH = 3,
SAY_DEAD = 4,
// Ashtongue Broken
SAY_BROKEN_SPECIAL = 0,
SAY_BROKEN_HAIL = 1,
};
enum Spells
{
// Akama
SPELL_STEALTH = 34189,
SPELL_AKAMA_SOUL_CHANNEL = 40447,
SPELL_FIXATE = 40607,
SPELL_CHAIN_LIGHTNING = 39945,
SPELL_DESTRUCTIVE_POISON = 40874,
SPELL_AKAMA_SOUL_EXPEL = 40902,
// Shade
SPELL_THREAT = 41602,
SPELL_SHADE_OF_AKAMA_TRIGGER = 40955,
SPELL_AKAMA_SOUL_EXPEL_CHANNEL = 40927,
// Ashtongue Channeler
SPELL_SHADE_SOUL_CHANNEL = 40401,
SPELL_SHADE_SOUL_CHANNEL_2 = 40520,
// Creature Spawner
SPELL_ASHTONGUE_WAVE_B = 42035,
SPELL_SUMMON_ASHTONGUE_SORCERER = 40476,
SPELL_SUMMON_ASHTONGUE_DEFENDER = 40474,
// Ashtongue Defender
SPELL_DEBILITATING_STRIKE = 41178,
SPELL_HEROIC_STRIKE = 41975,
SPELL_SHIELD_BASH = 41180,
SPELL_WINDFURY = 38229,
// Ashtongue Rogue
SPELL_DEBILITATING_POISON = 41978,
SPELL_EVISCERATE = 41177,
// Ashtongue Elementalist
SPELL_RAIN_OF_FIRE = 42023,
SPELL_LIGHTNING_BOLT = 42024,
// Ashtongue Spiritbinder
SPELL_SPIRIT_MEND = 42025,
SPELL_CHAIN_HEAL = 42027,
SPELL_SPIRITBINDER_SPIRIT_HEAL = 42317
};
enum Creatures
{
NPC_ASHTONGUE_CHANNELER = 23421,
NPC_ASHTONGUE_SORCERER = 23215,
NPC_ASHTONGUE_DEFENDER = 23216,
NPC_ASHTONGUE_ELEMENTALIST = 23523,
NPC_ASHTONGUE_ROGUE = 23318,
NPC_ASHTONGUE_SPIRITBINDER = 23524,
NPC_ASHTONGUE_BROKEN = 23319,
NPC_CREATURE_SPAWNER_AKAMA = 23210,
};
enum Factions
{
FACTION_FRIENDLY = 1820,
FACTION_COMBAT = 1868
};
enum Actions
{
ACTION_START_SPAWNING = 0,
ACTION_STOP_SPAWNING = 1,
ACTION_DESPAWN_ALL_SPAWNS = 2,
ACTION_AKAMA_DEAD = 3,
ACTION_SHADE_OF_AKAMA_DEAD = 4,
ACTION_BROKEN_SPECIAL = 5,
ACTION_BROKEN_EMOTE = 6,
ACTION_BROKEN_HAIL = 7,
};
enum Events
{
// Akama
EVENT_SHADE_START = 1,
EVENT_SHADE_CHANNEL = 2,
EVENT_FIXATE = 3,
EVENT_CHAIN_LIGHTNING = 4,
EVENT_DESTRUCTIVE_POISON = 5,
EVENT_START_BROKEN_FREE = 6,
EVENT_BROKEN_FREE_1 = 7,
EVENT_BROKEN_FREE_2 = 8,
EVENT_BROKEN_FREE_3 = 9,
EVENT_BROKEN_FREE_4 = 10,
// Shade of Akama
EVENT_INITIALIZE_SPAWNERS = 11,
EVENT_START_CHANNELERS_AND_SPAWNERS = 12,
EVENT_ADD_THREAT = 13,
// Creature spawner
EVENT_SPAWN_WAVE_B = 14,
EVENT_SUMMON_ASHTONGUE_SORCERER = 15,
EVENT_SUMMON_ASHTONGUE_DEFENDER = 16,
// Ashtongue Defender
EVENT_DEBILITATING_STRIKE = 17,
EVENT_HEROIC_STRIKE = 18,
EVENT_SHIELD_BASH = 19,
EVENT_WINDFURY = 20,
// Ashtongue Rogue
EVENT_DEBILITATING_POISON = 21,
EVENT_EVISCERATE = 22,
// Ashtongue Elementalist
EVENT_RAIN_OF_FIRE = 23,
EVENT_LIGHTNING_BOLT = 24,
// Ashtongue Spiritbinder
EVENT_SPIRIT_HEAL = 25,
EVENT_SPIRIT_MEND_RESET = 26,
EVENT_CHAIN_HEAL_RESET = 27,
//Misc
EVENT_EVADE_CHECK = 28
};
enum Misc
{
AKAMA_CHANNEL_WAYPOINT = 0,
AKAMA_INTRO_WAYPOINT = 1,
SUMMON_GROUP_RESET = 1
};
G3D::Vector3 const AkamaWP[] =
{
{ 517.4877f, 400.7993f, 112.7837f },
{ 468.4435f, 401.1062f, 118.5379f }
};
G3D::Vector4 const BrokenPos[] =
{
{ 495.5628f, 462.7089f, 112.8169f, 4.1808090f },
{ 498.3421f, 463.8384f, 112.8673f, 4.5634810f },
{ 501.6708f, 463.8806f, 112.8673f, 3.7157850f },
{ 532.4264f, 448.4718f, 112.8563f, 3.9813020f },
{ 532.9113f, 451.6227f, 112.8671f, 4.6479530f },
{ 532.8243f, 453.9475f, 112.8671f, 4.7032810f },
{ 521.5317f, 402.3790f, 112.8671f, 3.1138120f },
{ 521.9184f, 404.6848f, 112.8671f, 4.0787760f },
{ 522.4290f, 406.5160f, 112.8671f, 3.3869470f },
{ 521.0833f, 393.1852f, 112.8611f, 3.0750830f },
{ 521.9014f, 395.6381f, 112.8671f, 4.0157140f },
{ 522.2610f, 397.7423f, 112.8671f, 3.4417790f },
{ 532.4565f, 345.3987f, 112.8585f, 1.7232640f },
{ 532.5565f, 346.8792f, 112.8671f, 1.8325960f },
{ 532.5491f, 348.6840f, 112.8671f, 0.2054047f },
{ 501.4669f, 338.5967f, 112.8504f, 1.7038430f },
{ 499.0937f, 337.9894f, 112.8673f, 1.8586250f },
{ 496.8722f, 338.0152f, 112.8673f, 0.5428222f }
};
G3D::Vector3 const BrokenWP[] =
{
{ 479.1884f, 434.8635f, 112.7838f },
{ 479.7349f, 435.9843f, 112.7838f },
{ 480.5328f, 436.8310f, 112.7838f },
{ 493.1714f, 420.1136f, 112.7838f },
{ 494.7830f, 417.4830f, 112.7838f },
{ 492.9280f, 423.1891f, 112.7838f },
{ 491.8618f, 403.2035f, 112.7838f },
{ 491.7784f, 400.2046f, 112.7838f },
{ 491.9451f, 406.2023f, 112.7838f },
{ 488.3535f, 395.3652f, 112.7838f },
{ 488.8324f, 392.3267f, 112.7838f },
{ 489.2300f, 398.3135f, 112.7838f },
{ 491.9286f, 383.0433f, 112.7838f },
{ 491.1526f, 380.0966f, 112.7839f },
{ 493.6747f, 385.5407f, 112.7838f },
{ 476.2499f, 369.0865f, 112.7839f },
{ 473.7637f, 367.8766f, 112.7839f },
{ 478.8986f, 370.1895f, 112.7839f }
};
class boss_shade_of_akama : public CreatureScript
{
public:
boss_shade_of_akama() : CreatureScript("boss_shade_of_akama") { }
struct boss_shade_of_akamaAI : public BossAI
{
boss_shade_of_akamaAI(Creature* creature) : BossAI(creature, DATA_SHADE_OF_AKAMA){}
void Initialize()
{
Spawners.clear();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STUN);
me->SetWalk(true);
}
void Reset() override
{
Initialize();
events.ScheduleEvent(EVENT_INITIALIZE_SPAWNERS, Seconds(1));
me->SummonCreatureGroup(SUMMON_GROUP_RESET);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
_Reset();
for (GuidVector::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
Spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS);
_DespawnAtEvade();
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_AKAMA_DEAD)
EnterEvadeMode(EVADE_REASON_OTHER);
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_AKAMA_SOUL_CHANNEL)
{
events.ScheduleEvent(EVENT_START_CHANNELERS_AND_SPAWNERS, Seconds(1));
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
events.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10));
if (Creature* Akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
{
AttackStart(Akama);
me->AddThreat(Akama, 100000.0f);
}
}
if (spell->Id == SPELL_AKAMA_SOUL_EXPEL)
DoCastSelf(SPELL_AKAMA_SOUL_EXPEL_CHANNEL);
}
void MoveInLineOfSight(Unit* who) override
{
if (who->GetGUID() == instance->GetGuidData(DATA_AKAMA_SHADE) && me->IsWithinMeleeRange(who))
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetWalk(false);
events.ScheduleEvent(EVENT_ADD_THREAT, Milliseconds(100));
for (GuidVector::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
Spawner->AI()->DoAction(ACTION_STOP_SPAWNING);
}
}
void JustDied(Unit* /*killer*/) override
{
DoCastSelf(SPELL_SHADE_OF_AKAMA_TRIGGER);
if (Creature* Akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
Akama->AI()->DoAction(ACTION_SHADE_OF_AKAMA_DEAD);
for (GuidVector::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
Spawner->AI()->DoAction(ACTION_DESPAWN_ALL_SPAWNS);
events.Reset();
summons.DespawnEntry(NPC_ASHTONGUE_CHANNELER);
instance->SetBossState(DATA_SHADE_OF_AKAMA, DONE);
}
void CheckIfNeedsToEvade()
{
Map::PlayerList const &players = me->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
if (Player* player = i->GetSource())
if (player->IsAlive() && !player->IsGameMaster())
return;
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
if (!UpdateVictim())
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_INITIALIZE_SPAWNERS:
{
std::list<Creature*> SpawnerList;
me->GetCreatureListWithEntryInGrid(SpawnerList, NPC_CREATURE_SPAWNER_AKAMA);
if (!SpawnerList.empty())
for (std::list<Creature*>::const_iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr)
Spawners.push_back((*itr)->GetGUID());
break;
}
case EVENT_START_CHANNELERS_AND_SPAWNERS:
{
if (!summons.empty())
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
if (Creature* Channeler = ObjectAccessor::GetCreature(*me, *itr))
Channeler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
for (GuidVector::const_iterator itr = Spawners.begin(); itr != Spawners.end(); ++itr)
if (Creature* Spawner = ObjectAccessor::GetCreature(*me, *itr))
Spawner->AI()->DoAction(ACTION_START_SPAWNING);
break;
}
case EVENT_ADD_THREAT:
DoCast(SPELL_THREAT);
events.ScheduleEvent(EVENT_ADD_THREAT, Seconds(3) + Milliseconds(500));
break;
case EVENT_EVADE_CHECK:
CheckIfNeedsToEvade();
events.ScheduleEvent(EVENT_EVADE_CHECK, Seconds(10));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
GuidVector Spawners;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<boss_shade_of_akamaAI>(creature);
}
};
class npc_akama_shade : public CreatureScript
{
public:
npc_akama_shade() : CreatureScript("npc_akama_shade") { }
struct npc_akamaAI : public ScriptedAI
{
npc_akamaAI(Creature* creature) : ScriptedAI(creature), Summons(me)
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
IsInCombat = false;
HasYelledOnce = false;
}
void Reset() override
{
Summons.DespawnAll();
events.Reset();
chosen.Clear();
me->setFaction(FACTION_FRIENDLY);
DoCastSelf(SPELL_STEALTH);
Initialize();
if (instance->GetBossState(DATA_SHADE_OF_AKAMA) != DONE)
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
}
void JustSummoned(Creature* summon) override
{
Summons.Summon(summon);
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_THREAT && !IsInCombat)
{
IsInCombat = true;
me->SetWalk(false);
me->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL);
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
{
Shade->RemoveAurasDueToSpell(SPELL_AKAMA_SOUL_CHANNEL);
AttackStart(Shade);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(2));
events.ScheduleEvent(EVENT_DESTRUCTIVE_POISON, Seconds(5));
}
}
}
void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override
{
if (me->HealthBelowPct(20) && !HasYelledOnce)
{
HasYelledOnce = true;
Talk(SAY_LOW_HEALTH);
}
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SHADE_OF_AKAMA_DEAD)
{
IsInCombat = false;
me->CombatStop(true);
me->setFaction(FACTION_FRIENDLY);
me->SetWalk(true);
events.CancelEvent(EVENT_CHAIN_LIGHTNING);
events.CancelEvent(EVENT_DESTRUCTIVE_POISON);
me->GetMotionMaster()->MovePoint(AKAMA_INTRO_WAYPOINT, AkamaWP[1].x, AkamaWP[1].y, AkamaWP[1].z);
}
}
void MovementInform(uint32 motionType, uint32 pointId) override
{
if (motionType != POINT_MOTION_TYPE)
return;
if (pointId == AKAMA_CHANNEL_WAYPOINT)
events.ScheduleEvent(EVENT_SHADE_CHANNEL, Seconds(1));
else if (pointId == AKAMA_INTRO_WAYPOINT)
{
me->SetWalk(false);
me->SetFacingTo(0.08726646f);
DoCast(SPELL_AKAMA_SOUL_EXPEL);
events.ScheduleEvent(EVENT_START_BROKEN_FREE, Seconds(15));
}
}
void SummonBrokens()
{
for (uint8 i = 0; i < 18; i++)
{
TempSummon* summoned = me->SummonCreature(NPC_ASHTONGUE_BROKEN, BrokenPos[i].x, BrokenPos[i].y, BrokenPos[i].z, BrokenPos[i].w);
summoned->SetWalk(true);
summoned->GetMotionMaster()->MovePoint(0, BrokenWP[i].x, BrokenWP[i].y, BrokenWP[i].z);
if (i == 9) //On Sniffs, npc that Yell "Special" is the tenth to be created
chosen = summoned->GetGUID();
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SHADE_START:
instance->SetBossState(DATA_SHADE_OF_AKAMA, IN_PROGRESS);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->RemoveAurasDueToSpell(SPELL_STEALTH);
me->SetWalk(true);
me->GetMotionMaster()->MovePoint(AKAMA_CHANNEL_WAYPOINT, AkamaWP[0].x, AkamaWP[0].y, AkamaWP[0].z, false);
break;
case EVENT_SHADE_CHANNEL:
me->SetFacingTo(3.118662f);
DoCastSelf(SPELL_AKAMA_SOUL_CHANNEL);
me->setFaction(FACTION_COMBAT);
events.ScheduleEvent(EVENT_FIXATE, Seconds(5));
break;
case EVENT_FIXATE:
DoCast(SPELL_FIXATE);
break;
case EVENT_CHAIN_LIGHTNING:
DoCastVictim(SPELL_CHAIN_LIGHTNING);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, randtime(Seconds(8), Seconds(15)));
break;
case EVENT_DESTRUCTIVE_POISON:
DoCastSelf(SPELL_DESTRUCTIVE_POISON);
events.ScheduleEvent(EVENT_DESTRUCTIVE_POISON, randtime(Seconds(3), Seconds(7)));
break;
case EVENT_START_BROKEN_FREE:
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
Talk(SAY_BROKEN_FREE_0);
SummonBrokens();
events.ScheduleEvent(EVENT_BROKEN_FREE_1, Seconds(10));
break;
case EVENT_BROKEN_FREE_1:
Talk(SAY_BROKEN_FREE_1);
events.ScheduleEvent(EVENT_BROKEN_FREE_2, Seconds(12));
break;
case EVENT_BROKEN_FREE_2:
Talk(SAY_BROKEN_FREE_2);
events.ScheduleEvent(EVENT_BROKEN_FREE_3, Seconds(15));
break;
case EVENT_BROKEN_FREE_3:
if (Creature* special = ObjectAccessor::GetCreature(*me, chosen))
special->AI()->Talk(SAY_BROKEN_SPECIAL);
Summons.DoAction(ACTION_BROKEN_EMOTE, pred);
events.ScheduleEvent(EVENT_BROKEN_FREE_4, Seconds(5));
break;
case EVENT_BROKEN_FREE_4:
Summons.DoAction(ACTION_BROKEN_HAIL, pred);
break;
default:
break;
}
}
if (me->getFaction() == FACTION_COMBAT)
{
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
}
void JustDied(Unit* /*killer*/) override
{
Summons.DespawnAll();
Talk(SAY_DEAD);
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
if (Shade->IsAlive())
Shade->AI()->DoAction(ACTION_AKAMA_DEAD);
}
void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
if (gossipListId == 0)
{
player->CLOSE_GOSSIP_MENU();
events.ScheduleEvent(EVENT_SHADE_START, Milliseconds(500));
}
}
private:
InstanceScript* instance;
EventMap events;
SummonList Summons;
DummyEntryCheckPredicate pred;
ObjectGuid chosen; //Creature that should yell the speech special.
bool IsInCombat;
bool HasYelledOnce;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_akamaAI>(creature);
}
};
class npc_ashtongue_channeler : public CreatureScript
{
public:
npc_ashtongue_channeler() : CreatureScript("npc_ashtongue_channeler") { }
struct npc_ashtongue_channelerAI : public PassiveAI
{
npc_ashtongue_channelerAI(Creature* creature) : PassiveAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
_scheduler.Schedule(Seconds(2), [this](TaskContext channel)
{
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
{
if (Shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
DoCastSelf(SPELL_SHADE_SOUL_CHANNEL);
else
me->DespawnOrUnsummon(3000);
}
channel.Repeat(Seconds(2));
});
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
InstanceScript* instance;
TaskScheduler _scheduler;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_channelerAI>(creature);
}
};
class npc_creature_generator_akama : public CreatureScript
{
public:
npc_creature_generator_akama() : CreatureScript("npc_creature_generator_akama") { }
struct npc_creature_generator_akamaAI : public ScriptedAI
{
npc_creature_generator_akamaAI(Creature* creature) : ScriptedAI(creature), Summons(me) { }
void Reset() override
{
leftSide = false;
events.Reset();
Summons.DespawnAll();
if (me->GetPositionY() < 400.0f)
leftSide = true;
}
void JustSummoned(Creature* summon) override
{
Summons.Summon(summon);
}
void DoAction(int32 actionId) override
{
switch (actionId)
{
case ACTION_START_SPAWNING:
if (leftSide)
{
events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Milliseconds(100));
events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, randtime(Seconds(2), Seconds(5)));
}
else
{
events.ScheduleEvent(EVENT_SPAWN_WAVE_B, Seconds(10));
events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, randtime(Seconds(2), Seconds(5)));
}
break;
case ACTION_STOP_SPAWNING:
events.Reset();
break;
case ACTION_DESPAWN_ALL_SPAWNS:
events.Reset();
Summons.DespawnAll();
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPAWN_WAVE_B:
DoCastSelf(SPELL_ASHTONGUE_WAVE_B);
events.ScheduleEvent(EVENT_SPAWN_WAVE_B, randtime(Seconds(50), Seconds(60)));
break;
case EVENT_SUMMON_ASHTONGUE_SORCERER: // left
DoCastSelf(SPELL_SUMMON_ASHTONGUE_SORCERER);
events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_SORCERER, randtime(Seconds(30), Seconds(35)));
break;
case EVENT_SUMMON_ASHTONGUE_DEFENDER: // right
DoCastSelf(SPELL_SUMMON_ASHTONGUE_DEFENDER);
events.ScheduleEvent(EVENT_SUMMON_ASHTONGUE_DEFENDER, randtime(Seconds(30), Seconds(40)));
break;
default:
break;
}
}
}
private:
EventMap events;
SummonList Summons;
bool leftSide;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_creature_generator_akamaAI>(creature);
}
};
class npc_ashtongue_sorcerer : public CreatureScript
{
public:
npc_ashtongue_sorcerer() : CreatureScript("npc_ashtongue_sorcerer") { }
struct npc_ashtongue_sorcererAI : public ScriptedAI
{
npc_ashtongue_sorcererAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
switchToCombat = false;
inBanish = false;
}
void Reset() override
{
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
{
if (Shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
me->GetMotionMaster()->MovePoint(0, Shade->GetPositionX(), Shade->GetPositionY(), Shade->GetPositionZ());
else
{
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
}
Initialize();
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(5000);
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
void EnterCombat(Unit* /*who*/) override { }
void AttackStart(Unit* who) override
{
if (!switchToCombat)
return;
ScriptedAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (who->GetGUID() == instance->GetGuidData(DATA_SHADE_OF_AKAMA) && me->IsWithinDist(who, 20.0f, false) && !inBanish)
{
inBanish = true;
me->StopMoving();
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + frand(-8.0f, 8.0f), me->GetPositionY() + frand(-8.0f, 8.0f), me->GetPositionZ());
_scheduler.Schedule(Seconds(1) + Milliseconds(500), [this](TaskContext sorcer_channel)
{
if (Creature* Shade = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SHADE_OF_AKAMA)))
{
if (Shade->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))
{
me->SetFacingToObject(Shade);
DoCastSelf(SPELL_SHADE_SOUL_CHANNEL);
sorcer_channel.Repeat(Seconds(2));
}
else
{
me->InterruptSpell(CURRENT_CHANNELED_SPELL);
switchToCombat = true;
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
}
});
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
TaskScheduler _scheduler;
bool switchToCombat;
bool inBanish;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_sorcererAI>(creature);
}
};
class npc_ashtongue_defender : public CreatureScript
{
public:
npc_ashtongue_defender() : CreatureScript("npc_ashtongue_defender") { }
struct npc_ashtongue_defenderAI : public ScriptedAI
{
npc_ashtongue_defenderAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(5000);
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(5));
events.ScheduleEvent(EVENT_SHIELD_BASH, randtime(Seconds(10), Seconds(16)));
events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, randtime(Seconds(10), Seconds(16)));
events.ScheduleEvent(EVENT_WINDFURY, randtime(Seconds(8), Seconds(12)));
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DEBILITATING_STRIKE:
DoCastVictim(SPELL_DEBILITATING_STRIKE);
events.ScheduleEvent(EVENT_DEBILITATING_STRIKE, randtime(Seconds(20), Seconds(25)));
break;
case EVENT_HEROIC_STRIKE:
DoCastSelf(SPELL_HEROIC_STRIKE);
events.ScheduleEvent(EVENT_HEROIC_STRIKE, randtime(Seconds(5), Seconds(15)));
break;
case EVENT_SHIELD_BASH:
DoCastVictim(SPELL_SHIELD_BASH);
events.ScheduleEvent(EVENT_SHIELD_BASH, randtime(Seconds(10), Seconds(20)));
break;
case EVENT_WINDFURY:
DoCastVictim(SPELL_WINDFURY);
events.ScheduleEvent(EVENT_WINDFURY, randtime(Seconds(6), Seconds(8)));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_defenderAI>(creature);
}
};
class npc_ashtongue_rogue : public CreatureScript
{
public:
npc_ashtongue_rogue() : CreatureScript("npc_ashtongue_rogue") { }
struct npc_ashtongue_rogueAI : public ScriptedAI
{
npc_ashtongue_rogueAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(5000);
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_DEBILITATING_POISON, randtime(Milliseconds(500), Seconds(2)));
events.ScheduleEvent(EVENT_EVISCERATE, randtime(Seconds(2), Seconds(5)));
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DEBILITATING_POISON:
DoCastVictim(SPELL_DEBILITATING_POISON);
events.ScheduleEvent(EVENT_DEBILITATING_POISON, randtime(Seconds(15), Seconds(20)));
break;
case EVENT_EVISCERATE:
DoCastVictim(SPELL_EVISCERATE);
events.ScheduleEvent(EVENT_EVISCERATE, randtime(Seconds(12), Seconds(20)));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_rogueAI>(creature);
}
};
class npc_ashtongue_elementalist : public CreatureScript
{
public:
npc_ashtongue_elementalist() : CreatureScript("npc_ashtongue_elementalist") { }
struct npc_ashtongue_elementalistAI : public ScriptedAI
{
npc_ashtongue_elementalistAI(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(5000);
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, Seconds(18));
events.ScheduleEvent(EVENT_LIGHTNING_BOLT, Seconds(6));
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RAIN_OF_FIRE:
DoCastVictim(SPELL_RAIN_OF_FIRE);
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, randtime(Seconds(15), Seconds(20)));
break;
case EVENT_LIGHTNING_BOLT:
DoCastVictim(SPELL_LIGHTNING_BOLT);
events.ScheduleEvent(EVENT_LIGHTNING_BOLT, randtime(Seconds(8), Seconds(15)));
break;
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
EventMap events;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_elementalistAI>(creature);
}
};
class npc_ashtongue_spiritbinder : public CreatureScript
{
public:
npc_ashtongue_spiritbinder() : CreatureScript("npc_ashtongue_spiritbinder") { }
struct npc_ashtongue_spiritbinderAI : public ScriptedAI
{
npc_ashtongue_spiritbinderAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
spiritMend = false;
chainHeal = false;
}
void Reset() override
{
Initialize();
if (Unit* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA_SHADE)))
AttackStart(target);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(5000);
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SPIRIT_HEAL, randtime(Seconds(5), Seconds(6)));
}
void DamageTaken(Unit* /*who*/, uint32& /*damage*/) override
{
if (!spiritMend)
if (HealthBelowPct(30))
{
DoCastSelf(SPELL_SPIRIT_MEND);
spiritMend = true;
events.ScheduleEvent(EVENT_SPIRIT_MEND_RESET, randtime(Seconds(10),Seconds(15)));
}
if (!chainHeal)
if (HealthBelowPct(50))
{
DoCastSelf(SPELL_CHAIN_HEAL);
chainHeal = true;
events.ScheduleEvent(EVENT_CHAIN_HEAL_RESET, randtime(Seconds(10), Seconds(15)));
}
}
void EnterEvadeMode(EvadeReason /*why*/) override { }
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SPIRIT_HEAL:
DoCastSelf(SPELL_SPIRITBINDER_SPIRIT_HEAL);
events.ScheduleEvent(EVENT_SPIRIT_HEAL, randtime(Seconds(13), Seconds(16)));
break;
case EVENT_SPIRIT_MEND_RESET:
spiritMend = false;
break;
case EVENT_CHAIN_HEAL_RESET:
chainHeal = false;
break;
default:
break;
}
}
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
EventMap events;
bool spiritMend;
bool chainHeal;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_spiritbinderAI>(creature);
}
};
class npc_ashtongue_broken : public CreatureScript
{
public:
npc_ashtongue_broken() : CreatureScript("npc_ashtongue_broken") { }
struct npc_ashtongue_brokenAI : public ScriptedAI
{
npc_ashtongue_brokenAI(Creature* creature) : ScriptedAI(creature)
{
instance = me->GetInstanceScript();
}
void MovementInform(uint32 motionType, uint32 /*pointId*/) override
{
if (motionType != POINT_MOTION_TYPE)
return;
if (Creature* Akama = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_AKAMA)))
me->SetFacingToObject(Akama);
}
void DoAction(int32 actionId) override
{
switch (actionId)
{
case ACTION_BROKEN_SPECIAL:
Talk(SAY_BROKEN_SPECIAL);
break;
case ACTION_BROKEN_HAIL:
me->setFaction(FACTION_FRIENDLY);
Talk(SAY_BROKEN_HAIL);
break;
case ACTION_BROKEN_EMOTE:
me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_KNEEL);
break;
default:
break;
}
}
private:
InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetInstanceAI<npc_ashtongue_brokenAI>(creature);
}
};
class spell_shade_soul_channel : public SpellScriptLoader
{
public:
spell_shade_soul_channel() : SpellScriptLoader("spell_shade_soul_channel") { }
class spell_shade_soul_channel_AuraScript : public AuraScript
{
PrepareAuraScript(spell_shade_soul_channel_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_SHADE_SOUL_CHANNEL_2))
return false;
return true;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->RemoveAuraFromStack(SPELL_SHADE_SOUL_CHANNEL_2);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_shade_soul_channel_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_shade_soul_channel_AuraScript();
}
};
class spell_shade_soul_channel_two : public SpellScriptLoader
{
public:
spell_shade_soul_channel_two() : SpellScriptLoader("spell_shade_soul_channel_two") { }
class spell_shade_soul_channel_two_AuraScript : public AuraScript
{
PrepareAuraScript(spell_shade_soul_channel_two_AuraScript);
void UpdateSpeed()
{
Unit* target = GetTarget();
if (target->GetAuraCount(SPELL_SHADE_SOUL_CHANNEL_2) <= 3)
{
float moveSpeed = (2.0f - (0.6f * target->GetAuraCount(SPELL_SHADE_SOUL_CHANNEL_2)));
target->SetSpeedRate(MOVE_WALK, moveSpeed / 2.5f);
target->SetSpeedRate(MOVE_RUN, (moveSpeed * 2) / 7);
target->ClearUnitState(UNIT_STATE_ROOT);
}
else
target->AddUnitState(UNIT_STATE_ROOT);
}
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
UpdateSpeed();
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
UpdateSpeed();
}
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_shade_soul_channel_two_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
AfterEffectRemove += AuraEffectRemoveFn(spell_shade_soul_channel_two_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DECREASE_SPEED, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_shade_soul_channel_two_AuraScript();
}
};
void AddSC_boss_shade_of_akama()
{
new boss_shade_of_akama();
new npc_akama_shade();
new npc_ashtongue_channeler();
new npc_creature_generator_akama();
new npc_ashtongue_sorcerer();
new npc_ashtongue_defender();
new npc_ashtongue_rogue();
new npc_ashtongue_elementalist();
new npc_ashtongue_spiritbinder();
new npc_ashtongue_broken();
new spell_shade_soul_channel();
new spell_shade_soul_channel_two();
}
@Keader
Copy link
Author

Keader commented Jun 29, 2016

DELETE FROM `creature_summon_groups` WHERE `summonerId`=22841; -- Shade of Akama
INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`) VALUES
(22841,0,1,23421,443.495,413.973,118.621,5.13127 ,6,6000),-- Ashtongue Channeler
(22841,0,1,23421,456.694,414.117,118.621,4.2586  ,6,6000),
(22841,0,1,23421,457.763,390.117,118.621,2.25148 ,6,6000),
(22841,0,1,23421,444.153,389.214,118.621,1.0821  ,6,6000),
(22841,0,1,23421,438.279,401.258,118.621,0.017453,6,6000),
(22841,0,1,23421,463.186,401.64 ,118.621,3.19395 ,6,6000),
(22841,0,1,23191,547.186,400.534,112.867,3.12414 ,8,   0); -- Akama

DELETE FROM `creature` WHERE `id` IN (23191,23421);

DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_shade_soul_channel','spell_shade_soul_channel_two');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES 
(40401,'spell_shade_soul_channel'),
(40520,'spell_shade_soul_channel_two');

DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40902;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13,2,40902,0,1,31,0,3,22841,0,0,0,0,'','Effect_1 - Hits Shade of Akama'),
(13,4,40902,0,2,31,0,3,23351,0,0,0,0,'','Effect_2 - Hits Trigger');

UPDATE `creature_template` SET `mechanic_immune_mask`=618610687 WHERE `entry`=23215; -- Ashtongue Sorcerer Immunity
UPDATE `creature_template` SET `ScriptName`='npc_ashtongue_broken' WHERE `entry`=23319;

DELETE FROM `creature_text` WHERE `entry`=23191 AND `groupid` IN (3,4);
INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES 
(23191,3,0,'I will not last much longer!',14,0,100,0,0,11385,21784,0,'Akama SAY_LOW_HEALTH'),
(23191,4,0,'No! Not yet!',14,0,100,0,0,11386,21785,0,'Akama SAY_DEAD');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment