/*
* This file is part of the TrinityCore 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 "AreaTrigger.h"
#include "AreaTriggerAI.h"
#include "CellImpl.h"
#include "Containers.h"
#include "Conversation.h"
#include "ConversationAI.h"
#include "CreatureAIImpl.h"
#include "EventProcessor.h"
#include "GridNotifiersImpl.h"
#include "MapUtils.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "PassiveAI.h"
#include "PhasingHandler.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "TemporarySummon.h"
enum MardumSpellData
{
SPELL_START_DEMON_HUNTER_PLAY_SCENE = 193525
};
enum MardumQuestData
{
QUEST_DEMON_HUNTER_INTRO_TRACKER = 40076
};
enum MardumConversationData
{
CONVO_DEMONHUNTER_INTRO_START = 705
};
enum MardumSoundData
{
SOUND_METAL_WEAPON_UNSHEATH = 700,
SOUND_SPELL_DOUBLE_JUMP = 53780,
};
class scene_demonhunter_intro : public SceneScript
{
public:
scene_demonhunter_intro() : SceneScript("scene_demonhunter_intro") { }
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
Conversation::CreateConversation(CONVO_DEMONHUNTER_INTRO_START, player, *player, player->GetGUID(), nullptr);
}
void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
PhasingHandler::OnConditionChange(player);
}
};
// 196030 - Start: Quest Invis
class spell_demon_hunter_intro_aura : public AuraScript
{
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->CastSpell(nullptr, SPELL_START_DEMON_HUNTER_PLAY_SCENE, true);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_demon_hunter_intro_aura::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
enum TheInvasionBeginsQuestData
{
QUEST_THE_INVASION_BEGINS = 40077,
CONVO_THE_INVASION_BEGINS = 922,
NPC_KAYN_SUNFURY_INVASION_BEGINS = 93011,
NPC_JAYCE_DARKWEAVER_INVASION_BEGINS = 98228,
NPC_ALLARI_THE_SOULEATER_INVASION_BEGINS = 98227,
NPC_CYANA_NIGHTGLAIVE_INVASION_BEGINS = 98290,
NPC_KORVAS_BLOODTHORN_INVASION_BEGINS = 98292,
NPC_SEVIS_BRIGHTFLAME_INVASION_BEGINS = 99918,
NPC_WRATH_WARRIOR_INVASION_BEGINS = 94580,
SPELL_THE_INVASION_BEGINS = 187382,
SPELL_TRACK_TARGET_IN_CHANNEL = 175799,
SPELL_DEMON_HUNTER_GLIDE_STATE = 199303
};
enum TheInvasionsBeginsWaypointData
{
// Kayn
PATH_KAYN_ATTACK_DEMON = 9301100,
PATH_KAYN_AFTER_DEMON = 9301101,
// Path before Jump
PATH_JAYCE_INVASION_BEGINS = 9822800,
PATH_ALLARI_INVASION_BEGINS = 9822700,
PATH_CYANA_INVASION_BEGINS = 9829000,
PATH_KORVAS_INVASION_BEGINS = 9829200,
PATH_SEVIS_INVASION_BEGINS = 9991800,
// Path after Jump
PATH_JAYCE_JUMP_INVASION_BEGINS = 9822801,
PATH_ALLARI_JUMP_INVASION_BEGINS = 9822701,
PATH_CYANA_JUMP_INVASION_BEGINS = 9829001,
PATH_KORVAS_JUMP_INVASION_BEGINS = 9829201,
PATH_SEVIS_JUMP_INVASION_BEGINS = 9991801,
POINT_ILLIDARI_LAND_POS = 1,
POINT_KAYN_TRIGGER_DOUBLE_JUMP = 2,
POINT_KAYN_MOVE_TO_DEMON = 3,
};
enum TheInvasionBeginsAnimKitsData
{
ANIM_DH_WINGS = 58110,
ANIM_DH_RUN = 9767,
ANIM_DH_RUN_ALLARI = 9180,
};
enum TheInvasionBeginsVisualData
{
SPELL_VISUAL_KIT_KAYN_GLIDE = 59738,
SPELL_VISUAL_KIT_KAYN_WINGS = 59406,
SPELL_VISUAL_KIT_KAYN_DOUBLE_JUMP = 58110,
SPELL_VISUAL_KIT_KORVAS_JUMP = 63071,
SPELL_VISUAL_KIT_WRATH_WARRIOR_DIE = 58476,
};
Position const WrathWarriorSpawnPosition = { 1081.9166f, 3183.8716f, 26.335993f };
Position const KaynJumpPos = { 1172.17f, 3202.55f, 54.3479f };
Position const KaynDoubleJumpPosition = { 1094.2384f, 3186.058f, 28.81562f };
Position const JayceJumpPos = { 1119.24f, 3203.42f, 38.1061f };
Position const AllariJumpPos = { 1120.08f, 3197.2f, 36.8502f };
Position const KorvasJumpPos = { 1117.89f, 3196.24f, 36.2158f };
Position const SevisJumpPos = { 1120.74f, 3199.47f, 37.5157f };
Position const CyanaJumpPos = { 1120.34f, 3194.28f, 36.4321f };
// 93011 - Kayn Sunfury
struct npc_kayn_sunfury_invasion_begins : public ScriptedAI
{
npc_kayn_sunfury_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void OnQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_THE_INVASION_BEGINS)
{
PhasingHandler::OnConditionChange(player);
player->CastSpell(WrathWarriorSpawnPosition, SPELL_THE_INVASION_BEGINS, false);
Conversation::CreateConversation(CONVO_THE_INVASION_BEGINS, player, *player, player->GetGUID(), nullptr, false);
}
}
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_KAYN_ATTACK_DEMON)
{
Creature* wrathWarrior = me->FindNearestCreatureWithOptions(100.0f, { .CreatureId = NPC_WRATH_WARRIOR_INVASION_BEGINS, .IgnorePhases = true, .OwnerGuid = me->GetOwnerGUID() });
if (!wrathWarrior)
return;
me->SetFacingToObject(wrathWarrior);
wrathWarrior->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_WRATH_WARRIOR_DIE, 0, 0);
wrathWarrior->KillSelf();
_scheduler.Schedule(600ms, [this](TaskContext /*context*/)
{
me->GetMotionMaster()->MovePath(PATH_KAYN_AFTER_DEMON, false);
});
}
else if (pathId == PATH_KAYN_AFTER_DEMON)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_KAYN_TRIGGER_DOUBLE_JUMP)
{
TempSummon* summon = me->ToTempSummon();
if (!summon)
return;
WorldObject* summoner = summon->GetSummoner();
if (!summoner)
return;
Player* summonerPlayer = summoner->ToPlayer();
if (!summonerPlayer)
return;
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_KAYN_WINGS, 4, 3000);
me->PlayObjectSound(SOUND_SPELL_DOUBLE_JUMP, me->GetGUID(), summonerPlayer);
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_KAYN_DOUBLE_JUMP, 0, 0);
me->GetMotionMaster()->MoveJumpWithGravity(KaynDoubleJumpPosition, 24.0, 0.9874f, POINT_KAYN_MOVE_TO_DEMON);
}
else if (pointId == POINT_KAYN_MOVE_TO_DEMON)
{
me->SetAIAnimKitId(ANIM_DH_RUN);
me->GetMotionMaster()->MovePath(PATH_KAYN_ATTACK_DEMON, false);
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
// 98228 - Jayce Darkweaver
struct npc_jayce_darkweaver_invasion_begins : public ScriptedAI
{
npc_jayce_darkweaver_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_JAYCE_INVASION_BEGINS)
{
me->CastSpell(nullptr, SPELL_DEMON_HUNTER_GLIDE_STATE, true);
me->GetMotionMaster()->MoveJumpWithGravity(JayceJumpPos, 12.0f, 15.2792f, POINT_ILLIDARI_LAND_POS);
}
else if (pathId == PATH_JAYCE_JUMP_INVASION_BEGINS)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_ILLIDARI_LAND_POS)
{
me->RemoveAurasDueToSpell(SPELL_DEMON_HUNTER_GLIDE_STATE);
me->GetMotionMaster()->MovePath(PATH_JAYCE_JUMP_INVASION_BEGINS, false);
}
}
};
// 98227 - Allari the Souleater
struct npc_allari_the_souleater_invasion_begins : public ScriptedAI
{
npc_allari_the_souleater_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_ALLARI_INVASION_BEGINS)
{
me->CastSpell(nullptr, SPELL_DEMON_HUNTER_GLIDE_STATE, true);
me->GetMotionMaster()->MoveJumpWithGravity(AllariJumpPos, 12.0f, 9.2722f, POINT_ILLIDARI_LAND_POS);
}
else if (pathId == PATH_ALLARI_JUMP_INVASION_BEGINS)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_ILLIDARI_LAND_POS)
{
me->RemoveAurasDueToSpell(SPELL_DEMON_HUNTER_GLIDE_STATE);
me->GetMotionMaster()->MovePath(PATH_ALLARI_JUMP_INVASION_BEGINS, false);
}
}
};
// 98292 - Korvas Bloodthorn
struct npc_korvas_bloodthorn_invasion_begins : public ScriptedAI
{
npc_korvas_bloodthorn_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_KORVAS_INVASION_BEGINS)
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_KORVAS_JUMP, 4, 2000);
me->GetMotionMaster()->MoveJumpWithGravity(KorvasJumpPos, 24.0f, 19.2911f, POINT_ILLIDARI_LAND_POS);
}
else if (pathId == PATH_KORVAS_JUMP_INVASION_BEGINS)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_ILLIDARI_LAND_POS)
{
me->RemoveAurasDueToSpell(SPELL_DEMON_HUNTER_GLIDE_STATE);
me->GetMotionMaster()->MovePath(PATH_KORVAS_JUMP_INVASION_BEGINS, false);
}
}
};
// 99918 - Sevis Brightflame
struct npc_sevis_brightflame_invasion_begins : public ScriptedAI
{
npc_sevis_brightflame_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_SEVIS_INVASION_BEGINS)
{
me->CastSpell(nullptr, SPELL_DEMON_HUNTER_GLIDE_STATE, true);
me->GetMotionMaster()->MoveJumpWithGravity(SevisJumpPos, 12.0f, 13.3033f, POINT_ILLIDARI_LAND_POS);
}
else if (pathId == PATH_SEVIS_JUMP_INVASION_BEGINS)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_ILLIDARI_LAND_POS)
{
me->RemoveAurasDueToSpell(SPELL_DEMON_HUNTER_GLIDE_STATE);
me->GetMotionMaster()->MovePath(PATH_SEVIS_JUMP_INVASION_BEGINS, false);
}
}
};
// 98290 - Cyana Nightglaive
struct npc_cyana_nightglaive_invasion_begins : public ScriptedAI
{
npc_cyana_nightglaive_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_CYANA_INVASION_BEGINS)
{
me->CastSpell(nullptr, SPELL_DEMON_HUNTER_GLIDE_STATE, true);
me->GetMotionMaster()->MoveJumpWithGravity(CyanaJumpPos, 12.0f, 8.4555f, POINT_ILLIDARI_LAND_POS);
}
else if (pathId == PATH_CYANA_JUMP_INVASION_BEGINS)
me->DespawnOrUnsummon();
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE)
return;
if (pointId == POINT_ILLIDARI_LAND_POS)
{
me->RemoveAurasDueToSpell(SPELL_DEMON_HUNTER_GLIDE_STATE);
me->GetMotionMaster()->MovePath(PATH_CYANA_JUMP_INVASION_BEGINS, false);
}
}
};
// 922 - The Invasion Begins
class conversation_the_invasion_begins : public ConversationAI
{
public:
conversation_the_invasion_begins(Conversation* conversation) : ConversationAI(conversation) { }
enum TheInvasionBeginsConversationData
{
CONVO_LINE_TRIGGER_FACING = 2529,
CONVO_LINE_START_PATH = 2288,
CONVO_ACTOR_IDX_KAYN = 1,
CONVO_ACTOR_IDX_KORVAS = 2,
};
enum TheInvasionBeginsEventData
{
EVENT_ILLIDARI_FACE_PLAYERS = 1,
EVENT_ILLIDARI_START_PATH
};
void OnCreate(Unit* creator) override
{
Creature* kaynObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_KAYN_SUNFURY_INVASION_BEGINS, .IgnorePhases = true });
Creature* jayceObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_JAYCE_DARKWEAVER_INVASION_BEGINS, .IgnorePhases = true });
Creature* allariaObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_ALLARI_THE_SOULEATER_INVASION_BEGINS, .IgnorePhases = true });
Creature* cyanaObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_CYANA_NIGHTGLAIVE_INVASION_BEGINS, .IgnorePhases = true });
Creature* korvasObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_KORVAS_BLOODTHORN_INVASION_BEGINS, .IgnorePhases = true });
Creature* sevisObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_SEVIS_BRIGHTFLAME_INVASION_BEGINS, .IgnorePhases = true });
if (!kaynObject || !jayceObject || !allariaObject || !cyanaObject || !korvasObject || !sevisObject)
return;
TempSummon* kaynClone = kaynObject->SummonPersonalClone(kaynObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
TempSummon* jayceClone = jayceObject->SummonPersonalClone(jayceObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
TempSummon* allariaClone = allariaObject->SummonPersonalClone(allariaObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
TempSummon* cyanaClone = cyanaObject->SummonPersonalClone(cyanaObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
TempSummon* korvasClone = korvasObject->SummonPersonalClone(korvasObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
TempSummon* sevisClone = sevisObject->SummonPersonalClone(sevisObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer());
if (!kaynClone || !jayceClone || !allariaClone || !cyanaClone || !korvasClone || !sevisClone)
return;
_jayceGUID = jayceClone->GetGUID();
_allariGUID = allariaClone->GetGUID();
_cyanaGUID = cyanaClone->GetGUID();
_sevisGUID = sevisClone->GetGUID();
allariaClone->SetAIAnimKitId(ANIM_DH_RUN_ALLARI);
kaynClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER));
conversation->AddActor(CONVO_THE_INVASION_BEGINS, CONVO_ACTOR_IDX_KAYN, kaynClone->GetGUID());
conversation->AddActor(CONVO_THE_INVASION_BEGINS, CONVO_ACTOR_IDX_KORVAS, korvasClone->GetGUID());
conversation->Start();
}
void OnStart() override
{
LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale();
if (Milliseconds const* illidariFacingLineStarted = conversation->GetLineStartTime(privateOwnerLocale, CONVO_LINE_TRIGGER_FACING))
_events.ScheduleEvent(EVENT_ILLIDARI_FACE_PLAYERS, *illidariFacingLineStarted);
if (Milliseconds const* illidariStartPathLineStarted = conversation->GetLineStartTime(privateOwnerLocale, CONVO_LINE_START_PATH))
_events.ScheduleEvent(EVENT_ILLIDARI_START_PATH, *illidariStartPathLineStarted);
}
void StartCloneChannel(ObjectGuid guid)
{
Unit* privateObjectOwner = ObjectAccessor::GetUnit(*conversation, conversation->GetPrivateObjectOwner());
if (!privateObjectOwner)
return;
Creature* clone = ObjectAccessor::GetCreature(*conversation, guid);
if (!clone)
return;
clone->CastSpell(privateObjectOwner, SPELL_TRACK_TARGET_IN_CHANNEL, false);
}
void StartCloneMovement(ObjectGuid cloneGUID, uint32 pathId, uint32 animKit)
{
Creature* clone = ObjectAccessor::GetCreature(*conversation, cloneGUID);
if (!clone)
return;
clone->InterruptNonMeleeSpells(true);
clone->GetMotionMaster()->MovePath(pathId, false);
if (animKit)
clone->SetAIAnimKitId(animKit);
}
void OnUpdate(uint32 diff) override
{
_events.Update(diff);
switch (_events.ExecuteEvent())
{
case EVENT_ILLIDARI_FACE_PLAYERS:
{
StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KAYN)->GetGUID());
StartCloneChannel(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID());
StartCloneChannel(_jayceGUID);
StartCloneChannel(_allariGUID);
StartCloneChannel(_cyanaGUID);
StartCloneChannel(_sevisGUID);
break;
}
case EVENT_ILLIDARI_START_PATH:
{
Creature* kaynClone = conversation->GetActorCreature(CONVO_ACTOR_IDX_KAYN);
if (!kaynClone)
break;
Unit* privateObjectOwner = ObjectAccessor::GetUnit(*conversation, conversation->GetPrivateObjectOwner());
if (!privateObjectOwner)
return;
Player* player = privateObjectOwner->ToPlayer();
if (!player)
return;
kaynClone->PlayObjectSound(SOUND_METAL_WEAPON_UNSHEATH, kaynClone->GetGUID(), player);
kaynClone->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_KAYN_GLIDE, 4, 3000);
kaynClone->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_KAYN_WINGS, 4, 4000);
kaynClone->GetMotionMaster()->MoveJumpWithGravity(KaynJumpPos, 20.5f, 396.3535f, POINT_KAYN_TRIGGER_DOUBLE_JUMP);
kaynClone->SetSheath(SHEATH_STATE_MELEE);
kaynClone->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
StartCloneMovement(conversation->GetActorUnit(CONVO_ACTOR_IDX_KORVAS)->GetGUID(), PATH_KORVAS_INVASION_BEGINS, ANIM_DH_RUN);
StartCloneMovement(_jayceGUID, PATH_JAYCE_INVASION_BEGINS, 0);
StartCloneMovement(_allariGUID, PATH_ALLARI_INVASION_BEGINS, ANIM_DH_RUN_ALLARI);
StartCloneMovement(_cyanaGUID, PATH_CYANA_INVASION_BEGINS, 0);
StartCloneMovement(_sevisGUID, PATH_SEVIS_INVASION_BEGINS, ANIM_DH_RUN);
break;
}
default:
break;
}
}
private:
ObjectGuid _jayceGUID;
ObjectGuid _allariGUID;
ObjectGuid _cyanaGUID;
ObjectGuid _sevisGUID;
EventMap _events;
};
// 98459 - Kayn Sunfury
// 98458 - Jayce Darkweaver
// 98456 - Allari the Souleater
// 98460 - Korvas Bloodthorn
// 99919 - Sevis Brightflame
// 98457 - Cyana Nightglaive
struct npc_illidari_fighting_invasion_begins : public ScriptedAI
{
npc_illidari_fighting_invasion_begins(Creature* creature) : ScriptedAI(creature) { }
enum IllidariFightingSpells
{
SPELL_ILLIDARI_CHAOS_STRIKE = 197639,
SPELL_ILLIDARI_FEL_RUSH = 200879,
};
enum IllidariFightingEvents
{
EVENT_CHAOS_STRIKE = 1,
EVENT_FEL_RUSH
};
Unit* GetNextTarget()
{
std::list targetList;
Trinity::AnyUnfriendlyUnitInObjectRangeCheck checker(me, me, 100.0f);
Trinity::UnitListSearcher searcher(me, targetList, checker);
Cell::VisitAllObjects(me, searcher, 100.0f);
targetList.remove_if([](Unit* possibleTarget)
{
return possibleTarget->isAttackingPlayer();
});
return Trinity::Containers::SelectRandomContainerElement(targetList);
}
void ScheduleTargetSelection()
{
_oocScheduler.Schedule(200ms, [this](TaskContext context)
{
Unit* target = GetNextTarget();
if (!target)
{
context.Repeat(500ms);
return;
}
AttackStart(target);
});
}
void JustAppeared() override
{
ScheduleTargetSelection();
}
void Reset() override
{
_events.Reset();
}
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_CHAOS_STRIKE, 5s);
_events.ScheduleEvent(EVENT_FEL_RUSH, 7s);
}
void EnterEvadeMode(EvadeReason why) override
{
// manualling calling it to not move to home position but move to next target instead
_EnterEvadeMode(why);
Reset();
ScheduleTargetSelection();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
_oocScheduler.Update(diff);
return;
}
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (_events.ExecuteEvent())
{
case EVENT_CHAOS_STRIKE:
DoCastVictim(SPELL_ILLIDARI_CHAOS_STRIKE);
_events.ScheduleEvent(EVENT_CHAOS_STRIKE, 5s);
break;
case EVENT_FEL_RUSH:
DoCastVictim(SPELL_ILLIDARI_FEL_RUSH);
_events.ScheduleEvent(SPELL_ILLIDARI_FEL_RUSH, 7s);
break;
default:
break;
}
}
private:
EventMap _events;
TaskScheduler _oocScheduler;
};
enum ETIAshtongueIntroData
{
QUEST_ENTER_THE_ILLIDARI_ASHTONGUE = 40378,
NPC_KAYN_SUNFURY_ASHTONGUE = 98229,
NPC_KORVAS_BLOODTHORN_ASHTONGUE = 98354,
NPC_SEVIS_BRIGHTFLAME_ASHTONGUE = 99916,
NPC_ALLARI_SOULEATER_ASHTONGUE = 94410,
DISPLAY_ID_SEVIS_MOUNT = 64385,
SAY_KAYN_ACTIVATE_GATEWAY = 0,
SAY_KAYN_CUT_A_HOLE = 1,
SAY_KORVAS_SLAY_MORE_DEMONS = 0,
SAY_SEVIS_SAY_FIND_ALLARI = 1,
SPELL_VISUAL_KIT_SEVIS_MOUNT = 36264,
SPELL_CAST_MOUNT_DH_FELSABER = 200175,
SPELL_ASHTONGUE_FELLSABER_KILL_CREDIT = 200254,
PATH_KAYN_SUNFURY_NEAR_TELEPORT = 9822900,
PATH_KORVAS_BLOODTHORN_NEAR_TELEPORT = 9835400,
PATH_SEVIS_BRIGHTFLAME_GATEWAY = 9991600,
};
// 98229 - Kayn Sunfury
struct npc_kayn_sunfury_ashtongue_intro : public ScriptedAI
{
npc_kayn_sunfury_ashtongue_intro(Creature* creature) : ScriptedAI(creature) { }
void OnQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_ENTER_THE_ILLIDARI_ASHTONGUE)
{
PhasingHandler::OnConditionChange(player);
Creature* kaynObject = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = NPC_KAYN_SUNFURY_ASHTONGUE, .IgnorePhases = true });
Creature* korvasObject = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = NPC_KORVAS_BLOODTHORN_ASHTONGUE, .IgnorePhases = true });
if (!kaynObject || !korvasObject)
return;
TempSummon* kaynClone = kaynObject->SummonPersonalClone(kaynObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
TempSummon* korvasClone = korvasObject->SummonPersonalClone(korvasObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
if (!kaynClone || !korvasClone)
return;
korvasClone->SetEmoteState(EMOTE_STATE_READY1H);
kaynClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_QUESTGIVER));
}
}
};
// 98229 - Kayn Sunfury
struct npc_kayn_sunfury_ashtongue_intro_private : public ScriptedAI
{
npc_kayn_sunfury_ashtongue_intro_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
Creature* korvasObject = GetClosestCreatureWithOptions(me, 10.0f, { .CreatureId = NPC_KORVAS_BLOODTHORN_ASHTONGUE, .IgnorePhases = true, .PrivateObjectOwnerGuid = me->GetPrivateObjectOwner()});
if (!korvasObject)
return;
ObjectGuid korvasGuid = korvasObject->GetGUID();
_scheduler.Schedule(1s, [this, korvasGuid](TaskContext task)
{
Unit* privateObjectOwner = ObjectAccessor::GetUnit(*me, me->GetPrivateObjectOwner());
if (!privateObjectOwner)
return;
Unit* korvas = ObjectAccessor::GetUnit(*me, korvasGuid);
if (!korvas)
return;
Talk(SAY_KAYN_ACTIVATE_GATEWAY, me);
me->CastSpell(privateObjectOwner, SPELL_TRACK_TARGET_IN_CHANNEL, false);
korvas->CastSpell(privateObjectOwner, SPELL_TRACK_TARGET_IN_CHANNEL, false);
task.Schedule(6s, [this, korvasGuid](TaskContext task)
{
Talk(SAY_KAYN_CUT_A_HOLE, me);
task.Schedule(6s, [this, korvasGuid](TaskContext task)
{
Creature* korvas = ObjectAccessor::GetCreature(*me, korvasGuid);
if (!korvas)
return;
if (!korvas->IsAIEnabled())
return;
korvas->AI()->Talk(SAY_KORVAS_SLAY_MORE_DEMONS, me);
me->InterruptNonMeleeSpells(true);
me->GetMotionMaster()->MovePath(PATH_KAYN_SUNFURY_NEAR_TELEPORT, false);
me->SetAIAnimKitId(ANIM_DH_RUN);
me->DespawnOrUnsummon(10s);
task.Schedule(2s, [this, korvasGuid](TaskContext /*task*/)
{
Creature* korvas = ObjectAccessor::GetCreature(*me, korvasGuid);
if (!korvas)
return;
korvas->InterruptNonMeleeSpells(true);
korvas->GetMotionMaster()->MovePath(PATH_KORVAS_BLOODTHORN_NEAR_TELEPORT, false);
korvas->SetAIAnimKitId(ANIM_DH_RUN);
korvas->DespawnOrUnsummon(12s);
});
});
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* KaynSunfuryNearLegionBannerAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_kayn_sunfury_ashtongue_intro_private(creature);
return new npc_kayn_sunfury_ashtongue_intro(creature);
};
// 1053 - Enter the Illidari: Ashtongue
class scene_enter_the_illidari_ashtongue : public SceneScript
{
public:
scene_enter_the_illidari_ashtongue() : SceneScript("scene_enter_the_illidari_ashtongue") { }
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
Creature* sevisObject = GetClosestCreatureWithOptions(player, 30.0f, { .CreatureId = NPC_SEVIS_BRIGHTFLAME_ASHTONGUE, .IgnorePhases = true });
if (!sevisObject)
return;
TempSummon* sevisClone = sevisObject->SummonPersonalClone(sevisObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
if (!sevisClone)
return;
sevisClone->CastSpell(player, SPELL_TRACK_TARGET_IN_CHANNEL, false);
sevisClone->DespawnOrUnsummon(15s);
}
void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override
{
if (triggerName == "SEEFELSABERCREDIT")
player->CastSpell(player, SPELL_ASHTONGUE_FELLSABER_KILL_CREDIT, true);
else if (triggerName == "UPDATEPHASE")
PhasingHandler::OnConditionChange(player);
}
};
// 99916 - Sevis Brightflame (Ashtongue Gateway)
struct npc_sevis_brightflame_ashtongue_gateway_private : public ScriptedAI
{
npc_sevis_brightflame_ashtongue_gateway_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
_scheduler.Schedule(1s, [this](TaskContext task)
{
Talk(SAY_SEVIS_SAY_FIND_ALLARI, me);
task.Schedule(2s, [this](TaskContext task)
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SEVIS_MOUNT, 0, 0);
me->SetMountDisplayId(DISPLAY_ID_SEVIS_MOUNT);
task.Schedule(3s, [this](TaskContext /*task*/)
{
me->InterruptNonMeleeSpells(true);
me->GetMotionMaster()->MovePath(PATH_SEVIS_BRIGHTFLAME_GATEWAY, false);
});
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* SevisBrightflameAshtongueGatewayAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_sevis_brightflame_ashtongue_gateway_private(creature);
return new NullCreatureAI(creature);
};
// 200255 - Accepting Felsaber Gift
class spell_accepting_felsaber_gift : public SpellScript
{
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(nullptr, SPELL_CAST_MOUNT_DH_FELSABER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_accepting_felsaber_gift::HandleHitTarget, EFFECT_3, SPELL_EFFECT_DUMMY);
}
};
// 32 - Mardum - Trigger KillCredit for Quest "Enter the Illidari: Ashtongue"
struct at_enter_the_illidari_ashtongue_allari_killcredit : AreaTriggerAI
{
at_enter_the_illidari_ashtongue_allari_killcredit(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
Player* player = unit->ToPlayer();
if (!player || player->GetQuestStatus(QUEST_ENTER_THE_ILLIDARI_ASHTONGUE) != QUEST_STATUS_INCOMPLETE)
return;
player->KilledMonsterCredit(NPC_ALLARI_SOULEATER_ASHTONGUE);
}
};
enum ETICoilskarIntroData
{
NPC_SEVIS_BRIGHTFLAME_COILSKAR = 99917,
SAY_SEVIS_SAY_MEET_AT_LAST_GATEWAY = 2,
PATH_SEVIS_BRIGHTFLAME_COILSKAR = 9991700
};
// 1077 - Enter the Illidari: Coilskar
class scene_enter_the_illidari_coilskar : public SceneScript
{
public:
scene_enter_the_illidari_coilskar() : SceneScript("scene_enter_the_illidari_coilskar") { }
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
PhasingHandler::OnConditionChange(player);
Creature* sevisObject = GetClosestCreatureWithOptions(player, 30.0f, { .CreatureId = NPC_SEVIS_BRIGHTFLAME_COILSKAR, .IgnorePhases = true });
if (!sevisObject)
return;
sevisObject->SummonPersonalClone(sevisObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
}
};
// 99917 - Sevis Brightflame (Coilskar Gateway)
struct npc_sevis_brightflame_coilskar_gateway_private : public ScriptedAI
{
npc_sevis_brightflame_coilskar_gateway_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
TempSummon* summon = me->ToTempSummon();
if (!summon)
return;
Unit* summoner = summon->GetSummonerUnit();
if (!summoner)
return;
me->SetFacingToObject(summoner);
me->DespawnOrUnsummon(14s);
_scheduler.Schedule(1s, [this](TaskContext task)
{
Talk(SAY_SEVIS_SAY_MEET_AT_LAST_GATEWAY, me);
task.Schedule(2s, [this](TaskContext task)
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SEVIS_MOUNT, 0, 0);
me->SetMountDisplayId(DISPLAY_ID_SEVIS_MOUNT);
task.Schedule(3s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_SEVIS_BRIGHTFLAME_COILSKAR, false);
});
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* SevisBrightflameCoilskarGatewayAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_sevis_brightflame_coilskar_gateway_private(creature);
return new NullCreatureAI(creature);
};
enum EyeOnThePrizeData
{
NPC_COLOSSAL_INFERNAL_BALEFUL = 96159,
QUEST_EYE_ON_THE_PRIZE = 39049,
DISPLAYID_BALEFUL_EYE = 38795,
// Inquisitor Baleful text
SAY_BALEFUL_AGGRO = 0,
SAY_BALEFUL_AEGIS = 1,
SAY_BALEFUL_DEATH = 2,
// Inquisitor Baleful events
EVENT_BALEFUL_MIND_SPIKE = 1,
EVENT_BALEFUL_BEAMING_GAZE,
EVENT_BALEFUL_INCITE_MADNESS,
EVENT_BALEFUL_COLOSS_INFERNAL_SMASH,
// Inquisitor Baleful points
POINT_BALEFUL_AEGIS_UP = 1,
POINT_BALEFUL_AEGIS_DOWN,
// Inquisitor Baleful actions
ACTION_BALEFUL_AEGIS_DOWN = 1,
// Inquisitor Baleful spells
SPELL_BALEFUL_MIND_SPIKE = 194519,
SPELL_BALEFUL_BEAMING_GAZE = 195058,
SPELL_BALEFUL_INCITE_MADNESS = 194529,
SPELL_BALEFUL_LEGION_AEGIS = 192665,
SPELL_BALEFUL_DIE_KNOCKBACK = 190742,
SPELL_BALEFUL_TAKING_POWER = 203925,
SPELL_BALEFUL_KILL_CREDIT = 188559,
// Baleful Infernal Coloss
SPELL_BALEFUL_COLOSS_INFERNAL_SMASH = 192709,
SPELL_BALEFUL_COLOSS_INFERNAL_SMASH_CAST = 183938,
// Baleful Beaming Eye
SPELL_BALEFUL_BEAMING_EYE_SUMMON = 195061,
SPELL_BALEFUL_BEAMING_EYE_CREATE_AT = 195051
};
class BalefulColossSmashEvent : public BasicEvent
{
public:
BalefulColossSmashEvent(Creature* owner) : BasicEvent(), _owner(owner) { }
bool Execute(uint64, uint32) override
{
Unit* target = _owner->AI()->SelectTarget(SelectTargetMethod::Random, 0, 150.0f, true);
_owner->CastSpell(target, SPELL_BALEFUL_COLOSS_INFERNAL_SMASH, false);
return true;
}
private:
Creature* _owner;
};
Position const BalefulAegisPos = { 592.4335f, 2433.1067f, -62.91178f };
// 93105 - Inquisitor Baleful
struct npc_inquisitor_baleful_molten_shore : public ScriptedAI
{
npc_inquisitor_baleful_molten_shore(Creature* creature) : ScriptedAI(creature), _castedLegionAegis(false) { }
void JustAppeared() override
{
// Blizz use a personal spawn for every DH on Quest: 39049 which leads to issues
TempSummon* balefulColoss = me->SummonCreature(NPC_COLOSSAL_INFERNAL_BALEFUL, 523.4045f, 2428.4113f, -117.0033f, 0.10887321f, TEMPSUMMON_MANUAL_DESPAWN, 0s);
if (!balefulColoss)
return;
_balefulColossGUID = balefulColoss->GetGUID();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_BALEFUL_AGGRO);
_events.ScheduleEvent(EVENT_BALEFUL_MIND_SPIKE, 3s);
_events.ScheduleEvent(EVENT_BALEFUL_BEAMING_GAZE, 7s);
_events.ScheduleEvent(EVENT_BALEFUL_INCITE_MADNESS, 11s);
}
void DoAction(int32 action) override
{
if (action == ACTION_BALEFUL_AEGIS_DOWN)
me->GetMotionMaster()->MovePoint(POINT_BALEFUL_AEGIS_DOWN, me->GetHomePosition());
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != POINT_MOTION_TYPE)
return;
if (pointId == POINT_BALEFUL_AEGIS_UP)
me->SetFacingTo(0.19842f);
else if (pointId == POINT_BALEFUL_AEGIS_DOWN)
me->SetReactState(REACT_AGGRESSIVE);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (!_castedLegionAegis && me->HealthBelowPctDamaged(60, damage))
{
if (Creature* balefulColoss = ObjectAccessor::GetCreature(*me, _balefulColossGUID))
{
balefulColoss->m_Events.AddEventAtOffset(new BalefulColossSmashEvent(balefulColoss), 1s);
balefulColoss->m_Events.AddEventAtOffset(new BalefulColossSmashEvent(balefulColoss), 4s);
balefulColoss->m_Events.AddEventAtOffset(new BalefulColossSmashEvent(balefulColoss), 8s);
balefulColoss->m_Events.AddEventAtOffset(new BalefulColossSmashEvent(balefulColoss), 13s);
}
DoCast(SPELL_BALEFUL_LEGION_AEGIS);
me->SetReactState(REACT_PASSIVE);
Talk(SAY_BALEFUL_AEGIS);
me->GetMotionMaster()->MovePoint(POINT_BALEFUL_AEGIS_UP, BalefulAegisPos);
_castedLegionAegis = true;
}
}
void Reset() override
{
_castedLegionAegis = false;
_events.Reset();
}
void JustDied(Unit* /*killer*/) override
{
DoCast(SPELL_BALEFUL_DIE_KNOCKBACK);
Talk(SAY_BALEFUL_DEATH);
if (Creature* balefulColoss = ObjectAccessor::GetCreature(*me, _balefulColossGUID))
balefulColoss->KillSelf();
for (ObjectGuid tapperGUID : me->GetTapList())
{
if (Player* tapper = ObjectAccessor::GetPlayer(*me, tapperGUID))
{
tapper->CastSpell(tapper, SPELL_BALEFUL_KILL_CREDIT, false);
tapper->CastSpell(tapper, SPELL_BALEFUL_TAKING_POWER, false);
}
}
}
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_BALEFUL_MIND_SPIKE:
DoCastVictim(SPELL_BALEFUL_MIND_SPIKE);
_events.ScheduleEvent(EVENT_BALEFUL_MIND_SPIKE, 7s);
break;
case EVENT_BALEFUL_BEAMING_GAZE:
DoCastVictim(SPELL_BALEFUL_BEAMING_GAZE);
_events.ScheduleEvent(EVENT_BALEFUL_BEAMING_GAZE, 11s);
break;
case EVENT_BALEFUL_INCITE_MADNESS:
DoCastVictim(SPELL_BALEFUL_INCITE_MADNESS);
_events.ScheduleEvent(EVENT_BALEFUL_INCITE_MADNESS, 30s);
break;
default:
break;
}
}
}
private:
EventMap _events;
bool _castedLegionAegis;
ObjectGuid _balefulColossGUID;
};
// 99160 - Beaming Eye
struct npc_baleful_beaming_eye : public ScriptedAI
{
npc_baleful_beaming_eye(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->SetDisplayId(DISPLAYID_BALEFUL_EYE, true);
DoCastSelf(SPELL_BALEFUL_BEAMING_EYE_CREATE_AT);
// ToDo: rotation isn't changing orientation, turnspeed should be random
me->GetMotionMaster()->MoveRotate(0, RAND(ROTATE_DIRECTION_LEFT, ROTATE_DIRECTION_RIGHT), 10s);
}
};
// 192665 - Legion Aegis
class spell_mardum_baleful_legion_aegis : public AuraScript
{
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (UnitAI* ai = GetTarget()->GetAI())
ai->DoAction(ACTION_BALEFUL_AEGIS_DOWN);
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_mardum_baleful_legion_aegis::HandleRemove, EFFECT_0, SPELL_AURA_SCHOOL_IMMUNITY, AURA_EFFECT_HANDLE_REAL);
}
};
// 192709 - Infernal Smash
class spell_mardum_coloss_infernal_smash_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BALEFUL_COLOSS_INFERNAL_SMASH_CAST });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_BALEFUL_COLOSS_INFERNAL_SMASH_CAST, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_mardum_coloss_infernal_smash_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 195058 - Beaming Gaze (selector)
class spell_mardum_baleful_beaming_gaze_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BALEFUL_BEAMING_EYE_SUMMON });
}
void SummonBeamingEye(Unit* origin, float angle)
{
Position dest = origin->GetPosition();
origin->MovePositionToFirstCollision(dest, 6.5f, angle);
dest.m_positionZ += 0.35f;
origin->CastSpell(dest, SPELL_BALEFUL_BEAMING_EYE_SUMMON, true);
}
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
Unit* hitUnit = GetHitUnit();
SummonBeamingEye(hitUnit, float(M_PI));
SummonBeamingEye(hitUnit, float(-M_PI) / 4.0f);
SummonBeamingEye(hitUnit, float(M_PI) / 4.0f);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_mardum_baleful_beaming_gaze_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
enum SetThemFreeData
{
NPC_CYANA_NIGHTGLAIVE_FREED = 94377,
NPC_IZAL_WHITEMOON_FREED = 93117,
NPC_BELATH_DAWNBLADE_FREED = 94400,
NPC_MANNETHREL_DARKSTAR_FREED = 93230,
SAY_CYANA_NIGHTGLAIVE_FREED = 1,
SAY_IZAL_WHITEMOON_FREED = 1,
SAY_BELATH_DAWNBLADE_FREED = 1,
SAY_MANNETHRE_DARKSTAR_FREED = 1,
PATH_CYANA_NIGHTGLAIVE_FREED = 9437700,
PATH_IZAL_WHITEMOON_FREED = 9311700,
PATH_BELATH_DAWNBLADE_FREED = 9440000,
PATH_MANNETHREL_DARKSTAR_FREED = 9323000,
ANIM_DH_WALK_DAZED = 1078
};
// 94377 - Cyana Nightglaive
struct npc_cyana_nightglaive_freed_private : public ScriptedAI
{
npc_cyana_nightglaive_freed_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->DespawnOrUnsummon(19s);
_scheduler.Schedule(2s + 500ms, [this](TaskContext task)
{
Talk(SAY_CYANA_NIGHTGLAIVE_FREED, me);
task.Schedule(3s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_CYANA_NIGHTGLAIVE_FREED, false);
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* CyanaNightglaiveFreedAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_cyana_nightglaive_freed_private(creature);
return new NullCreatureAI(creature);
};
// 93117 - Izal Whitemoon
struct npc_izal_whitemoon_freed_private : public ScriptedAI
{
npc_izal_whitemoon_freed_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->DespawnOrUnsummon(18s);
_scheduler.Schedule(2s, [this](TaskContext task)
{
Talk(SAY_IZAL_WHITEMOON_FREED, me);
task.Schedule(3s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_CYANA_NIGHTGLAIVE_FREED, false);
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* IzalWhitemoonFreedAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_izal_whitemoon_freed_private(creature);
return new NullCreatureAI(creature);
};
// 94400 - Belath Dawnblade
struct npc_belath_dawnblade_freed_private : public ScriptedAI
{
npc_belath_dawnblade_freed_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->DespawnOrUnsummon(5min); // wtf blizz
_scheduler.Schedule(3s, [this](TaskContext task)
{
Talk(SAY_BELATH_DAWNBLADE_FREED, me);
task.Schedule(6s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_BELATH_DAWNBLADE_FREED, false);
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* BelathDawnbladeFreedAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_belath_dawnblade_freed_private(creature);
return new NullCreatureAI(creature);
};
// 93230 - Mannethrel Darkstar
struct npc_mannethrel_darkstar_freed_private : public ScriptedAI
{
npc_mannethrel_darkstar_freed_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
me->DespawnOrUnsummon(28s);
_scheduler.Schedule(2s, [this](TaskContext task)
{
Talk(SAY_BELATH_DAWNBLADE_FREED, me);
task.Schedule(6s, [this](TaskContext /*task*/)
{
me->SetAIAnimKitId(ANIM_DH_WALK_DAZED);
me->GetMotionMaster()->MovePath(PATH_MANNETHREL_DARKSTAR_FREED, false);
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
CreatureAI* MannethrelDarkstarFreedAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_mannethrel_darkstar_freed_private(creature);
return new NullCreatureAI(creature);
};
// 204711 - Set Them Free: Cyana Nightglaive Freed Kill Credit
// 204714 - Set Them Free: Izal Whitemoon Freed Kill Credit
// 204712 - Set Them Free: Belath Dawnblade Freed Kill Credit
// 204715 - Set Them Free: Mannethrel Darkstar Freed Kill Credit
template
class spell_freed_killcredit_set_them_free : public SpellScript
{
void HandleHitTarget(SpellEffIndex /*effIndex*/)
{
if (Player* player = GetCaster()->ToPlayer())
{
Creature* staticObject = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = CreatureId, .IgnorePhases = true });
if (!staticObject)
return;
staticObject->SummonPersonalClone(staticObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_freed_killcredit_set_them_free::HandleHitTarget, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
enum ETIShivarraData
{
NPC_SEVIS_BRIGHTFLAME_SHIVARRA = 99915,
GOSSIP_MENU_SACRIFICE_PLAYER = 19132,
GOSSIP_MENU_SACRIFICE_SEVIS = 19133,
GOSSIP_OPTION_SACRIFICE_PLAYER = 0,
GOSSIP_OPTION_SACRIFICE_SEVIS = 0,
SAY_SEVIS_PLAYER_SACRIFICE = 1,
SAY_SEVIS_GET_SACRIFICED = 2,
ANIM_KIT_SWING_WEAPON = 8973,
ANIM_KIT_KNEEL = 2312,
ANIM_KIT_SALUTE = 3342,
ANIM_KIT_ONESHOT_GET_HIT = 881,
SPELL_VISUAL_SACRIFICE_PLAYER = 55406,
PATH_SEVIS_GATEWAY_SHIVARRA = 9991500,
POINT_SEVIS_GATEWAY_SHIVARRA = 1,
SPELL_SACRIFICE_SEVIS = 196731,
SPELL_SEVIS_SACRIFICE_ME = 196735,
SPELL_SEVIS_CHAOS_STRIKE = 204317,
SPELL_SEVIS_SOUL_MISSILE_02 = 191664,
SPELL_SEVIS_KILLED_ME_AURA = 203292,
SPELL_TRIGGER_SHIVARRA_CONV_WHEN_DEAD = 196866,
ACTION_SACRIFICE_PLAYER = 1,
ACTION_SACRIFICE_SEVIS,
QUEST_SEVIS_SACRIFICE_TRACKER = 40087,
};
Position const SevisBrightflameShivarraGatewayPosition = { 1587.9618f, 2543.091f, 62.18399f, 3.49967908f };
// 99915 - Sevis Brightflame (Shivarra Gateway)
struct npc_sevis_brightflame_shivarra_gateway : public ScriptedAI
{
npc_sevis_brightflame_shivarra_gateway(Creature* creature) : ScriptedAI(creature), _soulMissileCounter(0) { }
bool OnGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
if (menuId == GOSSIP_MENU_SACRIFICE_PLAYER && gossipListId == GOSSIP_OPTION_SACRIFICE_PLAYER)
{
CloseGossipMenuFor(player);
player->CastSpell(nullptr, SPELL_SEVIS_SACRIFICE_ME, false);
return true;
}
else if (menuId == GOSSIP_MENU_SACRIFICE_SEVIS && gossipListId == GOSSIP_OPTION_SACRIFICE_SEVIS)
{
CloseGossipMenuFor(player);
player->CastSpell(me, SPELL_SACRIFICE_SEVIS, false);
return true;
}
return false;
}
void DoAction(int32 param) override
{
switch (param)
{
case ACTION_SACRIFICE_PLAYER:
SacrificePlayer();
break;
case ACTION_SACRIFICE_SEVIS:
SacrificeSelf();
break;
default:
break;
}
}
void SacrificeSelf()
{
me->PlayOneShotAnimKitId(ANIM_KIT_ONESHOT_GET_HIT);
Talk(SAY_SEVIS_GET_SACRIFICED, me);
_scheduler.Schedule(1s, [this](TaskContext task)
{
me->KillSelf();
_soulMissileCounter = 0;
task.Schedule(2s, [this](TaskContext task)
{
DoCast(SPELL_SEVIS_SOUL_MISSILE_02);
_soulMissileCounter++;
if (_soulMissileCounter < 3)
task.Repeat(2s);
});
});
}
void SacrificePlayer()
{
me->DespawnOrUnsummon(22s);
Talk(SAY_SEVIS_PLAYER_SACRIFICE, me);
_scheduler.Schedule(1s, [this](TaskContext task)
{
TempSummon* summon = me->ToTempSummon();
if (!summon)
return;
Unit* summoner = summon->GetSummonerUnit();
if (!summoner)
return;
me->GetMotionMaster()->MoveCloserAndStop(POINT_SEVIS_GATEWAY_SHIVARRA, summoner, 2.0f);
task.Schedule(2s, [this](TaskContext task)
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_SACRIFICE_PLAYER, 4, 1000);
me->SetAIAnimKitId(ANIM_KIT_SWING_WEAPON);
DoCast(SPELL_SEVIS_CHAOS_STRIKE);
task.Schedule(2s, [this](TaskContext task)
{
me->SetAIAnimKitId(ANIM_KIT_KNEEL);
task.Schedule(5s, [this](TaskContext task)
{
me->SetAIAnimKitId(ANIM_KIT_SALUTE);
task.Schedule(3s, [this](TaskContext task)
{
me->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SEVIS_MOUNT, 0, 0);
me->SetMountDisplayId(DISPLAY_ID_SEVIS_MOUNT);
task.Schedule(2s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(PATH_SEVIS_GATEWAY_SHIVARRA, false);
});
});
});
});
});
});
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
uint8 _soulMissileCounter;
};
// EventID 47550
class event_sevis_sacrifice_player : public EventScript
{
public:
event_sevis_sacrifice_player() : EventScript("event_sevis_sacrifice_player") { }
void OnTrigger(WorldObject* /*object*/, WorldObject* invoker, uint32 /*eventId*/) override
{
if (Creature* creature = invoker->SummonCreature(NPC_SEVIS_BRIGHTFLAME_SHIVARRA, SevisBrightflameShivarraGatewayPosition, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, invoker->GetGUID()))
{
if (Player* player = invoker->ToPlayer())
{
player->KilledMonsterCredit(NPC_SEVIS_BRIGHTFLAME_SHIVARRA);
player->CastSpell(nullptr, SPELL_SEVIS_KILLED_ME_AURA, false);
}
creature->AI()->DoAction(ACTION_SACRIFICE_PLAYER);
}
}
};
// EventID 47549
class event_sevis_sacrifice_self : public EventScript
{
public:
event_sevis_sacrifice_self() : EventScript("event_sevis_sacrifice_self") { }
void OnTrigger(WorldObject* /*object*/, WorldObject* invoker, uint32 /*eventId*/) override
{
if (Creature* creature = invoker->SummonCreature(NPC_SEVIS_BRIGHTFLAME_SHIVARRA, SevisBrightflameShivarraGatewayPosition, TEMPSUMMON_TIMED_DESPAWN, 60s, 0, 0, invoker->GetGUID()))
{
if (Player* player = invoker->ToPlayer())
player->KilledMonsterCredit(NPC_SEVIS_BRIGHTFLAME_SHIVARRA);
creature->AI()->DoAction(ACTION_SACRIFICE_SEVIS);
}
}
};
// XX - Mardum - Trigger Conversation for Quest "Enter the Illidari: Shivarra"
struct at_enter_the_illidari_shivarra_conversation : AreaTriggerAI
{
at_enter_the_illidari_shivarra_conversation(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
void OnUnitEnter(Unit* unit) override
{
Player* player = unit->ToPlayer();
if (!player || !player->HasAura(SPELL_SEVIS_KILLED_ME_AURA))
return;
player->CastSpell(nullptr, SPELL_TRIGGER_SHIVARRA_CONV_WHEN_DEAD, true);
}
};
// 38765 - Enter the Illidari: Shivarra
class quest_enter_the_illidari_shivarra : public QuestScript
{
public:
quest_enter_the_illidari_shivarra() : QuestScript("quest_enter_the_illidari_shivarra") { }
void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override
{
if (newStatus == QUEST_STATUS_NONE)
{
player->RemoveActiveQuest(QUEST_SEVIS_SACRIFICE_TRACKER, false);
player->RemoveRewardedQuest(QUEST_SEVIS_SACRIFICE_TRACKER);
}
}
};
enum GiveMeSightBeyondSightData
{
QUEST_GIVE_ME_SIGHT_BEYOND_SIGHT = 39262,
KILLCREDIT_FACE_THE_CAVE = 96437,
KILLCREDIT_SPEAK_WITH_JAYCE = 96436,
GOSSIP_MENU_USE_SPECTRAL_SIGHT = 19175,
GOSSIP_OPTION_USE_SPECTRAL_SIGHT = 0,
SAY_JAYCE_USE_SPECTRAL_SIGHT = 0,
SPELL_DH_SPECTRAL_SIGHT = 188501,
SPELL_GIVE_ME_SIGHT_PERIODIC_AURA = 191095,
SPELL_GIVE_ME_SIGHT_PERIODIC_DUMMY = 191097
};
Position const RockslideCavePosition = { 1237.1528f, 1642.6180f, 103.1518f, 5.8055872f };
// 191097 - Give Me Sight Beyond Sight: Periodic Trigger Dummy
class spell_give_me_sight_beyond_sight_periodic : public AuraScript
{
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
Player* player = GetCaster()->ToPlayer();
if (!player || !player->HasAura(SPELL_DH_SPECTRAL_SIGHT))
return;
float angleToWall = player->GetAbsoluteAngle(RockslideCavePosition);
float playerOrientation = player->GetOrientation();
if (playerOrientation >= Position::NormalizeOrientation(angleToWall - float(M_PI) / 4) && playerOrientation <= Position::NormalizeOrientation(angleToWall + float(M_PI) / 4))
{
player->KilledMonsterCredit(KILLCREDIT_FACE_THE_CAVE);
player->RemoveAurasDueToSpell(SPELL_GIVE_ME_SIGHT_PERIODIC_AURA);
player->RemoveAurasDueToSpell(SPELL_GIVE_ME_SIGHT_PERIODIC_DUMMY);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_give_me_sight_beyond_sight_periodic::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
enum HiddenNoMoreData
{
QUEST_HIDDEN_NO_MORE = 39495,
NPC_JAYCE_CRYPTIC_HOLLOW = 96436,
NPC_SHIVARRA_CRYPTIC_HOLLOW = 96504,
NPC_ROCKSLIDE_KILLCREDIT = 98755,
SAY_JAYCE_ATTACK_ILLIDARI = 1,
ACTION_HIDDEN_NO_MORE_EYEBEAM = 1,
ACTION_HIDDEN_NO_MORE_MOVE = 2,
SPELL_VISUAL_KIT_SHIVARRA_TELEPORT = 43182,
SPELL_VISUAL_KIT_SHIVARRA_TELEPORT2 = 43576,
SPELL_VISUAL_KIT_SHIVARRA_TELEPORT3 = 45431,
SPELL_ABANDON_HIDDEN_NO_MORE = 194376,
SPELL_COSMETIC_EYE_BEAM_01_FEMALE = 200754,
SPELL_COSMETIC_EYE_BEAM_01_MALE = 194326
};
enum HiddenNoMorePaths
{
POINT_JAYCE_DARKWEAVER_PREPARE_JUMP = 1,
POINT_JAYCE_DARKWEAVER_JUMP_TO_CAVE = 2,
PATH_JAYCE_DARKWEAVER_RUN_INTO_CAVE = 9643600,
PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_01 = 10178700,
PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_02 = 10178701,
PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_03 = 10178800,
PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_04 = 10178900,
PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_05 = 10179000,
PATH_CRYPTIC_HOLLOW_COILSKAR_01 = 9650200,
PATH_CRYPTIC_HOLLOW_COILSKAR_02 = 9650201,
PATH_CRYPTIC_HOLLOW_COILSKAR_03 = 9650300,
PATH_CRYPTIC_HOLLOW_ASHTONGUE_01 = 9650000,
PATH_CRYPTIC_HOLLOW_ASHTONGUE_02 = 9650001,
PATH_CRYPTIC_HOLLOW_ASHTONGUE_03 = 9650100
};
// 39495 - Hidden No More
class quest_hidden_no_more : public QuestScript
{
public:
quest_hidden_no_more() : QuestScript("quest_hidden_no_more") { }
void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override
{
if (newStatus == QUEST_STATUS_NONE)
{
player->CastSpell(nullptr, SPELL_ABANDON_HIDDEN_NO_MORE, true);
}
}
};
// 96436 - Jayce Darkweaver
struct npc_jayce_darkweaver_cryptic_hollow : public ScriptedAI
{
npc_jayce_darkweaver_cryptic_hollow(Creature* creature) : ScriptedAI(creature) { }
void OnQuestAccept(Player* player, Quest const* quest) override
{
if (quest->GetQuestId() == QUEST_HIDDEN_NO_MORE)
me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
}
bool OnGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
if (menuId == GOSSIP_MENU_USE_SPECTRAL_SIGHT && gossipListId == GOSSIP_OPTION_USE_SPECTRAL_SIGHT)
{
Talk(SAY_JAYCE_USE_SPECTRAL_SIGHT);
player->KilledMonsterCredit(KILLCREDIT_SPEAK_WITH_JAYCE);
player->CastSpell(player, SPELL_GIVE_ME_SIGHT_PERIODIC_AURA);
player->CastSpell(player, SPELL_GIVE_ME_SIGHT_PERIODIC_DUMMY);
CloseGossipMenuFor(player);
}
return true;
}
};
struct HiddenNoMorePathDelay
{
uint32 PathId;
Milliseconds ActionDelay;
Milliseconds MoveDelay;
};
std::unordered_map HiddenNoMorePathMap = {
{ "CrypticHollowDh01", { PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_01, 554ms, 2990ms } },
{ "CrypticHollowDh02", { PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_02, 270ms, 1690ms } },
{ "CrypticHollowDh03", { PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_03, 554ms, 1690ms } },
{ "CrypticHollowDh04", { PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_04, 554ms, 2990ms } },
{ "CrypticHollowDh05", { PATH_CRYPTIC_HOLLOW_DEMON_HUNTER_05, 402ms, 2990ms } },
{ "CrypticHollowCoilskar01", { PATH_CRYPTIC_HOLLOW_COILSKAR_01, 0ms, 1521ms } },
{ "CrypticHollowCoilskar02", { PATH_CRYPTIC_HOLLOW_COILSKAR_02, 0ms, 2024ms } },
{ "CrypticHollowCoilskar03", { PATH_CRYPTIC_HOLLOW_COILSKAR_03, 0ms, 1521ms } },
{ "CrypticHollowAshtongue01", { PATH_CRYPTIC_HOLLOW_ASHTONGUE_01, 0ms, 1521ms } },
{ "CrypticHollowAshtongue02", { PATH_CRYPTIC_HOLLOW_ASHTONGUE_02, 0ms, 1521ms } },
{ "CrypticHollowAshtongue03", { PATH_CRYPTIC_HOLLOW_ASHTONGUE_03, 0ms, 1521ms } },
};
constexpr Position JaycePrepareJump = { 1263.948f, 1632.9402f, 102.08563f };
constexpr Position JayceJumpPosition = { 1245.257f, 1639.049f, 101.223f };
// 96436 - Jayce Darkweaver
struct npc_jayce_darkweaver_cryptic_hollow_private : public ScriptedAI
{
npc_jayce_darkweaver_cryptic_hollow_private(Creature* creature) : ScriptedAI(creature) { }
void JustAppeared() override
{
Player* player = me->GetDemonCreatorPlayer();
if (!player)
return;
me->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER));
me->CastSpell(nullptr, SPELL_COSMETIC_EYE_BEAM_01_MALE, false);
Creature* shivarraObject = me->FindNearestCreatureWithOptions(25.0f, { .CreatureId = NPC_SHIVARRA_CRYPTIC_HOLLOW, .IgnorePhases = true });
if (!shivarraObject)
return;
Creature* shivarraClone = shivarraObject->SummonPersonalClone(shivarraObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player);
if (!shivarraClone)
return;
_scheduler.Schedule(4s, [this, shivarraGuid = shivarraClone->GetGUID()](TaskContext task)
{
Creature* shivarraClone = ObjectAccessor::GetCreature(*me, shivarraGuid);
if (!shivarraClone)
return;
shivarraClone->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SHIVARRA_TELEPORT, 4, 2000);
shivarraClone->SetEmoteState(EMOTE_STATE_READY_SPELL_OMNI);
task.Schedule(3s, [this, shivarraGuid](TaskContext /*task*/)
{
Creature* shivarraClone = ObjectAccessor::GetCreature(*me, shivarraGuid);
if (!shivarraClone)
return;
shivarraClone->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST_OMNI);
shivarraClone->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SHIVARRA_TELEPORT2, 4, 1000);
shivarraClone->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_SHIVARRA_TELEPORT3, 4, 2000);
shivarraClone->DespawnOrUnsummon(1s);
});
});
for (std::pair& npcPair : HiddenNoMorePathMap)
{
Creature* originalObject = me->FindNearestCreatureWithOptions(25.0f, { .StringId = npcPair.first, .IgnorePhases = true });
if (!originalObject)
continue;
Creature* clone = originalObject->SummonPersonalClone(originalObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, me->GetDemonCreatorPlayer());
if (!clone)
continue;
_cloneGuids.push_back(clone->GetGUID());
clone->AI()->DoAction(ACTION_HIDDEN_NO_MORE_EYEBEAM);
}
}
void OnChannelFinished(SpellInfo const* spell) override
{
if (spell->Id != SPELL_COSMETIC_EYE_BEAM_01_MALE)
return;
Player* player = me->GetDemonCreatorPlayer();
player->KilledMonsterCredit(NPC_ROCKSLIDE_KILLCREDIT);
Talk(SAY_JAYCE_ATTACK_ILLIDARI);
_scheduler.Schedule(1s, [this](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePoint(POINT_JAYCE_DARKWEAVER_PREPARE_JUMP, JaycePrepareJump);
for (ObjectGuid const& guid : _cloneGuids)
{
Creature* clone = ObjectAccessor::GetCreature(*me, guid);
if (!clone)
continue;
clone->AI()->DoAction(ACTION_HIDDEN_NO_MORE_MOVE);
}
});
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != EFFECT_MOTION_TYPE && type != POINT_MOTION_TYPE)
return;
if (pointId == POINT_JAYCE_DARKWEAVER_PREPARE_JUMP)
me->GetMotionMaster()->MoveJumpWithGravity(JayceJumpPosition, 19.880844f, 32.78205f, POINT_JAYCE_DARKWEAVER_JUMP_TO_CAVE);
else if (pointId == POINT_JAYCE_DARKWEAVER_JUMP_TO_CAVE)
{
me->GetMotionMaster()->MovePath(PATH_JAYCE_DARKWEAVER_RUN_INTO_CAVE, false);
me->DespawnOrUnsummon(5s);
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
std::vector _cloneGuids;
};
CreatureAI* JayceDarkweaverCrypticHollowAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_jayce_darkweaver_cryptic_hollow_private(creature);
return new npc_jayce_darkweaver_cryptic_hollow(creature);
};
struct npc_basic_hidden_no_more_private : public ScriptedAI
{
npc_basic_hidden_no_more_private(Creature* creature) : ScriptedAI(creature) { }
HiddenNoMorePathDelay const* GetPathDelay()
{
if (HiddenNoMorePathDelay const* pathDelay = Trinity::Containers::MapGetValuePtr(HiddenNoMorePathMap, me->GetStringId(StringIdType::Spawn)))
return pathDelay;
return nullptr;
}
void DoAction(int32 param) override
{
HiddenNoMorePathDelay const* pathDelay = GetPathDelay();
if (!pathDelay)
return;
switch (param)
{
case ACTION_HIDDEN_NO_MORE_MOVE:
{
_scheduler.Schedule(pathDelay->MoveDelay, [this, pathDelay](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(pathDelay->PathId, false);
me->DespawnOrUnsummon(6s);
});
break;
}
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
protected:
TaskScheduler _scheduler;
};
CreatureAI* BasicHiddenNoMoreAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_basic_hidden_no_more_private(creature);
return new NullCreatureAI(creature);
};
// 101787 - Demon Hunter
// 101788 - Demon Hunter
// 101789 - Demon Hunter
// 101790 - Demon Hunter
struct npc_demon_hunter_hidden_no_more_private : public npc_basic_hidden_no_more_private
{
npc_demon_hunter_hidden_no_more_private(Creature* creature) : npc_basic_hidden_no_more_private(creature) { }
void DoAction(int32 param) override
{
HiddenNoMorePathDelay const* pathDelay = GetPathDelay();
if (!pathDelay)
return;
switch (param)
{
case ACTION_HIDDEN_NO_MORE_EYEBEAM:
{
_scheduler.Schedule(pathDelay->ActionDelay, [this](TaskContext /*task*/)
{
me->CastSpell(me, (me->GetGender() == GENDER_FEMALE ? SPELL_COSMETIC_EYE_BEAM_01_FEMALE : SPELL_COSMETIC_EYE_BEAM_01_MALE), false);
});
break;
}
case ACTION_HIDDEN_NO_MORE_MOVE:
{
me->SetAIAnimKitId(ANIM_DH_RUN);
_scheduler.Schedule(pathDelay->MoveDelay, [this, pathDelay](TaskContext /*task*/)
{
me->GetMotionMaster()->MovePath(pathDelay->PathId, false);
me->DespawnOrUnsummon(6s);
});
break;
}
default:
break;
}
}
};
CreatureAI* DemonHunterHiddenNoMoreAISelector(Creature* creature)
{
if (creature->IsPrivateObject())
return new npc_demon_hunter_hidden_no_more_private(creature);
return new NullCreatureAI(creature);
};
void AddSC_zone_mardum()
{
// Creature
RegisterCreatureAI(npc_kayn_sunfury_invasion_begins);
RegisterCreatureAI(npc_jayce_darkweaver_invasion_begins);
RegisterCreatureAI(npc_allari_the_souleater_invasion_begins);
RegisterCreatureAI(npc_korvas_bloodthorn_invasion_begins);
RegisterCreatureAI(npc_sevis_brightflame_invasion_begins);
RegisterCreatureAI(npc_cyana_nightglaive_invasion_begins);
RegisterCreatureAI(npc_illidari_fighting_invasion_begins);
RegisterCreatureAI(npc_inquisitor_baleful_molten_shore);
RegisterCreatureAI(npc_baleful_beaming_eye);
RegisterCreatureAI(npc_sevis_brightflame_shivarra_gateway);
// AISelector
new FactoryCreatureScript("npc_kayn_sunfury_ashtongue_intro");
new FactoryCreatureScript("npc_sevis_brightflame_ashtongue_gateway_private");
new FactoryCreatureScript("npc_sevis_brightflame_coilskar_gateway_private");
new FactoryCreatureScript("npc_cyana_nightglaive_freed_private");
new FactoryCreatureScript("npc_izal_whitemoon_freed_private");
new FactoryCreatureScript("npc_belath_dawnblade_freed_private");
new FactoryCreatureScript("npc_mannethrel_darkstar_freed_private");
new FactoryCreatureScript("npc_jayce_darkweaver_cryptic_hollow");
new FactoryCreatureScript("npc_demon_hunter_hidden_no_more_private");
new FactoryCreatureScript("npc_basic_hidden_no_more_private");
// AreaTrigger
RegisterAreaTriggerAI(at_enter_the_illidari_ashtongue_allari_killcredit);
RegisterAreaTriggerAI(at_enter_the_illidari_shivarra_conversation);
// EventScript
new event_sevis_sacrifice_player();
new event_sevis_sacrifice_self();
// Conversation
RegisterConversationAI(conversation_the_invasion_begins);
// Scene
new scene_demonhunter_intro();
new scene_enter_the_illidari_ashtongue();
new scene_enter_the_illidari_coilskar();
// Quests
new quest_enter_the_illidari_shivarra();
new quest_hidden_no_more();
// Spells
RegisterSpellScript(spell_demon_hunter_intro_aura);
RegisterSpellScript(spell_accepting_felsaber_gift);
RegisterSpellScript(spell_mardum_baleful_legion_aegis);
RegisterSpellScript(spell_mardum_coloss_infernal_smash_selector);
RegisterSpellScript(spell_mardum_baleful_beaming_gaze_selector);
RegisterSpellScript(spell_give_me_sight_beyond_sight_periodic);
RegisterSpellScriptWithArgs(spell_freed_killcredit_set_them_free, "spell_cyana_nightglaive_killcredit_set_them_free");
RegisterSpellScriptWithArgs(spell_freed_killcredit_set_them_free, "spell_izal_whitemoon_killcredit_set_them_free");
RegisterSpellScriptWithArgs(spell_freed_killcredit_set_them_free, "spell_belath_dawnblade_killcredit_set_them_free");
RegisterSpellScriptWithArgs(spell_freed_killcredit_set_them_free, "spell_mannethrel_darkstar_killcredit_set_them_free");
};