2009 lines
72 KiB
C++
2009 lines
72 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2
|
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*/
|
|
|
|
/* ScriptData
|
|
SDName: Netherstorm
|
|
SD%Complete: 80
|
|
SDComment: Quest support: 10337, 10438, 10652 (special flight paths), 10198, 10191
|
|
SDCategory: Netherstorm
|
|
EndScriptData */
|
|
|
|
/* ContentData
|
|
npc_commander_dawnforge
|
|
npc_bessy
|
|
npc_maxx_a_million
|
|
go_captain_tyralius_prison
|
|
EndContentData */
|
|
|
|
#include "ScriptMgr.h"
|
|
#include "ScriptedCreature.h"
|
|
#include "ScriptedGossip.h"
|
|
#include "ScriptedEscortAI.h"
|
|
#include "Player.h"
|
|
#include "GameObjectAI.h"
|
|
#include "SpellInfo.h"
|
|
|
|
/* ###################################
|
|
# QUEST: Deathblow to the legion #
|
|
###################################
|
|
*/
|
|
|
|
enum DeathblowToTheLegion
|
|
{
|
|
ADYEN_THE_LIGHTBRINGER = 61021,
|
|
ANCHORITE_KARJA = 50001,
|
|
EXARCH_ORELIS = 50002,
|
|
SOCRETHAR = 20132,
|
|
KAYLAAN_THE_LOST = 20794,
|
|
ISHANAH_HIGH_PRIESTESS = 18538,
|
|
|
|
DEATHBLOW_TO_THE_LEGION = 10409, // Quest ID
|
|
TURNING_POINT = 10507, // Quest ID
|
|
SOCRETHAR_QUEST_CREDIT = 35762, // Quest spell
|
|
SOCRETHAR_TP_STONE = 29796,
|
|
|
|
EXODAR_FACTION = 1806,
|
|
EXODAR_ENEMY_FACTION = 90
|
|
};
|
|
|
|
enum RoleplayActions
|
|
{
|
|
// ADYEN TEXTS
|
|
EVENT_ADYEN_SAY_1 = 1,
|
|
EVENT_ADYEN_SAY_2 = 2,
|
|
EVENT_ADYEN_SAY_3 = 3,
|
|
EVENT_ADYEN_SAY_4 = 4,
|
|
|
|
// SOCRETHAR TEXT
|
|
EVENT_SOCRETHAR_SAY_1 = 5,
|
|
EVENT_SOCRETHAR_SAY_2 = 6,
|
|
EVENT_SOCRETHAR_SAY_3 = 7,
|
|
EVENT_SOCRETHAR_SAY_4 = 8,
|
|
EVENT_SOCRETHAR_SAY_5 = 9,
|
|
EVENT_SOCRETHAR_SAY_6 = 10,
|
|
|
|
// KAYLAAN TEXT
|
|
EVENT_KAYLAAN_SAY_1 = 11,
|
|
EVENT_KAYLAAN_SAY_2 = 12,
|
|
EVENT_KAYLAAN_SAY_3 = 13,
|
|
EVENT_KAYLAAN_SAY_4 = 14,
|
|
EVENT_KAYLAAN_SAY_5 = 15, // Spawn Ishanah at this point
|
|
EVENT_KAYLAAN_SAY_6 = 16,
|
|
EVENT_KAYLAAN_SAY_7 = 17,
|
|
|
|
// ISHANAH TEXT
|
|
EVENT_ISHANAH_SAY_1 = 18, // Make kaylaan bow
|
|
EVENT_ISHANAH_SAY_2 = 19,
|
|
|
|
// SOCRETHAR ROLEPLAY EVENTS
|
|
EVENT_KILL_ISHANAH = 20,
|
|
EVENT_KILL_KAYLAAN = 21,
|
|
EVENT_FINAL_FIGHT = 22, // On death grant credit to all players on threat list
|
|
|
|
// KAYLAAN ROLEPLAY EVENTS
|
|
EVENT_KAYLAAN_WALK_TO_ADYEN = 23, // Adyen talks and 3s later he triggers next event
|
|
EVENT_KAYLAAN_RESSURECTION = 24, // Ress Ishanah
|
|
EVENT_FIGHT_ALDOR = 25,
|
|
EVENT_END_ALDOR_FIGHT = 26,
|
|
RESET_DEATHBLOW_EVENT = 27
|
|
};
|
|
|
|
enum Adyen
|
|
{
|
|
// ADYEN SPELL EVENTS
|
|
EVENT_CRUSADER_STRIKE = 1,
|
|
EVENT_HAMMER_OF_JUSTICE = 2,
|
|
EVENT_HOLY_LIGHT = 3,
|
|
|
|
// ADYEN ROLEPLAY EVENTS
|
|
EVENT_START_PLAYER_READY = 4,
|
|
|
|
// ADYEN SPELLS
|
|
CRUSADER_STRIKE = 14518,
|
|
HAMMER_OF_JUSTICE = 13005,
|
|
HOLY_LIGHT = 13952,
|
|
REDEMPTION = 7328,
|
|
DIVINE_SHIELD = 40733,
|
|
|
|
ADYEN_PATH_ID = 610210
|
|
};
|
|
|
|
enum Karja
|
|
{
|
|
// KARJA SPELL EVENTS
|
|
EVENT_SPELL_HOLY_SMITE = 1,
|
|
|
|
// KARJA ROLEPLAY EVENTS
|
|
EVENT_KARJA_WALK = 2,
|
|
|
|
// KARJA SPELLS
|
|
HOLY_SMITE_KARJA = 9734,
|
|
|
|
KARJA_PATH_ID = 500010
|
|
};
|
|
|
|
enum Orelis
|
|
{
|
|
// ORELIS SPELL EVENTS
|
|
EVENT_SPELL_DEMORALIZING_SHOUT = 1,
|
|
EVENT_SPELL_HEROIC_STRIKE = 2,
|
|
EVENT_SPELL_REND = 3,
|
|
|
|
// ORELIS ROLEPLAY EVENTS
|
|
EVENT_ORELIS_WALK = 4,
|
|
|
|
// ORELIS SPELLS
|
|
DEMORALIZING_SHOUT = 13730,
|
|
HEROIC_STRIKE = 29426,
|
|
REND = 16509,
|
|
|
|
ORELIS_PATH_ID = 500020
|
|
};
|
|
|
|
enum Kaylaan
|
|
{
|
|
// KAYLAAN SPELL EVENTS
|
|
EVENT_SPELL_BURNING_LIGHT = 6,
|
|
EVENT_SPELL_CONSECRATION = 7,
|
|
|
|
// KAYLAAN SPELLS
|
|
BURNING_LIGHT = 37552,
|
|
CONSECRATION = 37553,
|
|
|
|
KAYLAAN_PATH_ID1 = 207940,
|
|
KAYLAAN_PATH_ID2 = 207941
|
|
};
|
|
|
|
enum Socrethar
|
|
{
|
|
// SOCRETHAR SPELL EVENTS # start high to avoid issues with RP enum
|
|
EVENT_SPELL_ANTI_MAGIC_SHIELD = 40,
|
|
EVENT_SPELL_BACKLASH = 41,
|
|
EVENT_SPELL_CLEAVE = 42,
|
|
EVENT_SPELL_FIREBALL_BARRAGE = 43,
|
|
EVENT_SPELL_NETHER_PROTECTION = 44,
|
|
EVENT_SPELL_POWER_OF_THE_LEGION = 45,
|
|
EVENT_SPELL_SHADOW_BOLT_VOLLEY = 46,
|
|
EVENT_ISHANAH_DIES = 47,
|
|
EVENT_KAYLAAN_DIES = 48,
|
|
EVENT_ISHANAH_IS_BACK_AGAIN = 49,
|
|
|
|
// SOCRETHAR SPELLS
|
|
ANTI_MAGIC_SHIELD = 37538,
|
|
BACKLASH = 37537,
|
|
CLEAVE = 15496,
|
|
FIREBALL_BARRAGE = 37540,
|
|
NETHER_PROTECTION = 37539,
|
|
POWER_OF_THE_LEGION = 35596,
|
|
SHADOW_BOLT_VOLLEY = 28448,
|
|
WRATH_OF_SOCRETHAR = 35600
|
|
};
|
|
|
|
enum Ishanah
|
|
{
|
|
ISHANAH_PATH_ID = 500050
|
|
};
|
|
|
|
// Ishanah script part is in zone shattrath city . cpp
|
|
|
|
const Position AdyenSpawnPosition { 4804.839355f, 3773.218750f, 210.530884f, 5.517495f };
|
|
const Position OrelisSpawnPosition { 4805.345215f, 3774.829346f, 210.535095f, 5.517495f };
|
|
const Position KarjaSpawnPosition { 4803.249512f, 3772.649170f, 210.535095f, 5.517495f };
|
|
const Position KaylaanSpawnPosition { 4955.089355f, 3916.570557f, 209.577209f, 4.603052f };
|
|
const Position IshanahSpawnPosition { 4926.066895f, 3825.549072f, 211.494125f, 0.510522f };
|
|
|
|
class deathblow_to_the_legion_trigger : public CreatureScript
|
|
{
|
|
public:
|
|
deathblow_to_the_legion_trigger() : CreatureScript("deathblow_to_the_legion_trigger") { }
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new deathblow_to_the_legion_triggerAI(creature);
|
|
}
|
|
|
|
struct deathblow_to_the_legion_triggerAI : public ScriptedAI
|
|
{
|
|
deathblow_to_the_legion_triggerAI(Creature* creature) : ScriptedAI(creature), _summons(me) { }
|
|
|
|
EventMap _events;
|
|
SummonList _summons;
|
|
|
|
void JustSummoned(Creature* cr) override { _summons.Summon(cr); }
|
|
|
|
void MoveInLineOfSight(Unit* who) override
|
|
{
|
|
if (who->GetTypeId() == TYPEID_PLAYER && who->IsAlive())
|
|
{
|
|
if (who->ToPlayer()->GetQuestStatus(DEATHBLOW_TO_THE_LEGION) == QUEST_STATUS_INCOMPLETE && me->FindNearestCreature(SOCRETHAR, 500.0f, true))
|
|
{
|
|
if (!_summons.HasEntry(ADYEN_THE_LIGHTBRINGER))
|
|
{
|
|
_summons.RemoveNotExisting();
|
|
me->SummonCreature(ADYEN_THE_LIGHTBRINGER, AdyenSpawnPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
|
|
if (!_summons.HasEntry(EXARCH_ORELIS))
|
|
me->SummonCreature(EXARCH_ORELIS, OrelisSpawnPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
|
|
if (!_summons.HasEntry(ANCHORITE_KARJA))
|
|
me->SummonCreature(ANCHORITE_KARJA, KarjaSpawnPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
class adyen_the_lightbringer : public CreatureScript
|
|
{
|
|
public:
|
|
adyen_the_lightbringer(): CreatureScript("adyen_the_lightbringer") { }
|
|
|
|
bool OnGossipHello(Player* player, Creature* creature) override
|
|
{
|
|
if (player->GetQuestStatus(DEATHBLOW_TO_THE_LEGION) == QUEST_STATUS_INCOMPLETE)
|
|
AddGossipItemFor(player, ADYEN_THE_LIGHTBRINGER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
|
|
|
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
|
{
|
|
ClearGossipMenuFor(player);
|
|
|
|
if (action == GOSSIP_ACTION_INFO_DEF + 1)
|
|
{
|
|
CloseGossipMenuFor(player);
|
|
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
creature->AI()->DoAction(EVENT_START_PLAYER_READY);
|
|
if (Creature* orelis = creature->FindNearestCreature(EXARCH_ORELIS, 15.0f, true))
|
|
orelis->AI()->DoAction(EVENT_ORELIS_WALK);
|
|
if (Creature* karja = creature->FindNearestCreature(ANCHORITE_KARJA, 15.0f, true))
|
|
karja->AI()->DoAction(EVENT_KARJA_WALK);
|
|
if (Creature* socrethar = creature->FindNearestCreature(SOCRETHAR, 500.0f, true))
|
|
socrethar->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
struct adyen_the_lightbringerAI : public ScriptedAI
|
|
{
|
|
adyen_the_lightbringerAI(Creature* creature) : ScriptedAI(creature), event_started(false) { }
|
|
|
|
EventMap _events;
|
|
uint32 eventTimer, eventPhase;
|
|
bool event_started = false;
|
|
|
|
void DoAction(int32 param) override
|
|
{
|
|
if (param == EVENT_START_PLAYER_READY)
|
|
{
|
|
me->GetMotionMaster()->MovePath(ADYEN_PATH_ID, false);
|
|
event_started = true;
|
|
}
|
|
else if (param == RESET_DEATHBLOW_EVENT)
|
|
{
|
|
me->ClearInCombat();
|
|
me->AttackStop();
|
|
me->GetMotionMaster()->MoveTargetedHome();
|
|
me->DespawnOrUnsummon(15000);
|
|
}
|
|
}
|
|
|
|
void MovementInform(uint32 type, uint32 point) override
|
|
{
|
|
if (type != POINT_MOTION_TYPE)
|
|
if (point == 9)
|
|
{
|
|
if (Creature* socrethar = me->FindNearestCreature(SOCRETHAR, 50.0f, true))
|
|
socrethar->AI()->DoAction(EVENT_ADYEN_SAY_1);
|
|
me->SetHomePosition(me->GetPosition());
|
|
}
|
|
}
|
|
|
|
void EnterCombat(Unit * /*who*/) override
|
|
{
|
|
_events.ScheduleEvent(EVENT_CRUSADER_STRIKE, 3000);
|
|
_events.ScheduleEvent(EVENT_HAMMER_OF_JUSTICE, 6000);
|
|
_events.ScheduleEvent(EVENT_HOLY_LIGHT, 1000);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
_events.Update(diff);
|
|
|
|
while (uint32 eventId = _events.ExecuteEvent())
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case EVENT_CRUSADER_STRIKE:
|
|
me->CastSpell(me->GetVictim(), CRUSADER_STRIKE, false);
|
|
_events.RepeatEvent(3500);
|
|
break;
|
|
case EVENT_HAMMER_OF_JUSTICE:
|
|
me->CastSpell(me->GetVictim(), HAMMER_OF_JUSTICE, false);
|
|
_events.RepeatEvent(urand(10000, 14000));
|
|
break;
|
|
case EVENT_HOLY_LIGHT:
|
|
// if low enough will heal and trigger again in 18s.
|
|
if (me->GetHealthPct() <= 45)
|
|
{
|
|
me->CastSpell(me, HOLY_LIGHT, false);
|
|
_events.RepeatEvent(urand(18000, 22000));
|
|
}
|
|
else if (Unit* who = me->FindNearestCreature(ANCHORITE_KARJA, 30.0f, true))
|
|
{
|
|
if (who->GetHealthPct() <= 45)
|
|
{
|
|
me->CastSpell(who, HOLY_LIGHT, false);
|
|
_events.RepeatEvent(urand(18000, 22000));
|
|
}
|
|
}
|
|
else if (Unit* who = me->FindNearestCreature(EXARCH_ORELIS, 30.0f, true))
|
|
{
|
|
if (who->GetHealthPct() <= 45)
|
|
{
|
|
me->CastSpell(who, HOLY_LIGHT, false);
|
|
_events.RepeatEvent(urand(18000, 22000));
|
|
}
|
|
}
|
|
else
|
|
_events.RepeatEvent(1000);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new adyen_the_lightbringerAI(creature);
|
|
}
|
|
};
|
|
|
|
class anchorite_karja : public CreatureScript
|
|
{
|
|
public:
|
|
anchorite_karja() : CreatureScript("anchorite_karja") { }
|
|
|
|
struct anchorite_karjaAI : public ScriptedAI
|
|
{
|
|
anchorite_karjaAI(Creature* creature) : ScriptedAI(creature) { }
|
|
|
|
EventMap _events;
|
|
|
|
void DoAction(int32 param) override
|
|
{
|
|
if (param == EVENT_KARJA_WALK)
|
|
{
|
|
me->GetMotionMaster()->MovePath(KARJA_PATH_ID, false);
|
|
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
}
|
|
else if (param == RESET_DEATHBLOW_EVENT)
|
|
{
|
|
me->ClearInCombat();
|
|
me->AttackStop();
|
|
me->GetMotionMaster()->MoveTargetedHome();
|
|
me->DespawnOrUnsummon(15000);
|
|
}
|
|
}
|
|
|
|
void MovementInform(uint32 type, uint32 point) override
|
|
{
|
|
if (type != POINT_MOTION_TYPE)
|
|
if (point == 11)
|
|
me->SetHomePosition(me->GetPosition());
|
|
}
|
|
|
|
void EnterCombat(Unit* who) override
|
|
{
|
|
AttackStart(who);
|
|
_events.ScheduleEvent(EVENT_SPELL_HOLY_SMITE, 1000);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
_events.Update(diff);
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
switch ( _events.ExecuteEvent())
|
|
{
|
|
case EVENT_SPELL_HOLY_SMITE:
|
|
me->CastSpell(me->GetVictim(), HOLY_SMITE_KARJA, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_HOLY_SMITE, 2500);
|
|
break;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new anchorite_karjaAI(creature);
|
|
}
|
|
};
|
|
|
|
class exarch_orelis : public CreatureScript
|
|
{
|
|
public:
|
|
exarch_orelis() : CreatureScript("exarch_orelis") { }
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new exarch_orelisAI(creature);
|
|
}
|
|
|
|
struct exarch_orelisAI : public ScriptedAI
|
|
{
|
|
exarch_orelisAI(Creature* creature) : ScriptedAI(creature) { }
|
|
|
|
EventMap _events;
|
|
|
|
void DoAction(int32 param) override
|
|
{
|
|
if (param == EVENT_ORELIS_WALK)
|
|
{
|
|
me->GetMotionMaster()->MovePath(ORELIS_PATH_ID, false);
|
|
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
}
|
|
else if (param == RESET_DEATHBLOW_EVENT)
|
|
{
|
|
me->ClearInCombat();
|
|
me->AttackStop();
|
|
me->GetMotionMaster()->MoveTargetedHome();
|
|
me->DespawnOrUnsummon(15000);
|
|
}
|
|
}
|
|
|
|
void JustSummoned(Creature *) override
|
|
{
|
|
me->SetHomePosition(me->GetPosition());
|
|
}
|
|
|
|
void AttackStart(Unit* who) override
|
|
{
|
|
ScriptedAI::AttackStart(who);
|
|
}
|
|
|
|
void MovementInform(uint32 type, uint32 point) override
|
|
{
|
|
if (type != POINT_MOTION_TYPE)
|
|
if (point == 11)
|
|
me->SetHomePosition(me->GetPosition());
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/) override
|
|
{
|
|
_events.ScheduleEvent(EVENT_SPELL_DEMORALIZING_SHOUT, 1000);
|
|
_events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, urand(2500, 4000));
|
|
_events.ScheduleEvent(EVENT_SPELL_REND, urand(1500, 6000));
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
_events.Update(diff);
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
switch (_events.ExecuteEvent())
|
|
{
|
|
case EVENT_SPELL_DEMORALIZING_SHOUT:
|
|
if (me->FindNearestCreature(me->GetVictim()->GetEntry(), 10.0f, true))
|
|
{
|
|
me->CastSpell(me->GetVictim(), DEMORALIZING_SHOUT, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_DEMORALIZING_SHOUT, urand(10000, 12000));
|
|
}
|
|
else
|
|
_events.ScheduleEvent(EVENT_SPELL_DEMORALIZING_SHOUT, 1000);
|
|
break;
|
|
case EVENT_SPELL_HEROIC_STRIKE:
|
|
me->CastSpell(me->GetVictim(), HEROIC_STRIKE, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_HEROIC_STRIKE, urand(3000, 4000));
|
|
break;
|
|
case EVENT_SPELL_REND:
|
|
me->CastSpell(me->GetVictim(), REND, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_REND, urand(5000, 8000));
|
|
break;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
};
|
|
|
|
class socrethar : public CreatureScript
|
|
{
|
|
public:
|
|
socrethar() : CreatureScript("socrethar") { }
|
|
|
|
struct socretharAI : public ScriptedAI
|
|
{
|
|
socretharAI(Creature* creature) : ScriptedAI(creature),
|
|
adyen(nullptr), orelis(nullptr), karja(nullptr), kaylaan(nullptr), ishanah(nullptr) { }
|
|
|
|
EventMap _actionEvents, combatEvents;
|
|
bool DeathblowToTheLegionRunning = false;
|
|
Creature* adyen, *orelis, *karja, *kaylaan, *ishanah;
|
|
|
|
bool GetCreature(uint32 CreatureID)
|
|
{
|
|
switch (CreatureID)
|
|
{
|
|
case ADYEN_THE_LIGHTBRINGER:
|
|
adyen = nullptr;
|
|
adyen = me->FindNearestCreature(ADYEN_THE_LIGHTBRINGER, 100.0f, true);
|
|
if (adyen != nullptr)
|
|
return true;
|
|
break;
|
|
case EXARCH_ORELIS:
|
|
orelis = nullptr;
|
|
orelis = me->FindNearestCreature(EXARCH_ORELIS, 100.0f, true);
|
|
if (orelis != nullptr)
|
|
return true;
|
|
break;
|
|
case ANCHORITE_KARJA:
|
|
karja = nullptr;
|
|
karja = me->FindNearestCreature(ANCHORITE_KARJA, 100.0f, true);
|
|
if (karja != nullptr)
|
|
return true;
|
|
break;
|
|
case KAYLAAN_THE_LOST:
|
|
kaylaan = nullptr;
|
|
kaylaan = me->FindNearestCreature(KAYLAAN_THE_LOST, 100.0f, true);
|
|
if (kaylaan != nullptr)
|
|
return true;
|
|
break;
|
|
case ISHANAH_HIGH_PRIESTESS:
|
|
ishanah = nullptr;
|
|
ishanah = me->FindNearestCreature(ISHANAH_HIGH_PRIESTESS, 100.0f, true);
|
|
if (ishanah == nullptr)
|
|
{
|
|
// Ishanah may be dead; in this case we also need a reference to the creature for the respawn
|
|
ishanah = me->FindNearestCreature(ISHANAH_HIGH_PRIESTESS, 100.0f, false);
|
|
if (ishanah != nullptr)
|
|
return true;
|
|
}
|
|
else
|
|
return true;
|
|
break;
|
|
}
|
|
return false; // When he doesn't find anyone
|
|
}
|
|
|
|
void Reset() override
|
|
{
|
|
me->SetReactState(REACT_PASSIVE);
|
|
me->setFaction(EXODAR_ENEMY_FACTION);
|
|
adyen = nullptr;
|
|
orelis = nullptr;
|
|
karja = nullptr;
|
|
ishanah = nullptr;
|
|
}
|
|
|
|
void DoAction(int32 param) override
|
|
{
|
|
switch (param)
|
|
{
|
|
case EVENT_ADYEN_SAY_1:
|
|
DeathblowToTheLegionRunning = true;
|
|
_actionEvents.ScheduleEvent(EVENT_ADYEN_SAY_1, 1000);
|
|
break;
|
|
case EVENT_ADYEN_SAY_3:
|
|
_actionEvents.ScheduleEvent(EVENT_ADYEN_SAY_3, 2000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_1:
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_1, 4000);
|
|
break;
|
|
case EVENT_END_ALDOR_FIGHT:
|
|
_actionEvents.ScheduleEvent(EVENT_END_ALDOR_FIGHT, 1);
|
|
break;
|
|
case EVENT_ISHANAH_SAY_1:
|
|
_actionEvents.ScheduleEvent(EVENT_ISHANAH_SAY_1, 2000);
|
|
break;
|
|
case RESET_DEATHBLOW_EVENT:
|
|
DeathblowToTheLegionRunning = false;
|
|
Reset();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/) override
|
|
{
|
|
DoCast(me, SOCRETHAR_QUEST_CREDIT);
|
|
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
{
|
|
ishanah->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
|
ishanah->DespawnOrUnsummon(60000);
|
|
}
|
|
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->GetAI()->DoAction(RESET_DEATHBLOW_EVENT);
|
|
|
|
if (GetCreature(EXARCH_ORELIS))
|
|
orelis->GetAI()->DoAction(RESET_DEATHBLOW_EVENT);
|
|
|
|
if (GetCreature(ANCHORITE_KARJA))
|
|
karja->GetAI()->DoAction(RESET_DEATHBLOW_EVENT);
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/) override
|
|
{
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_ANTI_MAGIC_SHIELD, 20000);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_BACKLASH, 4000);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_CLEAVE, 2000);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_FIREBALL_BARRAGE, 9000);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT_VOLLEY, 5000);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_NETHER_PROTECTION, 1);
|
|
}
|
|
|
|
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
|
|
{
|
|
me->SetReactState(REACT_AGGRESSIVE);
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
if (DeathblowToTheLegionRunning)
|
|
{
|
|
_actionEvents.Update(diff);
|
|
|
|
switch (_actionEvents.ExecuteEvent())
|
|
{
|
|
case EVENT_ADYEN_SAY_1:
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->AI()->Talk(0);
|
|
_actionEvents.ScheduleEvent(EVENT_SOCRETHAR_SAY_1, 11000);
|
|
break;
|
|
case EVENT_SOCRETHAR_SAY_1:
|
|
Talk(0);
|
|
_actionEvents.ScheduleEvent(EVENT_ADYEN_SAY_2, 7000);
|
|
break;
|
|
case EVENT_ADYEN_SAY_2:
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->AI()->Talk(1);
|
|
_actionEvents.ScheduleEvent(EVENT_SOCRETHAR_SAY_2, 11000);
|
|
break;
|
|
case EVENT_SOCRETHAR_SAY_2:
|
|
Talk(1);
|
|
if (Creature* summonKaylaan = me->SummonCreature(KAYLAAN_THE_LOST, KaylaanSpawnPosition, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 240000))
|
|
summonKaylaan->GetMotionMaster()->MovePath(KAYLAAN_PATH_ID1, false);
|
|
break;
|
|
case EVENT_ADYEN_SAY_3:
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->AI()->Talk(2);
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->SetStandState(UNIT_STAND_STATE_STAND);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_WALK_TO_ADYEN, 3500);
|
|
break;
|
|
case EVENT_KAYLAAN_WALK_TO_ADYEN:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->GetMotionMaster()->MovePath(KAYLAAN_PATH_ID2, false);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_1:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->AI()->Talk(0);
|
|
kaylaan->SetHomePosition(kaylaan->GetPosition());
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_2, 9000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_2:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->AI()->Talk(1);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_3, 8000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_3:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->AI()->Talk(2);
|
|
_actionEvents.ScheduleEvent(EVENT_ADYEN_SAY_4, 8000);
|
|
break;
|
|
case EVENT_ADYEN_SAY_4:
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->AI()->Talk(3);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_4, 11000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_4:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->AI()->Talk(3);
|
|
_actionEvents.ScheduleEvent(EVENT_SPELL_POWER_OF_THE_LEGION, 5000);
|
|
break;
|
|
case EVENT_SPELL_POWER_OF_THE_LEGION:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
me->CastSpell(kaylaan, POWER_OF_THE_LEGION, false);
|
|
Talk(2);
|
|
_actionEvents.ScheduleEvent(EVENT_FIGHT_ALDOR, 3000);
|
|
break;
|
|
case EVENT_FIGHT_ALDOR:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->setFaction(EXODAR_ENEMY_FACTION);
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
kaylaan->AI()->AttackStart(adyen);
|
|
}
|
|
break;
|
|
case EVENT_END_ALDOR_FIGHT:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->setFaction(EXODAR_FACTION);
|
|
kaylaan->GetMotionMaster()->MoveTargetedHome();
|
|
kaylaan->CombatStop();
|
|
kaylaan->ClearInCombat();
|
|
}
|
|
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
{
|
|
adyen->GetMotionMaster()->MoveTargetedHome();
|
|
adyen->CombatStop();
|
|
adyen->ClearInCombat();
|
|
}
|
|
|
|
if (GetCreature(EXARCH_ORELIS))
|
|
{
|
|
orelis->GetMotionMaster()->MoveTargetedHome();
|
|
orelis->CombatStop();
|
|
orelis->ClearInCombat();
|
|
}
|
|
|
|
if (GetCreature(ANCHORITE_KARJA))
|
|
{
|
|
karja->GetMotionMaster()->MoveTargetedHome();
|
|
karja->CombatStop();
|
|
karja->ClearInCombat();
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_SOCRETHAR_SAY_4, 2000);
|
|
break;
|
|
case EVENT_SOCRETHAR_SAY_4:
|
|
Talk(3);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_5, 8000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_5:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->AI()->Talk(4);
|
|
if (Creature* summonIshanah = me->SummonCreature(ISHANAH_HIGH_PRIESTESS, IshanahSpawnPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 180000))
|
|
{
|
|
summonIshanah->GetMotionMaster()->MovePath(ISHANAH_PATH_ID, false);
|
|
summonIshanah->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
|
}
|
|
break;
|
|
case EVENT_ISHANAH_SAY_1:
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
ishanah->AI()->Talk(0);
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->RemoveAurasDueToSpell(POWER_OF_THE_LEGION);
|
|
kaylaan->SetStandState(UNIT_STAND_STATE_KNEEL);
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_ISHANAH_SAY_2, 6000);
|
|
break;
|
|
case EVENT_ISHANAH_SAY_2:
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
ishanah->AI()->Talk(1);
|
|
_actionEvents.ScheduleEvent(EVENT_SOCRETHAR_SAY_5, 8000);
|
|
break;
|
|
case EVENT_SOCRETHAR_SAY_5:
|
|
Talk(4);
|
|
_actionEvents.ScheduleEvent(EVENT_KILL_ISHANAH, 4000);
|
|
break;
|
|
case EVENT_KILL_ISHANAH:
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
me->CastSpell(ishanah, WRATH_OF_SOCRETHAR);
|
|
_actionEvents.ScheduleEvent(EVENT_ISHANAH_DIES, 1500);
|
|
break;
|
|
case EVENT_ISHANAH_DIES:
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
me->Kill(me,ishanah);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_6, 4000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_6:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->AI()->Talk(6);
|
|
kaylaan->SetStandState(UNIT_STAND_STATE_STAND);
|
|
kaylaan->GetMotionMaster()->MovePath(207942, false);
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_SAY_7, 9000);
|
|
break;
|
|
case EVENT_KAYLAAN_SAY_7:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
{
|
|
kaylaan->AI()->Talk(7);
|
|
kaylaan->CastSpell(kaylaan, DIVINE_SHIELD);
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_RESSURECTION, 1000);
|
|
break;
|
|
case EVENT_KAYLAAN_RESSURECTION:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
kaylaan->CastSpell(ishanah, REDEMPTION);
|
|
_actionEvents.ScheduleEvent(EVENT_ISHANAH_IS_BACK_AGAIN, 11000);
|
|
break;
|
|
case EVENT_ISHANAH_IS_BACK_AGAIN:
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
{
|
|
ishanah->Respawn();
|
|
ishanah->setActive(true); // ensure that Ishanah disappears, even when no player is near
|
|
ishanah->DespawnOrUnsummon(600000); // ensure that Ishanah disappears after 10 minutes
|
|
ishanah->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
|
}
|
|
_actionEvents.ScheduleEvent(EVENT_SOCRETHAR_SAY_6, 3000);
|
|
break;
|
|
case EVENT_SOCRETHAR_SAY_6:
|
|
Talk(5);
|
|
_actionEvents.ScheduleEvent(EVENT_KILL_KAYLAAN, 4000);
|
|
break;
|
|
case EVENT_KILL_KAYLAAN:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
me->CastSpell(kaylaan, WRATH_OF_SOCRETHAR);
|
|
_actionEvents.ScheduleEvent(EVENT_KAYLAAN_DIES, 1500);
|
|
break;
|
|
case EVENT_KAYLAAN_DIES:
|
|
if (GetCreature(KAYLAAN_THE_LOST))
|
|
me->Kill(me, kaylaan);
|
|
_actionEvents.ScheduleEvent(EVENT_FINAL_FIGHT, 3000);
|
|
break;
|
|
case EVENT_FINAL_FIGHT:
|
|
// Prepare Socrethar for encounter
|
|
me->setFaction(EXODAR_ENEMY_FACTION);
|
|
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
|
me->SetReactState(REACT_AGGRESSIVE);
|
|
|
|
// Engage combat with Socrethar
|
|
if (GetCreature(ADYEN_THE_LIGHTBRINGER))
|
|
adyen->AI()->EnterCombat(me);
|
|
if (GetCreature(EXARCH_ORELIS))
|
|
orelis->AI()->EnterCombat(me);
|
|
if (GetCreature(ANCHORITE_KARJA))
|
|
karja->AI()->EnterCombat(me);
|
|
if (GetCreature(ISHANAH_HIGH_PRIESTESS))
|
|
ishanah->AI()->EnterCombat(me);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
combatEvents.Update(diff);
|
|
|
|
switch (combatEvents.ExecuteEvent())
|
|
{
|
|
case EVENT_SPELL_NETHER_PROTECTION:
|
|
if (!me->HasAura(NETHER_PROTECTION))
|
|
me->CastSpell(me, NETHER_PROTECTION, false);
|
|
break;
|
|
case EVENT_SPELL_ANTI_MAGIC_SHIELD:
|
|
me->CastSpell(me, ANTI_MAGIC_SHIELD, false);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_ANTI_MAGIC_SHIELD, 20000);
|
|
break;
|
|
case EVENT_SPELL_BACKLASH:
|
|
DoCastVictim(BACKLASH);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_BACKLASH, 7000);
|
|
break;
|
|
case EVENT_SPELL_CLEAVE:
|
|
me->CastSpell(me->GetVictim(), CLEAVE, false);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_CLEAVE, 3000);
|
|
break;
|
|
case EVENT_SPELL_FIREBALL_BARRAGE:
|
|
me->CastSpell(me->GetVictim(), FIREBALL_BARRAGE, false);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_FIREBALL_BARRAGE, 15000);
|
|
break;
|
|
case EVENT_SPELL_SHADOW_BOLT_VOLLEY:
|
|
me->CastSpell(me->GetVictim(), SHADOW_BOLT_VOLLEY, false);
|
|
combatEvents.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT_VOLLEY, 10000);
|
|
break;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new socretharAI(creature);
|
|
}
|
|
};
|
|
|
|
class kaylaan_the_lost : public CreatureScript
|
|
{
|
|
public:
|
|
kaylaan_the_lost() : CreatureScript("kaylaan_the_lost") { }
|
|
|
|
struct kaylaan_the_lostAI : public ScriptedAI
|
|
{
|
|
kaylaan_the_lostAI(Creature* creature) : ScriptedAI(creature) { }
|
|
|
|
EventMap _events;
|
|
bool first_waypath_done = false;
|
|
bool second_waypath_done = false;
|
|
bool adyen_dead = false, karja_dead = false, orelis_dead = false;
|
|
|
|
void EnterCombat(Unit* /*who*/) override
|
|
{
|
|
_events.ScheduleEvent(EVENT_SPELL_BURNING_LIGHT, 2000);
|
|
_events.ScheduleEvent(EVENT_SPELL_CONSECRATION, 3000);
|
|
}
|
|
|
|
void ResetDeathblowEvent(bool event_over /* If true then reset the event*/)
|
|
{
|
|
me->RemoveAurasDueToSpell(POWER_OF_THE_LEGION);
|
|
me->GetMotionMaster()->MoveTargetedHome();
|
|
|
|
// Get socrethar AI so we can reset the event
|
|
if (event_over)
|
|
{
|
|
if (Unit * socrethar = me->FindNearestCreature(SOCRETHAR, 100.0f, true))
|
|
socrethar->GetAI()->DoAction(RESET_DEATHBLOW_EVENT);
|
|
|
|
karja_dead = false;
|
|
orelis_dead = false;
|
|
adyen_dead = false;
|
|
|
|
me->DespawnOrUnsummon(5000); // Despawn in 5 seconds to reset event
|
|
}
|
|
}
|
|
|
|
void KilledUnit(Unit* victim) override
|
|
{
|
|
switch (victim->GetEntry())
|
|
{
|
|
case ADYEN_THE_LIGHTBRINGER:
|
|
adyen_dead = true;
|
|
break;
|
|
case ANCHORITE_KARJA:
|
|
karja_dead = true;
|
|
break;
|
|
case EXARCH_ORELIS:
|
|
orelis_dead = true;
|
|
break;
|
|
}
|
|
|
|
if (adyen_dead && karja_dead && orelis_dead)
|
|
ResetDeathblowEvent(true);
|
|
}
|
|
|
|
void MovementInform(uint32 type, uint32 point) override
|
|
{
|
|
if (type != POINT_MOTION_TYPE)
|
|
{
|
|
if (point == 4)
|
|
{
|
|
// First waypath complete
|
|
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
|
if (Creature* socrethar = me->FindNearestCreature(SOCRETHAR, 30.0f, true))
|
|
socrethar->AI()->DoAction(EVENT_ADYEN_SAY_3);
|
|
first_waypath_done = true;
|
|
}
|
|
else if (point == 0)
|
|
{
|
|
if (first_waypath_done)
|
|
{
|
|
if (!second_waypath_done)
|
|
{
|
|
// Second waypath complete
|
|
me->SetHomePosition(me->GetPosition());
|
|
if (Creature* adyen = me->FindNearestCreature(ADYEN_THE_LIGHTBRINGER, 30.0f, true))
|
|
me->SetOrientation(adyen->GetPositionX());
|
|
if (Creature* socrethar = me->FindNearestCreature(SOCRETHAR, 30.0f, true))
|
|
{
|
|
socrethar->AI()->DoAction(EVENT_KAYLAAN_SAY_1);
|
|
second_waypath_done = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
return;
|
|
|
|
_events.Update(diff);
|
|
|
|
if (me->GetHealthPct() <= 30)
|
|
if (Creature* socrethar = me->FindNearestCreature(SOCRETHAR, 200.0f, true))
|
|
socrethar->AI()->DoAction(EVENT_END_ALDOR_FIGHT);
|
|
|
|
switch (_events.ExecuteEvent())
|
|
{
|
|
case EVENT_SPELL_BURNING_LIGHT:
|
|
me->CastSpell(me->GetVictim(), BURNING_LIGHT, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_BURNING_LIGHT, 4000);
|
|
break;
|
|
case EVENT_SPELL_CONSECRATION:
|
|
if (me->FindNearestCreature(me->GetVictim()->GetGUID(), 10.0f, true))
|
|
me->CastSpell(me, CONSECRATION, false);
|
|
_events.ScheduleEvent(EVENT_SPELL_CONSECRATION, 14000);
|
|
break;
|
|
}
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new kaylaan_the_lostAI(creature);
|
|
}
|
|
};
|
|
|
|
// Ours
|
|
enum saeed
|
|
{
|
|
NPC_PROTECTORATE_AVENGER = 21805,
|
|
NPC_PROTECTORATE_DEFENDER = 20984,
|
|
NPC_DIMENSIUS = 19554,
|
|
|
|
EVENT_START_WALK = 1,
|
|
EVENT_START_FIGHT1 = 2,
|
|
EVENT_START_FIGHT2 = 3,
|
|
|
|
DATA_START_ENCOUNTER = 1,
|
|
DATA_START_FIGHT = 2,
|
|
|
|
SAY_SAEED_0 = 0,
|
|
SAY_SAEED_1 = 1,
|
|
SAY_SAEED_2 = 2,
|
|
SAY_SAEED_3 = 3,
|
|
SAY_DIMENSISIUS_1 = 1,
|
|
|
|
QUEST_DIMENSIUS_DEVOURING = 10439,
|
|
|
|
SPELL_DIMENSIUS_TRANSFORM = 35939
|
|
};
|
|
|
|
class npc_captain_saeed : public CreatureScript
|
|
{
|
|
public:
|
|
npc_captain_saeed() : CreatureScript("npc_captain_saeed") { }
|
|
|
|
struct npc_captain_saeedAI : public npc_escortAI
|
|
{
|
|
npc_captain_saeedAI(Creature* creature) : npc_escortAI(creature), summons(me) {}
|
|
|
|
SummonList summons;
|
|
EventMap events;
|
|
bool started, fight;
|
|
|
|
void Reset() override
|
|
{
|
|
if (!summons.empty())
|
|
{
|
|
for (std::list<uint64>::iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, *itr))
|
|
{
|
|
float x, y, z, o;
|
|
cr->GetRespawnPosition(x, y, z, &o);
|
|
cr->SetHomePosition(x, y, z, o);
|
|
}
|
|
}
|
|
events.Reset();
|
|
summons.clear();
|
|
started = false;
|
|
fight = false;
|
|
me->RestoreFaction();
|
|
}
|
|
|
|
void MoveInLineOfSight(Unit* who) override
|
|
{
|
|
if (Player* player = GetPlayerForEscort())
|
|
if (me->GetDistance(who) < 10.0f && !me->GetVictim())
|
|
if (player->IsValidAttackTarget(who))
|
|
{
|
|
AttackStart(who);
|
|
return;
|
|
}
|
|
|
|
npc_escortAI::MoveInLineOfSight(who);
|
|
}
|
|
|
|
void SetGUID(uint64 playerGUID, int32 type) override
|
|
{
|
|
if (type == DATA_START_ENCOUNTER)
|
|
{
|
|
Start(true, true, playerGUID);
|
|
SetEscortPaused(true);
|
|
started = true;
|
|
|
|
std::list<Creature*> cl;
|
|
me->GetCreaturesWithEntryInRange(cl, 20.0f, NPC_PROTECTORATE_AVENGER);
|
|
for (std::list<Creature*>::iterator itr = cl.begin(); itr != cl.end(); ++itr)
|
|
{
|
|
summons.Summon(*itr);
|
|
(*itr)->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
|
|
(*itr)->setFaction(250);
|
|
}
|
|
cl.clear();
|
|
me->GetCreaturesWithEntryInRange(cl, 20.0f, NPC_PROTECTORATE_DEFENDER);
|
|
for (std::list<Creature*>::iterator itr = cl.begin(); itr != cl.end(); ++itr)
|
|
{
|
|
summons.Summon(*itr);
|
|
(*itr)->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
|
|
(*itr)->setFaction(250);
|
|
}
|
|
|
|
me->setFaction(250);
|
|
Talk(SAY_SAEED_0);
|
|
events.ScheduleEvent(EVENT_START_WALK, 3000);
|
|
}
|
|
else if (type == DATA_START_FIGHT)
|
|
{
|
|
Talk(SAY_SAEED_2);
|
|
SetEscortPaused(false);
|
|
me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
|
|
}
|
|
}
|
|
|
|
void EnterEvadeMode() override
|
|
{
|
|
if (fight)
|
|
SetEscortPaused(false);
|
|
|
|
SummonsAction(NULL);
|
|
npc_escortAI::EnterEvadeMode();
|
|
}
|
|
|
|
void SummonsAction(Unit* who)
|
|
{
|
|
float i = 0;
|
|
for (std::list<uint64>::iterator itr = summons.begin(); itr != summons.end(); ++itr, i += 1.0f)
|
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, *itr))
|
|
{
|
|
if (who == NULL)
|
|
{
|
|
cr->GetMotionMaster()->Clear(false);
|
|
cr->GetMotionMaster()->MoveFollow(me, 2.0f, M_PI/2.0f + (i / summons.size() * M_PI));
|
|
}
|
|
else
|
|
{
|
|
cr->SetHomePosition(cr->GetPositionX(), cr->GetPositionY(), cr->GetPositionZ(), cr->GetOrientation());
|
|
cr->AI()->AttackStart(who);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WaypointReached(uint32 i) override
|
|
{
|
|
Player* player = GetPlayerForEscort();
|
|
if (!player)
|
|
return;
|
|
|
|
switch (i)
|
|
{
|
|
case 16:
|
|
Talk(SAY_SAEED_1);
|
|
me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
|
|
SetEscortPaused(true);
|
|
break;
|
|
case 18:
|
|
events.ScheduleEvent(EVENT_START_FIGHT1, 0);
|
|
SetEscortPaused(true);
|
|
break;
|
|
case 19:
|
|
summons.DespawnAll();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EnterCombat(Unit* who) override
|
|
{
|
|
SummonsAction(who);
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/) override
|
|
{
|
|
Player* player = GetPlayerForEscort();
|
|
if (player)
|
|
player->FailQuest(QUEST_DIMENSIUS_DEVOURING);
|
|
|
|
summons.DespawnAll();
|
|
}
|
|
|
|
void CorpseRemoved(uint32&) override
|
|
{
|
|
summons.DespawnAll();
|
|
}
|
|
|
|
uint32 GetData(uint32 data) const override
|
|
{
|
|
if (data == 1)
|
|
return (uint32)started;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void UpdateAI(uint32 diff) override
|
|
{
|
|
npc_escortAI::UpdateAI(diff);
|
|
|
|
events.Update(diff);
|
|
switch (events.ExecuteEvent())
|
|
{
|
|
case EVENT_START_WALK:
|
|
SummonsAction(NULL);
|
|
SetEscortPaused(false);
|
|
break;
|
|
case EVENT_START_FIGHT1:
|
|
Talk(SAY_SAEED_3);
|
|
events.ScheduleEvent(EVENT_START_FIGHT2, 3000);
|
|
break;
|
|
case EVENT_START_FIGHT2:
|
|
if (Creature* dimensius = me->FindNearestCreature(NPC_DIMENSIUS, 50.0f))
|
|
{
|
|
dimensius->RemoveAurasDueToSpell(SPELL_DIMENSIUS_TRANSFORM);
|
|
dimensius->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
|
|
AttackStart(dimensius);
|
|
fight = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) override
|
|
{
|
|
ClearGossipMenuFor(player);
|
|
if (uiAction == GOSSIP_ACTION_INFO_DEF+1)
|
|
{
|
|
creature->AI()->SetGUID(player->GetGUID(), DATA_START_ENCOUNTER);
|
|
player->KilledMonsterCredit(creature->GetEntry(), 0);
|
|
}
|
|
else if (uiAction == GOSSIP_ACTION_INFO_DEF+2)
|
|
{
|
|
creature->AI()->SetGUID(player->GetGUID(), DATA_START_FIGHT);
|
|
}
|
|
|
|
CloseGossipMenuFor(player);
|
|
return true;
|
|
}
|
|
|
|
bool OnGossipHello(Player* player, Creature* creature) override
|
|
{
|
|
if (creature->IsQuestGiver())
|
|
player->PrepareQuestMenu(creature->GetGUID());
|
|
|
|
if (player->GetQuestStatus(QUEST_DIMENSIUS_DEVOURING) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
if (!creature->AI()->GetData(1))
|
|
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Let's move out.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
|
|
else
|
|
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Let's start the battle.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
|
|
}
|
|
|
|
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
|
|
|
return true;
|
|
}
|
|
|
|
CreatureAI* GetAI(Creature* creature) const override
|
|
{
|
|
return new npc_captain_saeedAI(creature);
|
|
}
|
|
};
|
|
|
|
|
|
// Theirs
|
|
/*######
|
|
## npc_commander_dawnforge
|
|
######*/
|
|
|
|
// The Speech of Dawnforge, Ardonis & Pathaleon
|
|
enum CommanderDawnforgeData
|
|
{
|
|
SAY_COMMANDER_DAWNFORGE_1 = 0,
|
|
SAY_COMMANDER_DAWNFORGE_2 = 1,
|
|
SAY_COMMANDER_DAWNFORGE_3 = 2,
|
|
SAY_COMMANDER_DAWNFORGE_4 = 3,
|
|
SAY_COMMANDER_DAWNFORGE_5 = 4,
|
|
|
|
SAY_ARCANIST_ARDONIS_1 = 0,
|
|
SAY_ARCANIST_ARDONIS_2 = 1,
|
|
|
|
SAY_PATHALEON_CULATOR_IMAGE_1 = 0,
|
|
SAY_PATHALEON_CULATOR_IMAGE_2 = 1,
|
|
SAY_PATHALEON_CULATOR_IMAGE_2_1 = 2,
|
|
SAY_PATHALEON_CULATOR_IMAGE_2_2 = 3,
|
|
|
|
QUEST_INFO_GATHERING = 10198,
|
|
SPELL_SUNFURY_DISGUISE = 34603,
|
|
};
|
|
|
|
// Entries of Arcanist Ardonis, Commander Dawnforge, Pathaleon the Curators Image
|
|
const uint32 CreatureEntry[3] =
|
|
{
|
|
19830, // Ardonis
|
|
19831, // Dawnforge
|
|
21504 // Pathaleon
|
|
};
|
|
|
|
class npc_commander_dawnforge : public CreatureScript
|
|
{
|
|
public:
|
|
npc_commander_dawnforge() : CreatureScript("npc_commander_dawnforge") { }
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new npc_commander_dawnforgeAI(creature);
|
|
}
|
|
|
|
struct npc_commander_dawnforgeAI : public ScriptedAI
|
|
{
|
|
npc_commander_dawnforgeAI(Creature* creature) : ScriptedAI(creature) { }
|
|
|
|
uint64 PlayerGUID;
|
|
uint64 ardonisGUID;
|
|
uint64 pathaleonGUID;
|
|
|
|
uint32 Phase;
|
|
uint32 PhaseSubphase;
|
|
uint32 Phase_Timer;
|
|
bool isEvent;
|
|
|
|
void Reset()
|
|
{
|
|
PlayerGUID = 0;
|
|
ardonisGUID = 0;
|
|
pathaleonGUID = 0;
|
|
|
|
Phase = 1;
|
|
PhaseSubphase = 0;
|
|
Phase_Timer = 4000;
|
|
isEvent = false;
|
|
}
|
|
|
|
void EnterCombat(Unit* /*who*/) { }
|
|
|
|
void JustSummoned(Creature* summoned)
|
|
{
|
|
pathaleonGUID = summoned->GetGUID();
|
|
}
|
|
|
|
// Emote Ardonis and Pathaleon
|
|
void Turn_to_Pathaleons_Image()
|
|
{
|
|
Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID);
|
|
Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID);
|
|
|
|
if (!ardonis || !pathaleon)
|
|
return;
|
|
|
|
// Turn Dawnforge
|
|
me->SetFacingToObject(pathaleon);
|
|
|
|
// Turn Ardonis
|
|
ardonis->SetFacingToObject(pathaleon);
|
|
|
|
//Set them to kneel
|
|
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
|
ardonis->SetStandState(UNIT_STAND_STATE_KNEEL);
|
|
}
|
|
|
|
//Set them back to each other
|
|
void Turn_to_eachother()
|
|
{
|
|
if (Unit* ardonis = ObjectAccessor::GetUnit(*me, ardonisGUID))
|
|
{
|
|
// Turn Dawnforge
|
|
me->SetFacingToObject(ardonis);
|
|
|
|
// Turn Ardonis
|
|
ardonis->SetFacingToObject(me);
|
|
|
|
//Set state
|
|
me->SetStandState(UNIT_STAND_STATE_STAND);
|
|
ardonis->SetStandState(UNIT_STAND_STATE_STAND);
|
|
}
|
|
}
|
|
|
|
bool CanStartEvent(Player* player)
|
|
{
|
|
if (!isEvent)
|
|
{
|
|
Creature* ardonis = me->FindNearestCreature(CreatureEntry[0], 10.0f);
|
|
if (!ardonis)
|
|
return false;
|
|
|
|
ardonisGUID = ardonis->GetGUID();
|
|
PlayerGUID = player->GetGUID();
|
|
|
|
isEvent = true;
|
|
|
|
Turn_to_eachother();
|
|
return true;
|
|
}
|
|
|
|
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
|
sLog->outDebug(LOG_FILTER_TSCR, "TSCR: npc_commander_dawnforge event already in progress, need to wait.");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
//Is event even running?
|
|
if (!isEvent)
|
|
return;
|
|
|
|
//Phase timing
|
|
if (Phase_Timer >= diff)
|
|
{
|
|
Phase_Timer -= diff;
|
|
return;
|
|
}
|
|
|
|
Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID);
|
|
Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID);
|
|
Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);
|
|
|
|
if (!ardonis || !player)
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
if (Phase > 4 && !pathaleon)
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
//Phase 1 Dawnforge say
|
|
switch (Phase)
|
|
{
|
|
case 1:
|
|
Talk(SAY_COMMANDER_DAWNFORGE_1);
|
|
++Phase;
|
|
Phase_Timer = 16000;
|
|
break;
|
|
//Phase 2 Ardonis say
|
|
case 2:
|
|
ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_1);
|
|
++Phase;
|
|
Phase_Timer = 16000;
|
|
break;
|
|
//Phase 3 Dawnforge say
|
|
case 3:
|
|
Talk(SAY_COMMANDER_DAWNFORGE_2);
|
|
++Phase;
|
|
Phase_Timer = 16000;
|
|
break;
|
|
//Phase 4 Pathaleon spawns up to phase 9
|
|
case 4:
|
|
//spawn pathaleon's image
|
|
me->SummonCreature(CreatureEntry[2], 2325.851563f, 2799.534668f, 133.084229f, 6.038996f, TEMPSUMMON_TIMED_DESPAWN, 90000);
|
|
++Phase;
|
|
Phase_Timer = 500;
|
|
break;
|
|
//Phase 5 Pathaleon say
|
|
case 5:
|
|
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_1);
|
|
++Phase;
|
|
Phase_Timer = 6000;
|
|
break;
|
|
//Phase 6
|
|
case 6:
|
|
switch (PhaseSubphase)
|
|
{
|
|
//Subphase 1: Turn Dawnforge and Ardonis
|
|
case 0:
|
|
Turn_to_Pathaleons_Image();
|
|
++PhaseSubphase;
|
|
Phase_Timer = 8000;
|
|
break;
|
|
//Subphase 2 Dawnforge say
|
|
case 1:
|
|
Talk(SAY_COMMANDER_DAWNFORGE_3);
|
|
PhaseSubphase = 0;
|
|
++Phase;
|
|
Phase_Timer = 8000;
|
|
break;
|
|
}
|
|
break;
|
|
//Phase 7 Pathaleons say 3 Sentence, every sentence need a subphase
|
|
case 7:
|
|
switch (PhaseSubphase)
|
|
{
|
|
//Subphase 1
|
|
case 0:
|
|
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2);
|
|
++PhaseSubphase;
|
|
Phase_Timer = 12000;
|
|
break;
|
|
//Subphase 2
|
|
case 1:
|
|
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_1);
|
|
++PhaseSubphase;
|
|
Phase_Timer = 16000;
|
|
break;
|
|
//Subphase 3
|
|
case 2:
|
|
pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_2);
|
|
PhaseSubphase = 0;
|
|
++Phase;
|
|
Phase_Timer = 10000;
|
|
break;
|
|
}
|
|
break;
|
|
//Phase 8 Dawnforge & Ardonis say
|
|
case 8:
|
|
Talk(SAY_COMMANDER_DAWNFORGE_4);
|
|
ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_2);
|
|
++Phase;
|
|
Phase_Timer = 4000;
|
|
break;
|
|
//Phase 9 Pathaleons Despawn, Reset Dawnforge & Ardonis angle
|
|
case 9:
|
|
Turn_to_eachother();
|
|
//hide pathaleon, unit will despawn shortly
|
|
pathaleon->SetVisible(false);
|
|
PhaseSubphase = 0;
|
|
++Phase;
|
|
Phase_Timer = 3000;
|
|
break;
|
|
//Phase 10 Dawnforge say
|
|
case 10:
|
|
Talk(SAY_COMMANDER_DAWNFORGE_5);
|
|
player->AreaExploredOrEventHappens(QUEST_INFO_GATHERING);
|
|
Reset();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
class at_commander_dawnforge : public AreaTriggerScript
|
|
{
|
|
public:
|
|
at_commander_dawnforge() : AreaTriggerScript("at_commander_dawnforge") { }
|
|
|
|
bool OnTrigger(Player* player, const AreaTrigger* /*at*/)
|
|
{
|
|
//if player lost aura or not have at all, we should not try start event.
|
|
if (!player->HasAura(SPELL_SUNFURY_DISGUISE))
|
|
return false;
|
|
|
|
if (player->IsAlive() && player->GetQuestStatus(QUEST_INFO_GATHERING) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
Creature* Dawnforge = player->FindNearestCreature(CreatureEntry[1], 30.0f);
|
|
if (!Dawnforge)
|
|
return false;
|
|
|
|
if (CAST_AI(npc_commander_dawnforge::npc_commander_dawnforgeAI, Dawnforge->AI())->CanStartEvent(player))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/*######
|
|
## npc_professor_dabiri
|
|
######*/
|
|
enum ProfessorDabiriData
|
|
{
|
|
SPELL_PHASE_DISTRUPTOR = 35780,
|
|
|
|
//WHISPER_DABIRI = 0, not existing in database
|
|
|
|
QUEST_DIMENSIUS = 10439,
|
|
QUEST_ON_NETHERY_WINGS = 10438,
|
|
};
|
|
|
|
#define GOSSIP_ITEM "I need a new phase distruptor, Professor"
|
|
|
|
class npc_professor_dabiri : public CreatureScript
|
|
{
|
|
public:
|
|
npc_professor_dabiri() : CreatureScript("npc_professor_dabiri") { }
|
|
|
|
//OnQuestAccept:
|
|
//if (quest->GetQuestId() == QUEST_DIMENSIUS)
|
|
//creature->AI()->Talk(WHISPER_DABIRI, player);
|
|
|
|
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
|
{
|
|
ClearGossipMenuFor(player);
|
|
if (action == GOSSIP_ACTION_INFO_DEF+1)
|
|
{
|
|
creature->CastSpell(player, SPELL_PHASE_DISTRUPTOR, false);
|
|
CloseGossipMenuFor(player);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OnGossipHello(Player* player, Creature* creature) override
|
|
{
|
|
if (creature->IsQuestGiver())
|
|
player->PrepareQuestMenu(creature->GetGUID());
|
|
|
|
if (player->GetQuestStatus(QUEST_ON_NETHERY_WINGS) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(29778))
|
|
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
|
|
|
|
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/*######
|
|
## npc_phase_hunter
|
|
######*/
|
|
|
|
enum PhaseHunterData
|
|
{
|
|
QUEST_RECHARGING_THE_BATTERIES = 10190,
|
|
|
|
NPC_PHASE_HUNTER_ENTRY = 18879,
|
|
NPC_DRAINED_PHASE_HUNTER_ENTRY = 19595,
|
|
|
|
EMOTE_WEAK = 0,
|
|
|
|
// Spells
|
|
SPELL_RECHARGING_BATTERY = 34219,
|
|
SPELL_PHASE_SLIP = 36574,
|
|
SPELL_MANA_BURN = 13321,
|
|
SPELL_MATERIALIZE = 34804,
|
|
SPELL_DE_MATERIALIZE = 34814,
|
|
};
|
|
|
|
class npc_phase_hunter : public CreatureScript
|
|
{
|
|
public:
|
|
npc_phase_hunter() : CreatureScript("npc_phase_hunter") { }
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new npc_phase_hunterAI(creature);
|
|
}
|
|
|
|
struct npc_phase_hunterAI : public ScriptedAI
|
|
{
|
|
npc_phase_hunterAI(Creature* creature) : ScriptedAI(creature) { }
|
|
|
|
bool Weak;
|
|
bool Materialize;
|
|
bool Drained;
|
|
uint8 WeakPercent;
|
|
|
|
uint64 PlayerGUID;
|
|
|
|
uint32 ManaBurnTimer;
|
|
|
|
void Reset()
|
|
{
|
|
Weak = false;
|
|
Materialize = false;
|
|
Drained = false;
|
|
WeakPercent = 25 + (rand() % 16); // 25-40
|
|
|
|
PlayerGUID = 0;
|
|
|
|
ManaBurnTimer = 5000 + (rand() % 3 * 1000); // 5-8 sec cd
|
|
|
|
if (me->GetEntry() == NPC_DRAINED_PHASE_HUNTER_ENTRY)
|
|
me->UpdateEntry(NPC_PHASE_HUNTER_ENTRY);
|
|
}
|
|
|
|
void EnterCombat(Unit* who)
|
|
{
|
|
if (who->GetTypeId() == TYPEID_PLAYER)
|
|
PlayerGUID = who->GetGUID();
|
|
}
|
|
|
|
//void SpellHit(Unit* /*caster*/, const SpellInfo* /*spell*/)
|
|
//{
|
|
// DoCast(me, SPELL_DE_MATERIALIZE);
|
|
//}
|
|
|
|
void UpdateAI(uint32 diff)
|
|
{
|
|
if (!Materialize)
|
|
{
|
|
DoCast(me, SPELL_MATERIALIZE);
|
|
Materialize = true;
|
|
}
|
|
|
|
if (me->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || me->HasUnitState(UNIT_STATE_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it
|
|
DoCast(me, SPELL_PHASE_SLIP);
|
|
|
|
if (!UpdateVictim())
|
|
return;
|
|
|
|
// some code to cast spell Mana Burn on random target which has mana
|
|
if (ManaBurnTimer <= diff)
|
|
{
|
|
std::list<HostileReference*> AggroList = me->getThreatManager().getThreatList();
|
|
std::list<Unit*> UnitsWithMana;
|
|
|
|
for (std::list<HostileReference*>::const_iterator itr = AggroList.begin(); itr != AggroList.end(); ++itr)
|
|
{
|
|
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
|
|
{
|
|
if (unit->GetCreateMana() > 0)
|
|
UnitsWithMana.push_back(unit);
|
|
}
|
|
}
|
|
if (!UnitsWithMana.empty())
|
|
{
|
|
DoCast(acore::Containers::SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN);
|
|
ManaBurnTimer = 8000 + (rand() % 10 * 1000); // 8-18 sec cd
|
|
}
|
|
else
|
|
ManaBurnTimer = 3500;
|
|
} else ManaBurnTimer -= diff;
|
|
|
|
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) // start: support for quest 10190
|
|
{
|
|
if (!Weak && HealthBelowPct(WeakPercent)
|
|
&& player->GetQuestStatus(QUEST_RECHARGING_THE_BATTERIES) == QUEST_STATUS_INCOMPLETE)
|
|
{
|
|
Talk(EMOTE_WEAK);
|
|
Weak = true;
|
|
}
|
|
if (Weak && !Drained && me->HasAura(SPELL_RECHARGING_BATTERY))
|
|
{
|
|
Drained = true;
|
|
int32 uHpPct = int32(me->GetHealthPct());
|
|
|
|
me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
|
|
|
|
me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
|
|
me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
|
|
me->SetInCombatWith(player);
|
|
}
|
|
} // end: support for quest 10190
|
|
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
};
|
|
|
|
/*######
|
|
## npc_bessy
|
|
######*/
|
|
enum BessyData
|
|
{
|
|
Q_ALMABTRIEB = 10337,
|
|
N_THADELL = 20464,
|
|
SPAWN_FIRST = 20512,
|
|
SPAWN_SECOND = 19881,
|
|
SAY_THADELL_1 = 0,
|
|
SAY_THADELL_2 = 1,
|
|
SAY_BESSY_0 = 0,
|
|
SAY_BESSY_1 = 1
|
|
};
|
|
|
|
class npc_bessy : public CreatureScript
|
|
{
|
|
public:
|
|
npc_bessy() : CreatureScript("npc_bessy") { }
|
|
|
|
bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest)
|
|
{
|
|
if (quest->GetQuestId() == Q_ALMABTRIEB)
|
|
{
|
|
creature->setFaction(113);
|
|
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
|
creature->AI()->Talk(SAY_BESSY_0);
|
|
CAST_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new npc_bessyAI(creature);
|
|
}
|
|
|
|
struct npc_bessyAI : public npc_escortAI
|
|
{
|
|
npc_bessyAI(Creature* creature) : npc_escortAI(creature) { }
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
if (Player* player = GetPlayerForEscort())
|
|
player->FailQuest(Q_ALMABTRIEB);
|
|
}
|
|
|
|
void WaypointReached(uint32 waypointId)
|
|
{
|
|
Player* player = GetPlayerForEscort();
|
|
if (!player)
|
|
return;
|
|
|
|
switch (waypointId)
|
|
{
|
|
case 3: //first spawn
|
|
Talk(SAY_BESSY_1);
|
|
me->SummonCreature(SPAWN_FIRST, 2449.67f, 2183.11f, 96.85f, 6.20f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
|
me->SummonCreature(SPAWN_FIRST, 2449.53f, 2184.43f, 96.36f, 6.27f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
|
me->SummonCreature(SPAWN_FIRST, 2449.85f, 2186.34f, 97.57f, 6.08f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
|
break;
|
|
case 7:
|
|
Talk(SAY_BESSY_1);
|
|
me->SummonCreature(SPAWN_SECOND, 2309.64f, 2186.24f, 92.25f, 6.06f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
|
me->SummonCreature(SPAWN_SECOND, 2309.25f, 2183.46f, 91.75f, 6.22f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
|
break;
|
|
case 12:
|
|
player->GroupEventHappens(Q_ALMABTRIEB, me);
|
|
if (me->FindNearestCreature(N_THADELL, 30))
|
|
Talk(SAY_THADELL_1);
|
|
break;
|
|
case 13:
|
|
if (me->FindNearestCreature(N_THADELL, 30))
|
|
Talk(SAY_THADELL_2, player);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JustSummoned(Creature* summoned)
|
|
{
|
|
summoned->AI()->AttackStart(me);
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
me->RestoreFaction();
|
|
me->SetReactState(REACT_PASSIVE);
|
|
}
|
|
};
|
|
};
|
|
|
|
/*######
|
|
## npc_maxx_a_million
|
|
######*/
|
|
|
|
enum MaxxAMillion
|
|
{
|
|
QUEST_MARK_V_IS_ALIVE = 10191,
|
|
GO_DRAENEI_MACHINE = 183771
|
|
};
|
|
|
|
class npc_maxx_a_million_escort : public CreatureScript
|
|
{
|
|
public:
|
|
npc_maxx_a_million_escort() : CreatureScript("npc_maxx_a_million_escort") { }
|
|
|
|
CreatureAI* GetAI(Creature* creature) const
|
|
{
|
|
return new npc_maxx_a_million_escortAI(creature);
|
|
}
|
|
|
|
struct npc_maxx_a_million_escortAI : public npc_escortAI
|
|
{
|
|
npc_maxx_a_million_escortAI(Creature* creature) : npc_escortAI(creature) { }
|
|
|
|
bool bTake;
|
|
uint32 uiTakeTimer;
|
|
|
|
void Reset()
|
|
{
|
|
bTake=false;
|
|
uiTakeTimer=3000;
|
|
}
|
|
|
|
void WaypointReached(uint32 waypointId)
|
|
{
|
|
Player* player = GetPlayerForEscort();
|
|
if (!player)
|
|
return;
|
|
|
|
switch (waypointId)
|
|
{
|
|
case 7:
|
|
case 17:
|
|
case 29:
|
|
//Find Object and "work"
|
|
if (GetClosestGameObjectWithEntry(me, GO_DRAENEI_MACHINE, INTERACTION_DISTANCE))
|
|
{
|
|
// take the GO -> animation
|
|
me->HandleEmoteCommand(EMOTE_STATE_LOOT);
|
|
SetEscortPaused(true);
|
|
bTake=true;
|
|
}
|
|
break;
|
|
case 36: //return and quest_complete
|
|
player->CompleteQuest(QUEST_MARK_V_IS_ALIVE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void JustDied(Unit* /*killer*/)
|
|
{
|
|
if (Player* player = GetPlayerForEscort())
|
|
player->FailQuest(QUEST_MARK_V_IS_ALIVE);
|
|
}
|
|
|
|
void UpdateAI(uint32 uiDiff)
|
|
{
|
|
npc_escortAI::UpdateAI(uiDiff);
|
|
|
|
if (bTake)
|
|
{
|
|
if (uiTakeTimer < uiDiff)
|
|
{
|
|
me->HandleEmoteCommand(EMOTE_STATE_NONE);
|
|
if (GameObject* go = GetClosestGameObjectWithEntry(me, GO_DRAENEI_MACHINE, INTERACTION_DISTANCE))
|
|
{
|
|
SetEscortPaused(false);
|
|
bTake=false;
|
|
uiTakeTimer = 3000;
|
|
go->Delete();
|
|
}
|
|
}
|
|
else
|
|
uiTakeTimer -= uiDiff;
|
|
}
|
|
DoMeleeAttackIfReady();
|
|
}
|
|
};
|
|
|
|
bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest)
|
|
{
|
|
if (quest->GetQuestId() == QUEST_MARK_V_IS_ALIVE)
|
|
{
|
|
if (npc_maxx_a_million_escortAI* pEscortAI = CAST_AI(npc_maxx_a_million_escort::npc_maxx_a_million_escortAI, creature->AI()))
|
|
{
|
|
creature->setFaction(113);
|
|
pEscortAI->Start(false, false, player->GetGUID());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void AddSC_netherstorm()
|
|
{
|
|
// Ours
|
|
new npc_captain_saeed();
|
|
|
|
// Theirs
|
|
new npc_commander_dawnforge();
|
|
new at_commander_dawnforge();
|
|
new npc_professor_dabiri();
|
|
new npc_phase_hunter();
|
|
new npc_bessy();
|
|
new npc_maxx_a_million_escort();
|
|
|
|
// Deathblow to the legion
|
|
new deathblow_to_the_legion_trigger();
|
|
new adyen_the_lightbringer();
|
|
new anchorite_karja();
|
|
new exarch_orelis();
|
|
new kaylaan_the_lost();
|
|
new socrethar();
|
|
}
|