/* * 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 "Containers.h" #include "Conversation.h" #include "ConversationAI.h" #include "CreatureAIImpl.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "PhasingHandler.h" #include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellInfo.h" #include "SpellScript.h" #include "TemporarySummon.h" enum GetYourBearingsData { QUEST_GET_YOUR_BEARINGS = 47099, KILL_CREDIT_FERRY_DOCK_VISITED = 124588, KILL_CREDIT_COUNTING_HOUSE_VISITED = 124586, KILL_CREDIT_SNUG_HARBOR_INN_VISITED = 124768, KILL_CREDIT_FLIGHT_MASTER_VISITED = 124587, OBJECTIVE_FERRY_DOCK_VISITED = 291081, OBJECTIVE_COUNTING_HOUSE_VISITED = 291079, OBJECTIVE_SNUG_HARBOR_INN_VISITED = 291080, OBJECTIVE_FLIGHT_MASTER_VISITED = 291171, NPC_SUMMONED_KULTIRAN_GUARD = 124630, CONVO_ACTOR_KULTIRAN_GUARD = 59582, POINT_KULTIRAN_GUARD = 1, POINT_KULTIRAN_GUARD_FLIGHT_MASTER = 2, SPELL_HUB_TOUR_CONVO_FERRY = 247669, SPELL_HUB_TOUR_CONVO_BANK = 247749, SPELL_HUB_TOUR_CONVO_INN = 247894, SPELL_HUB_TOUR_CONVO_FLIGHT_MASTER = 247753 }; enum TheOldKnightData { QUEST_THE_OLD_KNIGHT = 46729, NPC_CYRUS_CRESTFALL = 122370, NPC_GENN_GREYMANE = 120788, NPC_GREYGUARD = 120599, GOSSIP_MENU_CYRUS_SHAKING_HANDS = 22543, GOSSIP_OPTION_CYRUS_SHAKING_HANDS = 0, CONVO_ACCEPT_OLD_KNIGHT_QUEST = 9556, CONVO_CYRUS_MEETS_GENN_IN_OFFICE = 8062, CONVO_CYRUS_SHAKING_HAND = 7653, CONVO_ACTOR_CYRUS_CRESTFAL = 59635, OBJECTIVE_ENTER_HARBORMASTERS_OFFICE = 335127, KILLCREDIT_SPEAK_WITH_CYRUS_OLD_KNIGHT = 137009, KILLCREDIT_HEAR_CYRUS_TALE_OLD_KNIGHT = 137877, PATH_KULTIRAN_GUARD_ENTER_OFFICE = 12463000, PATH_KULTIRAN_GUARD_AFTER_SCENE_OFFICE = 12463001, PATH_CYRUS_CRESTFAL_AFTER_SCENE_OFFICE = 12237000, PATH_GENN_GREYMANE_AFTER_SCENE_OFFICE = 12078800, PATH_GREYGUARD_TWO_AFTER_SCENE_OFFICE = 12059900, PATH_GREYGUARD_ONE_AFTER_SCENE_OFFICE = 12059901, SPELL_ENTER_HARBOR_MASTERS_OFFICE = 268759, SPELL_FIND_CYRUS_OBJECTIVE_COMPLETE = 269054, SPELL_CLIENT_SCENE_CYRUS_AND_GENN = 271234 }; // 124630 - Taelia struct npc_taelia_get_your_bearings : public ScriptedAI { npc_taelia_get_your_bearings(Creature* creature) : ScriptedAI(creature) { } void IsSummonedBy(WorldObject* summoner) override { // might be handled by SummonProperties if (Player* player = summoner->ToPlayer()) me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } void OnQuestAccept(Player* player, Quest const* quest) override { if (quest->GetQuestId() == QUEST_THE_OLD_KNIGHT) Conversation::CreateConversation(CONVO_ACCEPT_OLD_KNIGHT_QUEST, player, *player, player->GetGUID(), nullptr, false); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_FIND_CYRUS_OBJECTIVE_COMPLETE) return; me->GetMotionMaster()->MovePath(PATH_KULTIRAN_GUARD_AFTER_SCENE_OFFICE, false); } void MovementInform(uint32 type, uint32 pointId) override { if (type != POINT_MOTION_TYPE) return; if (pointId == POINT_KULTIRAN_GUARD) { if (Unit* summoner = me->GetOwner()) me->SetFacingToObject(summoner); } } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (pathId == PATH_KULTIRAN_GUARD_AFTER_SCENE_OFFICE) me->DespawnOrUnsummon(); } }; // 5360 - Conversation class conversation_boralus_hub_tour_00 : public ConversationAI { public: conversation_boralus_hub_tour_00(Conversation* conversation) : ConversationAI(conversation) { } void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) return; conversation->AddActor(CONVO_ACTOR_KULTIRAN_GUARD, 0, kultiranGuard->GetGUID()); conversation->Start(); } }; // XX - Boralus - Get your Bearings (Ferry) // XX - Boralus - Get your Bearings (Bank) // XX - Boralus - Get your Bearings (Inn) // XX - Boralus - Get your Bearings (Flightmaster) template struct at_boralus_get_your_bearings : AreaTriggerAI { at_boralus_get_your_bearings(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player || player->GetQuestStatus(QuestId) != QUEST_STATUS_INCOMPLETE || player->GetQuestObjectiveData(QuestId, ObjectiveId)) return; player->CastSpell(nullptr, SpellId, false); } }; // 5362 - Conversation - Get your Bearings (Ferry) class conversation_boralus_hub_tour : public ConversationAI { public: conversation_boralus_hub_tour(Conversation* conversation) : ConversationAI(conversation) { } enum ConversationFerryData { EVENT_TAELIA_CREDIT = 1 }; virtual Position const& GetGuardMovePosition() = 0; virtual uint32 GetKillCreditId() = 0; void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) return; kultiranGuard->GetMotionMaster()->Clear(); kultiranGuard->GetMotionMaster()->MovePoint(POINT_KULTIRAN_GUARD, GetGuardMovePosition()); conversation->AddActor(CONVO_ACTOR_KULTIRAN_GUARD, 0, kultiranGuard->GetGUID()); conversation->Start(); } void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); _events.ScheduleEvent(EVENT_TAELIA_CREDIT, conversation->GetLastLineEndTime(privateOwnerLocale)); } void OnUpdate(uint32 diff) override { _events.Update(diff); switch (_events.ExecuteEvent()) { case EVENT_TAELIA_CREDIT: { Player* player = ObjectAccessor::GetPlayer(*conversation, conversation->GetPrivateObjectOwner()); if (!player) break; Creature* kultiranGuard = player->FindNearestCreatureWithOptions(50.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = player->GetGUID() }); if (!kultiranGuard) break; player->KilledMonsterCredit(GetKillCreditId()); kultiranGuard->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); break; } default: break; } } private: EventMap _events; }; Position const TaeliaFerryPos = { 1039.5955f, -598.00653f, 1.458778f }; // 5362 - Conversation - Get your Bearings (Ferry) class conversation_boralus_hub_tour_ferry : public conversation_boralus_hub_tour { public: conversation_boralus_hub_tour_ferry(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { return TaeliaFerryPos; } uint32 GetKillCreditId() { return KILL_CREDIT_FERRY_DOCK_VISITED; } }; Position const TaeliaBankPos = { 1118.7385f, -622.4115f, 17.76035f }; // 5365 - Conversation Get your Bearings (Counting House) class conversation_boralus_hub_tour_counting_house : public conversation_boralus_hub_tour { public: conversation_boralus_hub_tour_counting_house(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { return TaeliaBankPos; } uint32 GetKillCreditId() { return KILL_CREDIT_COUNTING_HOUSE_VISITED; } }; Position const TaeliaInnPos = { 1177.39f, -587.682f, 31.557224f }; // 5375 - Conversation Get your Bearings (Harbor Inn) class conversation_boralus_hub_tour_harbor_inn : public conversation_boralus_hub_tour { public: conversation_boralus_hub_tour_harbor_inn(Conversation* conversation) : conversation_boralus_hub_tour(conversation) { } Position const& GetGuardMovePosition() { return TaeliaInnPos; } uint32 GetKillCreditId() { return KILL_CREDIT_SNUG_HARBOR_INN_VISITED; } }; Position const TaeliaFlightMasterPos = { 1149.82f, -471.071f, 30.503826f }; // 5366 - Conversation Get your Bearings (Flight Master) class conversation_boralus_hub_tour_flight_master : public conversation_boralus_hub_tour { public: conversation_boralus_hub_tour_flight_master(Conversation* conversation) : conversation_boralus_hub_tour(conversation) {} Position const& GetGuardMovePosition() { return TaeliaFlightMasterPos; } uint32 GetKillCreditId() { return KILL_CREDIT_FLIGHT_MASTER_VISITED; } }; // 9556 - Conversation The Old Knight (accept Quest) class conversation_boralus_accept_old_knight : public ConversationAI { public: conversation_boralus_accept_old_knight(Conversation* conversation) : ConversationAI(conversation) { } void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) return; conversation->AddActor(CONVO_ACTOR_KULTIRAN_GUARD, 0, kultiranGuard->GetGUID()); conversation->Start(); } }; // XX - Boralus The Old Knight (Enter the Harbormasters Office) struct at_boralus_old_knight_enter_harbormasters_office : AreaTriggerAI { at_boralus_old_knight_enter_harbormasters_office(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player || player->GetQuestStatus(QUEST_THE_OLD_KNIGHT) != QUEST_STATUS_INCOMPLETE || player->GetQuestObjectiveData(QUEST_THE_OLD_KNIGHT, OBJECTIVE_ENTER_HARBORMASTERS_OFFICE)) return; player->CastSpell(nullptr, SPELL_ENTER_HARBOR_MASTERS_OFFICE, false); } }; // 7605 - Conversation The Old Knight (Enter the Harbormasters Office) class conversation_boralus_enter_harbormaster_office : public ConversationAI { public: conversation_boralus_enter_harbormaster_office(Conversation* conversation) : ConversationAI(conversation) { } void OnCreate(Unit* creator) override { Creature* kultiranGuard = creator->FindNearestCreatureWithOptions(20.0f, { .CreatureId = NPC_SUMMONED_KULTIRAN_GUARD, .IgnorePhases = true, .OwnerGuid = creator->GetGUID() }); if (!kultiranGuard) return; kultiranGuard->GetMotionMaster()->Clear(); kultiranGuard->GetMotionMaster()->MovePath(PATH_KULTIRAN_GUARD_ENTER_OFFICE, false); conversation->AddActor(CONVO_ACTOR_KULTIRAN_GUARD, 0, kultiranGuard->GetGUID()); conversation->Start(); } }; // XX - Boralus The Old Knight (Genn Greymane arrives Boralus) struct at_boralus_old_knight_genn_arrives_boralus : AreaTriggerAI { at_boralus_old_knight_genn_arrives_boralus(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player || player->GetQuestStatus(QUEST_THE_OLD_KNIGHT) != QUEST_STATUS_INCOMPLETE || player->GetQuestObjectiveData(QUEST_THE_OLD_KNIGHT, OBJECTIVE_ENTER_HARBORMASTERS_OFFICE)) return; player->CastSpell(nullptr, SPELL_CLIENT_SCENE_CYRUS_AND_GENN, false); } }; // 1960 - Client Scene: Cyrus and Genn class scene_boralus_client_scene_cyrus_and_genn : public SceneScript { public: scene_boralus_client_scene_cyrus_and_genn() : SceneScript("scene_boralus_client_scene_cyrus_and_genn") { } void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, SPELL_FIND_CYRUS_OBJECTIVE_COMPLETE, true); } void OnSceneCancel(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, SPELL_FIND_CYRUS_OBJECTIVE_COMPLETE, true); } }; Position const TaeliaTeleportOfficePos = { 1054.29f, -469.776f, 11.7166f, 3.065999f }; // 269054 - Find Cyrus Objective Complete class spell_boralus_find_cyrus_objective_complete : public SpellScript { void HandleHitTarget(SpellEffIndex /*effIndex*/) { if (Player* player = GetHitUnit()->ToPlayer()) { player->KilledMonsterCredit(NPC_CYRUS_CRESTFALL); Conversation::CreateConversation(CONVO_CYRUS_MEETS_GENN_IN_OFFICE, player, *player, player->GetGUID(), nullptr, false); } else { if (GetHitUnit()->GetEntry() != NPC_SUMMONED_KULTIRAN_GUARD) return; GetHitUnit()->NearTeleportTo(TaeliaTeleportOfficePos); } } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_boralus_find_cyrus_objective_complete::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY); } }; Position const CyrusOfficePos = { 1056.310f, -470.567f, 11.656f, 5.80610f }; Position const GennOfficePos = { 1052.689f, -470.200f, 11.692f, 0.24838f }; Position const GreyguardOneOfficePos = { 1044.979f, -468.523f, 8.386f, 6.03047f }; Position const GreyguardTwoOfficePos = { 1042.359f, -467.738f, 8.386f, 6.04665f }; // 8062 - Conversation class conversation_boralus_cyrus_meets_genn : public ConversationAI { public: conversation_boralus_cyrus_meets_genn(Conversation* conversation) : ConversationAI(conversation) { } enum OldKnightsConversationData { CONVO_LINE_CYRUS_AND_GENN_DESPAWN = 18298, EVENT_OLD_KNIGHTS_CLONE_DESPAWN = 1 }; void OnCreate(Unit* creator) override { Creature* cyrusObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_CYRUS_CRESTFALL, .IgnorePhases = true }); Creature* gennObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_GENN_GREYMANE, .IgnorePhases = true }); Creature* greyguardOneObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_GREYGUARD, .StringId = "GreyguardOne", .IgnorePhases = true }); Creature* greyguardTwoObject = GetClosestCreatureWithOptions(creator, 30.0f, { .CreatureId = NPC_GREYGUARD, .StringId = "GreyguardTwo", .IgnorePhases = true }); if (!cyrusObject || !gennObject || !greyguardOneObject || !greyguardTwoObject) return; TempSummon* cyrusClone = cyrusObject->SummonPersonalClone(CyrusOfficePos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer()); TempSummon* gennClone = gennObject->SummonPersonalClone(GennOfficePos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer()); TempSummon* greyguardOneClone = greyguardOneObject->SummonPersonalClone(GreyguardOneOfficePos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer()); TempSummon* greyguardTwoClone = greyguardTwoObject->SummonPersonalClone(GreyguardTwoOfficePos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer()); if (!cyrusClone || !gennClone || !greyguardOneClone || !greyguardTwoClone) return; _gennCloneGUID = gennClone->GetGUID(); cyrusClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER)); gennClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER)); cyrusClone->GetMotionMaster()->MovePath(PATH_CYRUS_CRESTFAL_AFTER_SCENE_OFFICE, false); gennClone->GetMotionMaster()->MovePath(PATH_GENN_GREYMANE_AFTER_SCENE_OFFICE, false); greyguardOneClone->GetMotionMaster()->MovePath(PATH_GREYGUARD_ONE_AFTER_SCENE_OFFICE, false); greyguardTwoClone->GetMotionMaster()->MovePath(PATH_GREYGUARD_TWO_AFTER_SCENE_OFFICE, false); conversation->AddActor(CONVO_ACTOR_CYRUS_CRESTFAL, 0, cyrusClone->GetGUID()); conversation->Start(); } void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); _events.ScheduleEvent(EVENT_OLD_KNIGHTS_CLONE_DESPAWN, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_AND_GENN_DESPAWN)); } void OnUpdate(uint32 diff) override { _events.Update(diff); switch (_events.ExecuteEvent()) { case EVENT_OLD_KNIGHTS_CLONE_DESPAWN: { Creature* cyrusClone = conversation->GetActorCreature(0); if (!cyrusClone) break; Unit* privateObjectOwner = ObjectAccessor::GetUnit(*conversation, conversation->GetPrivateObjectOwner()); if (!privateObjectOwner) return; if (Creature* gennClone = ObjectAccessor::GetCreature(*conversation, _gennCloneGUID)) gennClone->DespawnOrUnsummon(); cyrusClone->DespawnOrUnsummon(); PhasingHandler::OnConditionChange(privateObjectOwner); break; } default: break; } } private: ObjectGuid _gennCloneGUID; EventMap _events; }; // 122370 - Cyrus Crestfall struct npc_cyrus_crestfall_old_knight : public ScriptedAI { npc_cyrus_crestfall_old_knight(Creature* creature) : ScriptedAI(creature) { } bool OnGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override { // Quest 46729 - The Old Knight if (menuId == GOSSIP_MENU_CYRUS_SHAKING_HANDS && gossipListId == GOSSIP_OPTION_CYRUS_SHAKING_HANDS) { CloseGossipMenuFor(player); player->KilledMonsterCredit(KILLCREDIT_SPEAK_WITH_CYRUS_OLD_KNIGHT); Conversation::CreateConversation(CONVO_CYRUS_SHAKING_HAND, player, *player, player->GetGUID(), nullptr, false); } return true; } }; Position const CyrusMoveToOfficeFirePos = { 1075.257f, -487.25696f, 9.812291f }; Position const CyrusStaticOfficePos = { 1071.428f, -486.312f, 9.783f, 3.4995f }; // 7653 - Conversation class conversation_cyrus_crestfall_shaking_hands : public ConversationAI { public: conversation_cyrus_crestfall_shaking_hands(Conversation* conversation) : ConversationAI(conversation) { } enum ShakingHandsConversationData { CONVO_LINE_CYRUS_START_WALK_TO_FIRE = 17416, CONVO_LINE_CYRUS_CHANGE_FACING_GENN = 17419, CONVO_LINE_CYRUS_MOVE_BACK_TO_GENN = 17421, CONVO_LINE_CYRUS_DESPAWN_CLONE_OFFICE = 17423, EVENT_CYRUS_START_WALK_TO_FIRE = 1, EVENT_CYRUS_CHANGE_FACING_GENN = 2, EVENT_CYRUS_MOVE_BACK_TO_GENN = 3, EVENT_CYRUS_DESPAWN_CLONE_OFFICE = 4, POINT_CYRUS_MOVE_TO_OFFICE_FIRE = 1, POINT_CYRUS_MOVE_BACK_TO_GENN = 2 }; void OnCreate(Unit* creator) override { Creature* cyrusObject = GetClosestCreatureWithOptions(creator, 10.0f, { .CreatureId = NPC_CYRUS_CRESTFALL, .IgnorePhases = true }); if (!cyrusObject) return; TempSummon* cyrusClone = cyrusObject->SummonPersonalClone(cyrusObject->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, creator->ToPlayer()); if (!cyrusClone) return; cyrusClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER)); conversation->AddActor(CONVO_ACTOR_CYRUS_CRESTFAL, 1, cyrusClone->GetGUID()); conversation->Start(); } void OnStart() override { LocaleConstant privateOwnerLocale = conversation->GetPrivateObjectOwnerLocale(); _events.ScheduleEvent(EVENT_CYRUS_START_WALK_TO_FIRE, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_START_WALK_TO_FIRE)); _events.ScheduleEvent(EVENT_CYRUS_CHANGE_FACING_GENN, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_CHANGE_FACING_GENN)); _events.ScheduleEvent(EVENT_CYRUS_MOVE_BACK_TO_GENN, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_MOVE_BACK_TO_GENN)); _events.ScheduleEvent(EVENT_CYRUS_DESPAWN_CLONE_OFFICE, conversation->GetLineEndTime(privateOwnerLocale, CONVO_LINE_CYRUS_DESPAWN_CLONE_OFFICE)); } void OnUpdate(uint32 diff) override { _events.Update(diff); switch (_events.ExecuteEvent()) { case EVENT_CYRUS_START_WALK_TO_FIRE: { Creature* cyrusClone = conversation->GetActorCreature(1); if (!cyrusClone) break; cyrusClone->SetWalk(true); cyrusClone->GetMotionMaster()->MovePoint(POINT_CYRUS_MOVE_TO_OFFICE_FIRE, CyrusMoveToOfficeFirePos); break; } case EVENT_CYRUS_CHANGE_FACING_GENN: { Creature* cyrusClone = conversation->GetActorCreature(1); if (!cyrusClone) break; cyrusClone->SetFacingTo(3.49956f); break; } case EVENT_CYRUS_MOVE_BACK_TO_GENN: { Creature* cyrusClone = conversation->GetActorCreature(1); if (!cyrusClone) break; Player* privateObjectOwner = ObjectAccessor::GetPlayer(*conversation, conversation->GetPrivateObjectOwner()); if (!privateObjectOwner) return; cyrusClone->SetWalk(true); cyrusClone->GetMotionMaster()->MovePoint(POINT_CYRUS_MOVE_BACK_TO_GENN, CyrusStaticOfficePos); privateObjectOwner->KilledMonsterCredit(KILLCREDIT_HEAR_CYRUS_TALE_OLD_KNIGHT); break; } case EVENT_CYRUS_DESPAWN_CLONE_OFFICE: { Creature* cyrusClone = conversation->GetActorCreature(1); if (!cyrusClone) break; cyrusClone->DespawnOrUnsummon(); break; } default: break; } } private: EventMap _events; }; enum SanctumOfTheSagesData { QUEST_SANCTUM_OF_THE_SAGES = 47186, NPC_7TH_LEGION_MAGUS_WITH_GOSSIP = 137066, NPC_7TH_LEGION_MAGUS = 143613, GOSSIP_MENU_OPEN_CITY_PORTALS = 22548, GOSSIP_OPTION_OPEN_CITY_PORTALS = 0, CONVO_SANCTUM_OF_THE_SAGES = 8356, KILLCREDIT_OPEN_CAPITAL_PORTALS = 137066, SPELL_LEGION_MAGUS_ARCANE_CHANNEL = 54219, PATH_MAGUS_OPEN_PORTAL_STORMWIND = 13706600, PATH_MAGUS_FINISH_PORTAL_STORMWIND = 13706601, PATH_MAGUS_OPEN_PORTAL_EXODAR = 14361300, PATH_MAGUS_FINISH_PORTAL_EXODAR = 14361301, PATH_MAGUS_OPEN_PORTAL_IRONFORGE = 14361302, PATH_MAGUS_FINISH_PORTAL_IRONFORGE = 14361303 }; // 137066 - 7th Legion Magus // 143613 - 7th Legion Magus struct npc_7th_legion_magus_sanctum_of_the_sages : public ScriptedAI { npc_7th_legion_magus_sanctum_of_the_sages(Creature* creature) : ScriptedAI(creature) { } bool OnGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override { // Quest 47186 - Sanctum of the Sages if (menuId == GOSSIP_MENU_OPEN_CITY_PORTALS && gossipListId == GOSSIP_OPTION_OPEN_CITY_PORTALS) { CloseGossipMenuFor(player); player->KilledMonsterCredit(KILLCREDIT_OPEN_CAPITAL_PORTALS); Creature* magusStormwind = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = NPC_7TH_LEGION_MAGUS_WITH_GOSSIP, .StringId = "MagusStormwind", .IgnorePhases = true}); Creature* magusExodar = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = NPC_7TH_LEGION_MAGUS, .StringId = "MagusExodar", .IgnorePhases = true}); Creature* magusIronforge = GetClosestCreatureWithOptions(player, 10.0f, { .CreatureId = NPC_7TH_LEGION_MAGUS, .StringId = "MagusIronforge", .IgnorePhases = true}); if (!magusStormwind || !magusExodar || !magusIronforge) return true; TempSummon* magusStormwindClone = magusStormwind->SummonPersonalClone(magusStormwind->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); TempSummon* magusExodarClone = magusExodar->SummonPersonalClone(magusExodar->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); TempSummon* magusIronforgeClone = magusIronforge->SummonPersonalClone(magusIronforge->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!magusStormwindClone || !magusExodarClone || !magusIronforgeClone) return true; magusStormwindClone->RemoveNpcFlag(NPCFlags(UNIT_NPC_FLAG_GOSSIP)); magusStormwindClone->GetMotionMaster()->MovePath(PATH_MAGUS_OPEN_PORTAL_STORMWIND, false); magusExodarClone->GetMotionMaster()->MovePath(PATH_MAGUS_OPEN_PORTAL_EXODAR, false); magusIronforgeClone->GetMotionMaster()->MovePath(PATH_MAGUS_OPEN_PORTAL_IRONFORGE, false); } return true; } void WaypointReached(uint32 /*waypointId*/, uint32 pathId) override { if (pathId == PATH_MAGUS_OPEN_PORTAL_EXODAR) { DoCastAOE(SPELL_LEGION_MAGUS_ARCANE_CHANNEL); _scheduler.Schedule(3s + 500ms, [this](TaskContext task) { me->InterruptSpell(CURRENT_CHANNELED_SPELL); task.Schedule(1s + 500ms, [this](TaskContext /*task*/) { me->GetMotionMaster()->MovePath(PATH_MAGUS_FINISH_PORTAL_EXODAR, false); }); }); } else if (pathId == PATH_MAGUS_OPEN_PORTAL_IRONFORGE) { DoCastAOE(SPELL_LEGION_MAGUS_ARCANE_CHANNEL); _scheduler.Schedule(3s + 500ms, [this](TaskContext task) { me->InterruptSpell(CURRENT_CHANNELED_SPELL); task.Schedule(1s + 500ms, [this](TaskContext /*task*/) { me->GetMotionMaster()->MovePath(PATH_MAGUS_FINISH_PORTAL_IRONFORGE, false); }); }); } else if (pathId == PATH_MAGUS_OPEN_PORTAL_STORMWIND) { DoCastAOE(SPELL_LEGION_MAGUS_ARCANE_CHANNEL); _scheduler.Schedule(3s + 500ms, [this](TaskContext task) { me->InterruptSpell(CURRENT_CHANNELED_SPELL); task.Schedule(1s + 500ms, [this](TaskContext /*task*/) { TempSummon* summon = me->ToTempSummon(); if (!summon) return; Unit* summoner = summon->GetSummonerUnit(); if (!summoner) return; PhasingHandler::OnConditionChange(summoner); me->GetMotionMaster()->MovePath(PATH_MAGUS_FINISH_PORTAL_STORMWIND, false); }); }); } else if (pathId == PATH_MAGUS_FINISH_PORTAL_STORMWIND || pathId == PATH_MAGUS_FINISH_PORTAL_EXODAR || pathId == PATH_MAGUS_FINISH_PORTAL_IRONFORGE) me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; }; // 64 - Boralus - Sanctum of the Sages struct at_boralus_sanctum_of_the_sages_conversation : AreaTriggerAI { at_boralus_sanctum_of_the_sages_conversation(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player || player->GetQuestStatus(QUEST_SANCTUM_OF_THE_SAGES) != QUEST_STATUS_COMPLETE) return; Conversation::CreateConversation(CONVO_SANCTUM_OF_THE_SAGES, player, *player, player->GetGUID(), nullptr, true); } }; enum DaughterOfTheSeaData { NPC_JAINA_PROUDMOORE_BEFORE_AUDIENCE = 120922, SPELL_PLAY_SCENE_JAINA_PROCESSION = 270608, SPELL_OBJ_COMPLETE_KATHERINES_COURT = 241525, SPELL_WAKE_UP_IN_TOL_DAGOR = 270081 }; // 281460 - Teleport Off Ship class spell_boralus_teleport_off_ship : public SpellScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_PLAY_SCENE_JAINA_PROCESSION }); } void HandleHitSummoner(SpellEffIndex /*effIndex*/) { if (Player* player = GetHitUnit()->ToPlayer()) player->CastSpell(player, SPELL_PLAY_SCENE_JAINA_PROCESSION, false); } void HandleHitJaina(SpellEffIndex /*effIndex*/) { if (Creature* summon = GetHitCreature()) { if (summon->GetEntry() == NPC_JAINA_PROUDMOORE_BEFORE_AUDIENCE) summon->DespawnOrUnsummon(2s); } } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_boralus_teleport_off_ship::HandleHitSummoner, EFFECT_0, SPELL_EFFECT_DUMMY); OnEffectHitTarget += SpellEffectFn(spell_boralus_teleport_off_ship::HandleHitJaina, EFFECT_1, SPELL_EFFECT_DUMMY); } }; // 1954 - Play Scene: Jainas Procession class scene_boralus_jainas_procession : public SceneScript { public: scene_boralus_jainas_procession() : SceneScript("scene_boralus_jainas_procession") {} void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, SPELL_OBJ_COMPLETE_KATHERINES_COURT, true); } void OnSceneCancel(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, SPELL_OBJ_COMPLETE_KATHERINES_COURT, true); } }; // 241526 - Teleport to Tol Dagor class spell_boralus_teleport_to_tol_dagor : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_WAKE_UP_IN_TOL_DAGOR }); } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) caster->CastSpell(caster, SPELL_WAKE_UP_IN_TOL_DAGOR, false); } void Register() override { AfterEffectApply += AuraEffectRemoveFn(spell_boralus_teleport_to_tol_dagor::OnApply, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; void AddSC_zone_boralus() { // Creature RegisterCreatureAI(npc_taelia_get_your_bearings); RegisterCreatureAI(npc_cyrus_crestfall_old_knight); RegisterCreatureAI(npc_7th_legion_magus_sanctum_of_the_sages); // Conversation RegisterConversationAI(conversation_boralus_hub_tour_00); RegisterConversationAI(conversation_boralus_hub_tour_ferry); RegisterConversationAI(conversation_boralus_hub_tour_counting_house); RegisterConversationAI(conversation_boralus_hub_tour_harbor_inn); RegisterConversationAI(conversation_boralus_hub_tour_flight_master); RegisterConversationAI(conversation_boralus_accept_old_knight); RegisterConversationAI(conversation_boralus_enter_harbormaster_office); RegisterConversationAI(conversation_boralus_cyrus_meets_genn); RegisterConversationAI(conversation_cyrus_crestfall_shaking_hands); // Scene new scene_boralus_client_scene_cyrus_and_genn(); new scene_boralus_jainas_procession(); // AreaTrigger RegisterAreaTriggerAI(at_boralus_old_knight_enter_harbormasters_office); RegisterAreaTriggerAI(at_boralus_old_knight_genn_arrives_boralus); RegisterAreaTriggerAI(at_boralus_sanctum_of_the_sages_conversation); // AreaTrigger Template new GenericAreaTriggerEntityScript>("at_boralus_get_your_bearings_ferry"); new GenericAreaTriggerEntityScript>("at_boralus_get_your_bearings_counting_house"); new GenericAreaTriggerEntityScript>("at_boralus_get_your_bearings_inn"); new GenericAreaTriggerEntityScript>("at_boralus_get_your_bearings_flight_master"); // Spells RegisterSpellScript(spell_boralus_find_cyrus_objective_complete); RegisterSpellScript(spell_boralus_teleport_off_ship); RegisterSpellScript(spell_boralus_teleport_to_tol_dagor); }