/* * 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 "ScriptMgr.h" #include "AreaTrigger.h" #include "AreaTriggerAI.h" #include "CellImpl.h" #include "CombatAI.h" #include "Containers.h" #include "Conversation.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "MapUtils.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "PassiveAI.h" #include "PhasingHandler.h" #include "Player.h" #include "ScriptedCreature.h" #include "SpellAuras.h" #include "SpellHistory.h" #include "SpellInfo.h" #include "SpellScript.h" #include "TemporarySummon.h" #include "VehicleDefines.h" #include "WorldStateMgr.h" template CreatureAI* GetPrivatePublicPairAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new privateAI(creature); return new publicAI(creature); } #define RegisterPrivatePublicCreatureAIPair(scriptName, privateAI, publicAI) new FactoryCreatureScript>(scriptName); static Creature* FindCreatureIgnorePhase(WorldObject const* obj, std::string_view stringId, float range = 100.0f) { return obj->FindNearestCreatureWithOptions(range, { .StringId = stringId, .IgnorePhases = true }); } // ******************************************** // * Scripting in this section occurs on ship * // ******************************************** enum AttentionExilesReachData { SPELL_DEBUG_LOOK_RIGHT = 290903 }; // 290901 - Attention! class spell_attention_exiles_reach_tutorial : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_DEBUG_LOOK_RIGHT }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { GetTarget()->CastSpell(GetTarget(), SPELL_DEBUG_LOOK_RIGHT, true); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_attention_exiles_reach_tutorial::OnRemove, EFFECT_0, SPELL_AURA_MOD_ROOT, AURA_EFFECT_HANDLE_REAL); } }; enum WarmingUpData { CONVERSATION_WARMING_UP_ACCEPT = 12818, CONVERSATION_WARMING_UP_COMPLETE = 12798, }; class BaseQuestWarmingUp : public QuestScript { public: BaseQuestWarmingUp(const char* name) : QuestScript(name) { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) { if (newStatus == QUEST_STATUS_INCOMPLETE) Conversation::CreateConversation(CONVERSATION_WARMING_UP_ACCEPT, player, *player, player->GetGUID(), nullptr); else if (newStatus == QUEST_STATUS_COMPLETE) Conversation::CreateConversation(CONVERSATION_WARMING_UP_COMPLETE, player, *player, player->GetGUID(), nullptr); } }; class q56775_warming_up : public BaseQuestWarmingUp { public: q56775_warming_up() : BaseQuestWarmingUp("q56775_warming_up") { } static constexpr float CLONE_ORIENTATION = 5.124503135681152343f; static constexpr float CLONE_Z_OFFSET = 0.308f; void OnQuestStatusChange(Player* player, Quest const* quest, QuestStatus oldStatus, QuestStatus newStatus) override { BaseQuestWarmingUp::OnQuestStatusChange(player, quest, oldStatus, newStatus); if (newStatus == QUEST_STATUS_REWARDED) { Creature* garrickLowerDeck = FindCreatureIgnorePhase(player, "q56775_garrick_lower_deck", 5.0f); Creature* garrickUpperDeck = FindCreatureIgnorePhase(player, "q56775_garrick_upper_deck", 75.0f); if (!garrickLowerDeck || !garrickUpperDeck) return; Position pos(garrickLowerDeck->GetPositionX(), garrickLowerDeck->GetPositionY(), garrickLowerDeck->GetPositionZ() - CLONE_Z_OFFSET, CLONE_ORIENTATION); garrickUpperDeck->SummonPersonalClone(pos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } } }; class q59926_warming_up : public BaseQuestWarmingUp { public: q59926_warming_up() : BaseQuestWarmingUp("q59926_warming_up") { } void OnQuestStatusChange(Player* player, Quest const* quest, QuestStatus oldStatus, QuestStatus newStatus) override { BaseQuestWarmingUp::OnQuestStatusChange(player, quest, oldStatus, newStatus); if (newStatus == QUEST_STATUS_REWARDED) { Creature* grimaxeLowerDeck = FindCreatureIgnorePhase(player, "q59926_grimaxe_lower_deck", 5.0f); Creature* grimaxeUpperDeck = FindCreatureIgnorePhase(player, "q59926_grimaxe_upper_deck", 75.0f); if (!grimaxeLowerDeck || !grimaxeUpperDeck) return; grimaxeUpperDeck->SummonPersonalClone(*grimaxeLowerDeck, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } } }; enum WarmingUpCaptainData { NPC_WARLORD_BREKA_GRIMAXE2 = 166824, NPC_WARLORD_BREKA_GRIMAXE3 = 166827, NPC_CAPTAIN_GARRICK = 156280, PATH_GARRICK_TO_COLE = 10501450, PATH_GARRICK_TO_UPPER_DECK = 10501451, PATH_GRIMAXE_TO_THROG = 10501900, PATH_GRIMAXE_TO_UPPER_DECK = 10501901, EVENT_SHIP_CAPTAIN1_SCRIPT1 = 1, EVENT_SHIP_CAPTAIN1_SCRIPT2, EVENT_SHIP_CAPTAIN1_SCRIPT3, SAY_SPAR = 0, }; // 156280 - Captain Garrick // 166824 - Warlord Breka Grimaxe struct npc_ship_captain_warming_up_private : public ScriptedAI { npc_ship_captain_warming_up_private(Creature* creature) : ScriptedAI(creature), _pathToSparringPartner(0), _pathToUpperDeck(0) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } void JustAppeared() override { if (me->GetEntry() == NPC_CAPTAIN_GARRICK) { _pathToSparringPartner = PATH_GARRICK_TO_COLE; _pathToUpperDeck = PATH_GARRICK_TO_UPPER_DECK; } else if (me->GetEntry() == NPC_WARLORD_BREKA_GRIMAXE2) { _pathToSparringPartner = PATH_GRIMAXE_TO_THROG; _pathToUpperDeck = PATH_GRIMAXE_TO_UPPER_DECK; } _events.ScheduleEvent(EVENT_SHIP_CAPTAIN1_SCRIPT1, 1s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (pathId == _pathToSparringPartner) _events.ScheduleEvent(EVENT_SHIP_CAPTAIN1_SCRIPT2, 0s); else if (pathId == _pathToUpperDeck) me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SHIP_CAPTAIN1_SCRIPT1: Talk(SAY_SPAR); me->GetMotionMaster()->MovePath(_pathToSparringPartner, false); break; case EVENT_SHIP_CAPTAIN1_SCRIPT2: me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); _events.ScheduleEvent(EVENT_SHIP_CAPTAIN1_SCRIPT3, 3s); break; case EVENT_SHIP_CAPTAIN1_SCRIPT3: me->GetMotionMaster()->MovePath(_pathToUpperDeck, false); break; default: break; } } } private: EventMap _events; uint32 _pathToSparringPartner; uint32 _pathToUpperDeck; }; enum StandYourGroundData { ACTOR_ID_ALLIANCE = 68598, ACTOR_ID_HORDE = 75920, CONVERSATION_PREFIGHT = 14422, CONVERSATION_AGGRO = 14423, CONVERSATION_JUMP = 14424, EQUIPMENT_SWORD = 108493, EQUIPMENT_AXE = 175161, EVENT_MOVE_TO_A_POSITION = 1, EVENT_PREFIGHT_CONVERSATION, EVENT_JUMP_BEHIND, EVENT_WALK_BACK, PATH_ALLIANCE_SPARING_PARTNER = 10501460, PATH_HORDE_SPARING_PARTNER = 10501870, POSITION_SPARPOINT_ADVERTISMENT = 1, POSITION_SPARPOINT_READY = 2, TALK_SPARING_COMPLETE = 0, NPC_ALLIANCE_SPARING_PARTNER = 157051, NPC_HORDE_SPARING_PARTNER = 166814, NPC_SPAR_POINT_ADVERTISMENT = 174971, NPC_KILL_CREDIT = 155607, SPELL_COMBAT_TRAINING_COMPLETE = 303120, SPELL_JUMP_LEFT = 312757, SPELL_JUMP_BEHIND = 312755, SPELL_COMBAT_TRAINING = 323071, SPELL_UPDATE_PHASE_SHIFT = 82238, }; // 58209 - Stand Your Ground // 59927 - Stand Your Ground class quest_stand_your_ground : public QuestScript { public: quest_stand_your_ground() : QuestScript("quest_stand_your_ground") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { // Remove aura if player drops quest if (newStatus == QUEST_STATUS_NONE) { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, SPELL_COMBAT_TRAINING_COMPLETE); } } }; // 303065 - Summon Cole - Combat Training (DNT) // 325108 - Summon Throg - Combat Training (DNT) class spell_summon_sparring_partner : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Player* caster = GetCaster()->ToPlayer(); if (!caster) return; Creature* partner = FindCreatureIgnorePhase(caster, caster->GetTeam() == ALLIANCE ? "q58209_cole" : "q59927_throg", 10.0f); if (!partner) return; target = partner; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_sparring_partner::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; // 157051 - Alliance Sparring Partner // 166814 - Horde Sparring Partner struct npc_sparring_partner_exiles_reach : public ScriptedAI { npc_sparring_partner_exiles_reach(Creature* creature) : ScriptedAI(creature), _jumped(false), _actorIndex(0), _actorId(0), _path(0) { } void JustAppeared() override { if (me->GetEntry() == NPC_ALLIANCE_SPARING_PARTNER) { SetEquipmentSlots(false, EQUIPMENT_SWORD, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); _path = PATH_ALLIANCE_SPARING_PARTNER; _actorId = ACTOR_ID_ALLIANCE; _actorIndex = 0; } else if (me->GetEntry() == NPC_HORDE_SPARING_PARTNER) { SetEquipmentSlots(false, EQUIPMENT_AXE, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); _path = PATH_HORDE_SPARING_PARTNER; _actorId = ACTOR_ID_HORDE; _actorIndex = 1; } me->SetImmuneToPC(true); _events.ScheduleEvent(EVENT_MOVE_TO_A_POSITION, 1s); } void EnterEvadeMode(EvadeReason /*why*/) override { if (!me->IsAlive()) return; me->CombatStop(true); EngagementOver(); me->ResetPlayerDamageReq(); _events.ScheduleEvent(EVENT_WALK_BACK, 1s); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; switch (uiId) { case POSITION_SPARPOINT_ADVERTISMENT: me->SetWalk(true); me->GetMotionMaster()->MovePoint(POSITION_SPARPOINT_READY, me->GetFirstCollisionPosition(2.0f, rand_norm() * static_cast(2 * M_PI))); break; case POSITION_SPARPOINT_READY: if (Unit* owner = me->GetDemonCreator()) me->SetFacingToObject(owner); me->SetImmuneToPC(false); me->SetUninteractible(false); break; default: break; } } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (pathId != _path) return; if (Unit* owner = me->GetDemonCreator()) { me->DespawnOrUnsummon(); owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); owner->CastSpell(owner, SPELL_COMBAT_TRAINING_COMPLETE); } } void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (me->GetHealth() <= damage) { damage = 0; me->SetHealth(1); DoStopAttack(); me->SetImmuneToPC(true); me->SetUninteractible(true); _events.CancelEvent(EVENT_JUMP_BEHIND); if (Player* player = me->GetDemonCreatorPlayer()) { me->SetFacingToObject(player); Talk(TALK_SPARING_COMPLETE, player); player->CastSpell(player, SPELL_COMBAT_TRAINING); player->KilledMonsterCredit(NPC_KILL_CREDIT); } } if (me->HealthBelowPctDamaged(65, damage) && !_jumped) { _jumped = true; DoCastVictim(SPELL_JUMP_LEFT, true); StartPrivateConversation(CONVERSATION_JUMP); _events.ScheduleEvent(EVENT_JUMP_BEHIND, 2s); } } void JustEngagedWith(Unit* /*who*/) override { StartPrivateConversation(CONVERSATION_AGGRO); } void DamageDealt(Unit* target, uint32& damage, DamageEffectType /*damageType*/) override { if (target->GetHealthPct() < 95) damage = 0; } void StartPrivateConversation(uint32 conversationId) { if (Unit* owner = me->GetDemonCreator()) { Conversation* conversation = Conversation::CreateConversation(conversationId, owner, *owner, owner->GetGUID(), nullptr, false); conversation->AddActor(_actorId, _actorIndex, me->GetGUID()); conversation->Start(); } } Creature* GetRandomSparPoint() { std::list sparPoints; GetCreatureListWithEntryInGrid(sparPoints, me, NPC_SPAR_POINT_ADVERTISMENT, 25.0f); Trinity::Containers::RandomResize(sparPoints, 1); if (sparPoints.empty()) // should never happen return nullptr; return sparPoints.front(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_MOVE_TO_A_POSITION: { if (Creature* sparPoint = GetRandomSparPoint()) me->GetMotionMaster()->MovePoint(POSITION_SPARPOINT_ADVERTISMENT, sparPoint->GetPosition()); _events.ScheduleEvent(EVENT_PREFIGHT_CONVERSATION, 1s); break; } case EVENT_PREFIGHT_CONVERSATION: StartPrivateConversation(CONVERSATION_PREFIGHT); break; case EVENT_JUMP_BEHIND: DoCastVictim(SPELL_JUMP_BEHIND, true); break; case EVENT_WALK_BACK: me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePath(_path, false); break; default: break; } } if (!UpdateVictim()) return; } private: EventMap _events; bool _jumped; uint8 _actorIndex; uint32 _actorId; uint32 _path; }; enum FirstMateStandYourGroundData { QUEST_STAND_YOUR_GROUND_ALLIANCE = 58209, QUEST_STAND_YOUR_GROUND_HORDE = 59927, SPELL_SUMMON_COLE = 303064, SPELL_SUMMON_THROG = 325107, }; // 160664 - Private Cole // 166583 - Grunt Throg struct npc_first_mate_stand_your_ground : public ScriptedAI { npc_first_mate_stand_your_ground(Creature* creature) : ScriptedAI(creature) { } void OnQuestAccept(Player* player, Quest const* quest) override { if (quest->GetQuestId() == QUEST_STAND_YOUR_GROUND_ALLIANCE) { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, SPELL_SUMMON_COLE); } else if (quest->GetQuestId() == QUEST_STAND_YOUR_GROUND_HORDE) { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, SPELL_SUMMON_THROG); } } }; struct ActorData { std::string_view StringId; Position ActorPosition; }; static std::vector const ActorDataMap[2] = { // TEAM_ALLIANCE { { "q58208_garrick", { 35.5643f, -1.19837f, 12.1479f, 3.3272014f } }, { "q58208_richter", { -1.84858f, -8.38776f, 5.10018f, 1.5184366f } }, { "q58208_keela", { -15.3642f, 6.5793f, 5.5026f, 3.1415925f } }, { "q58208_bjorn", { 12.8406f, -8.49553f, 4.98031f, 4.8520155f } }, { "q58208_austin", { -4.48607f, 9.89729f, 5.07851f, 1.5184366f } }, { "q58208_cole", { -13.3396f, 0.702157f, 5.57996f, 0.087266445f } }, }, // TEAM_HORDE { { "q59928_grimaxe", { 25.5237f, 0.283005f, 26.5455f, 3.3526998f } }, { "q59928_throg", { -10.8399f, 11.9039f, 8.88028f, 6.2308254f } }, { "q59928_mithdran", { -24.4763f, -4.48273f, 9.13471f, 0.62831855f } }, { "q59928_lana", { -5.1971f, -15.0268f, 8.992f, 4.712389f } }, { "q59928_bo", { -22.1559f, 5.58041f, 9.09176f, 6.143559f } }, { "q59928_jinhake", { -31.9464f, 7.5772f, 10.6408f, 6.0737457f } }, } }; static std::unordered_map const ActorPetData = { { RACE_HUMAN, "q58208_wolf" }, { RACE_DWARF, "q58208_bear" }, { RACE_NIGHTELF, "q58208_tiger" }, { RACE_GNOME, "q58208_bunny" }, { RACE_DRAENEI, "q58208_moth" }, { RACE_WORGEN, "q58208_dog" }, { RACE_PANDAREN_ALLIANCE, "q58208_turtle" }, { RACE_ORC, "q59928_wolf" }, { RACE_UNDEAD_PLAYER, "q59928_bat" }, { RACE_TAUREN, "q59928_plainstrider" }, { RACE_TROLL, "q59928_raptor" }, { RACE_GOBLIN, "q59928_scorpion" }, { RACE_BLOODELF, "q59928_dragonhawk" }, { RACE_PANDAREN_HORDE, "q59928_turtle" } }; enum BraceForImpactData { QUEST_BRACE_FOR_IMPACT_ALLIANCE = 58208, QUEST_BRACE_FOR_IMPACT_HORDE = 59928, }; // 58208 - Brace For Impact // 59928 - Brace For Impact class quest_brace_for_impact : public QuestScript { public: quest_brace_for_impact() : QuestScript("quest_brace_for_impact") { } void OnQuestStatusChange(Player* player, Quest const* quest, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { if (newStatus != QUEST_STATUS_COMPLETE) return; TeamId team = TEAM_NEUTRAL; Position petSpawnPos; if (quest->GetQuestId() == QUEST_BRACE_FOR_IMPACT_ALLIANCE) { team = TEAM_ALLIANCE; petSpawnPos = { -1.4492f, 8.06887f, 5.10348f, 2.6005409f }; } else if (quest->GetQuestId() == QUEST_BRACE_FOR_IMPACT_HORDE) { team = TEAM_HORDE; petSpawnPos = { -22.8374f, -3.08287f, 9.12613f, 3.857178f }; } if (team == TEAM_NEUTRAL) return; SpawnActors(player, team, petSpawnPos); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } void SpawnActors(Player* player, TeamId team, Position petSpawnPos) { for (ActorData const& actor : ActorDataMap[team]) SpawnActor(player, FindCreatureIgnorePhase(player, actor.StringId, 50.0f), actor.ActorPosition); SpawnPet(player, petSpawnPos); } void SpawnPet(Player* player, Position const& position) { if (player->GetClass() != CLASS_HUNTER) return; if (std::string_view const* stringId = Trinity::Containers::MapGetValuePtr(ActorPetData, Races(player->GetRace()))) { Creature* pet = FindCreatureIgnorePhase(player, *stringId, 25.0f); if (!pet) return; SpawnActor(player, pet, position); } } void SpawnActor(Player* player, Creature* creature, Position const& position) { TransportBase const* transport = player->GetDirectTransport(); if (!transport || !creature) return; float x, y, z, o; position.GetPosition(x, y, z, o); transport->CalculatePassengerPosition(x, y, z, &o); creature->SummonPersonalClone({ x, y, z, o }, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } }; enum BraceForImpactCaptainData { PATH_GARRICK_FROM_UPPER_DECK = 10505890, PATH_GARRICK_TO_LOWER_DECK = 10505891, PATH_GRIMAXE_FROM_UPPER_DECK = 10501910, PATH_GRIMAXE_TO_LOWER_DECK = 10501911, EVENT_SHIP_CAPTAIN2_SCRIPT1 = 1, EVENT_SHIP_CAPTAIN2_SCRIPT2, SAY_GET_TO_POSITIONS = 1, }; // 156280 - Captain Garrick // 166827 - Warlord Breka Grimaxe struct npc_ship_captain_brace_for_impact_private : public ScriptedAI { npc_ship_captain_brace_for_impact_private(Creature* creature) : ScriptedAI(creature), _pathPreTalk(0), _pathPostTalk(0), _waitTime(0s){ } void JustAppeared() override { if (me->GetEntry() == NPC_CAPTAIN_GARRICK) { _pathPreTalk = PATH_GARRICK_FROM_UPPER_DECK; _pathPostTalk = PATH_GARRICK_TO_LOWER_DECK; _waitTime = 0s; } else if (me->GetEntry() == NPC_WARLORD_BREKA_GRIMAXE3) { _pathPreTalk = PATH_GRIMAXE_FROM_UPPER_DECK; _pathPostTalk = PATH_GRIMAXE_TO_LOWER_DECK; _waitTime = 1s; } me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); me->GetMotionMaster()->MovePath(_pathPreTalk, false); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (pathId == _pathPreTalk) _events.ScheduleEvent(EVENT_SHIP_CAPTAIN2_SCRIPT1, _waitTime); else if (pathId == _pathPostTalk) me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SHIP_CAPTAIN2_SCRIPT1: Talk(SAY_GET_TO_POSITIONS); _events.ScheduleEvent(EVENT_SHIP_CAPTAIN2_SCRIPT2, 3s); break; case EVENT_SHIP_CAPTAIN2_SCRIPT2: me->GetMotionMaster()->MovePath(_pathPostTalk, false); break; default: break; } } } private: EventMap _events; uint32 _pathPreTalk; uint32 _pathPostTalk; Seconds _waitTime; }; enum BraceForImpactFirstMateData { NPC_PRIVATE_COLE = 160664, NPC_GRUNT_THROG = 166583, PATH_COLE_BRACE_FOR_IMPACT = 10501461, PATH_THROG_BRACE_FOR_IMPACT = 10501871, EVENT_FIRST_MATE_1 = 1, EVENT_FIRST_MATE_2, SAY_STORM = 0, }; // 160664 - Private Cole // 166583 - Grunt Throg struct npc_first_mate_brace_for_impact_private : public ScriptedAI { npc_first_mate_brace_for_impact_private(Creature* creature) : ScriptedAI(creature), _path(0) { } void JustAppeared() override { if (me->GetEntry() == NPC_PRIVATE_COLE) _path = PATH_COLE_BRACE_FOR_IMPACT; else if (me->GetEntry() == NPC_GRUNT_THROG) _path = PATH_THROG_BRACE_FOR_IMPACT; _events.ScheduleEvent(EVENT_FIRST_MATE_1, 3s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (_path && pathId == _path) me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_FIRST_MATE_1: Talk(SAY_STORM); _events.ScheduleEvent(EVENT_FIRST_MATE_2, 4s); break; case EVENT_FIRST_MATE_2: me->GetMotionMaster()->MovePath(_path, false); break; default: break; } } } private: EventMap _events; uint32 _path; }; enum BraceForImpactCrewData { NPC_QUARTERMASTER_RICHTER = 157042, NPC_KEE_LA = 157043, NPC_BJORN_STOUTHANDS = 157044, NPC_AUSTIN_HUXWORTH = 157046, NPC_BO = 166585, NPC_MITHDRAN_DAWNTRACKER = 166590, NPC_LANA_JORDAN = 166794, NPC_PROVISONER_JIN_HAKE = 166799, PATH_RICHTER_BRACE_FOR_IMPACT = 10501770, PATH_KEE_LA_BRACE_FOR_IMPACT = 10501800, PATH_BJORN_BRACE_FOR_IMPACT = 10501790, PATH_AUSTIN_BRACE_FOR_IMPACT = 10501780, PATH_BO_BRACE_FOR_IMPACT = 10502010, PATH_MITHDRAN_BRACE_FOR_IMPACT = 10501990, PATH_LANA_BRACE_FOR_IMPACT = 10501980, PATH_JIN_HAKE_BRACE_FOR_IMPACT = 10502000, }; // 157042 - Quartermaster Richter // 157043 - Kee-La // 157044 - Bjorn Stouthands // 157046 - Austin Huxworth // 166585 - Bo // 166590 - Mithdran Dawntracker // 166794 - Lana Jordan // 166799 - Provisoner Jin'hake struct npc_crew_ship_private : public ScriptedAI { npc_crew_ship_private(Creature* creature) : ScriptedAI(creature), _path(0) { } uint32 GetPathID() { switch (me->GetEntry()) { case NPC_QUARTERMASTER_RICHTER: return PATH_RICHTER_BRACE_FOR_IMPACT; case NPC_KEE_LA: return PATH_KEE_LA_BRACE_FOR_IMPACT; case NPC_BJORN_STOUTHANDS: return PATH_BJORN_BRACE_FOR_IMPACT; case NPC_AUSTIN_HUXWORTH: return PATH_AUSTIN_BRACE_FOR_IMPACT; case NPC_BO: return PATH_BO_BRACE_FOR_IMPACT; case NPC_MITHDRAN_DAWNTRACKER: return PATH_MITHDRAN_BRACE_FOR_IMPACT; case NPC_LANA_JORDAN: return PATH_LANA_BRACE_FOR_IMPACT; case NPC_PROVISONER_JIN_HAKE: return PATH_JIN_HAKE_BRACE_FOR_IMPACT; default: return 0; } } void JustAppeared() override { _path = GetPathID(); _scheduler.Schedule(Seconds(7), [this](TaskContext) { me->GetMotionMaster()->MovePath(_path, false); }); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { if (_path && pathId == _path) me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; uint32 _path; }; enum BraceForImpactPetData { EVENT_PET_SHIP_RUN_TO_POSITION = 1, MAP_ALLIANCE_SHIP = 2261, MAP_HORDE_SHIP = 2369, PATH_PET_ALLIANCE_SHIP = 10501510, PATH_PET_HORDE_SHIP = 10502020 }; // 167337 - Mechanical Bunny // 167342 - Moth // 167343 - Dragonhawk // 167344 - Scorpion // 167345 - Wolf // 167346 - Wolf // 167347 - Tiger // 167348 - Turtle // 167349 - Plainstrider // 167350 - Raptor // 167351 - Bat // 167352 - Dog // 167375 - Bear struct npc_pet_ship_private : public ScriptedAI { npc_pet_ship_private(Creature* creature) : ScriptedAI(creature), _path(0) { } void JustAppeared() override { if (!me->GetTransport()) return; int32 transportMap = me->GetTransport()->GetMapIdForSpawning(); if (transportMap == MAP_ALLIANCE_SHIP) _path = PATH_PET_ALLIANCE_SHIP; else if (transportMap == MAP_HORDE_SHIP) _path = PATH_PET_HORDE_SHIP; if (_path) _events.ScheduleEvent(EVENT_PET_SHIP_RUN_TO_POSITION, 8s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { if (eventId == EVENT_PET_SHIP_RUN_TO_POSITION) me->GetMotionMaster()->MovePath(_path, false); } } private: EventMap _events; uint32 _path; }; enum ExilesReachShipCrashData { MOVIE_ALLIANCE_SHIP_CRASH = 895, MOVIE_HORDE_SHIP_CRASH = 931, SPELL_ALLIANCE_SHIP_CRASH = 305446, SPELL_HORDE_SHIP_CRASH = 325133, SPELL_BEGIN_TUTORIAL = 295600, }; class player_exiles_reach_ship_crash : public PlayerScript { public: player_exiles_reach_ship_crash() : PlayerScript("player_exiles_reach_ship_crash") { } void OnMovieComplete(Player* player, uint32 movieId) override { switch (movieId) { case MOVIE_ALLIANCE_SHIP_CRASH: player->CastSpell(player, SPELL_ALLIANCE_SHIP_CRASH, true); break; case MOVIE_HORDE_SHIP_CRASH: player->CastSpell(player, SPELL_HORDE_SHIP_CRASH, true); break; default: break; } } }; class scene_alliance_and_horde_ship : public SceneScript { public: scene_alliance_and_horde_ship() : SceneScript("scene_alliance_and_horde_ship") { } void StartConvo(Player* player) { // This script is used to send conversation to Captian Garrick and Warlord Grimaxe on movement after entering ship player->CastSpell(player, SPELL_BEGIN_TUTORIAL, true); } void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { StartConvo(player); } void OnSceneCancel(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { StartConvo(player); } }; // *************************************************************** // * Scripting in this section occurs after teleporting to beach * // *************************************************************** enum KnockedDownExilesReachData { SPELL_KNOCKED_DOWN_STUN2 = 344889 }; // 305445 - Knocked Down! class spell_knocked_down_exiles_reach_beach : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_KNOCKED_DOWN_STUN2 }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { GetTarget()->CastSpell(nullptr, SPELL_KNOCKED_DOWN_STUN2, true); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_knocked_down_exiles_reach_beach::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); } }; enum ExilesReachShipCrashBeachData { SPELL_KNOCKED_DOWN = 305445, SPELL_CRASHED_LANDED_ALLIANCE = 305464, SPELL_CRASHED_LANDED_HORDE = 325136 }; // Script scene for washed up on beach to cast spells Alliance and Horde class scene_alliance_and_horde_crash : public SceneScript { public: scene_alliance_and_horde_crash() : SceneScript("scene_alliance_and_horde_crash") { } void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override { if (triggerName == "Begin Knockdown Aura") player->CastSpell(player, SPELL_KNOCKED_DOWN, true); } void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, player->GetTeam() == ALLIANCE ? SPELL_CRASHED_LANDED_ALLIANCE : SPELL_CRASHED_LANDED_HORDE, true); } }; CreatureAI* CaptainGarrickAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if ((privateObjectOwner->GetTeam() == ALLIANCE && privateObjectOwner->GetQuestStatus(QUEST_BRACE_FOR_IMPACT_ALLIANCE) == QUEST_STATUS_NONE)) return new npc_ship_captain_warming_up_private(creature); else return new npc_ship_captain_brace_for_impact_private(creature); } } return new NullCreatureAI(creature); }; enum SpellCrashLandedData { NPC_CAPTAIN_GARRICK_BEACH = 156626, NPC_WARLORD_BREKA_GRIMAXE_BEACH = 166782 }; // 305464 - Crash Landed // 325136 - Crash Landed template class spell_crash_landed_generic : public SpellScript { void HandleEffect(SpellEffIndex /*effIndex*/) { Player* player = GetCaster()->ToPlayer(); if (!player) return; if (Creature* creature = player->FindNearestCreature(StaticCaptainNPCId, 50.0f)) creature->SummonPersonalClone(creature->GetPosition(), TempSummonType(TEMPSUMMON_MANUAL_DESPAWN), 0s, 0, 0, player); } void Register() override { OnEffectHit += SpellEffectFn(spell_crash_landed_generic::HandleEffect, EFFECT_0, SPELL_EFFECT_SEND_EVENT); } }; enum ExilesReachCaptainsBeachData { CONVERSATION_QUEST_MURLOC_MANIA_ALLIANCE = 12043, CONVERSATION_QUEST_MURLOC_MANIA_HORDE = 14432, EVENT_EMERGENCY_FIRST_AID_SCRIPT_SHEATH = 1, EVENT_EMERGENCY_FIRST_AID_SCRIPT_BANDAGE, EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_SECOND_SURVIVOR, EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_HOME_BEACH, POINT_SECOND_SURVIVOR = 0, POINT_BEACH_HOME = 1, QUEST_MURLOC_MANIA_ALLIANCE = 55122, QUEST_EMERGENCY_FIRST_AID_ALLIANCE = 54951, QUEST_MURLOC_MANIA_HORDE = 59929, QUEST_EMERGENCY_FIRST_AID_HORDE = 59930, SPELL_BANDAGING = 305584, TALK_ARRIVED_AT_BEACH = 0 }; // 156626 - Captain Garrick // 166782 - Warlord Breka Grimaxe struct npc_captain_warlord_beach_arrive_private : public ScriptedAI { npc_captain_warlord_beach_arrive_private(Creature* creature) : ScriptedAI(creature) { } void IsSummonedBy(WorldObject* summonerWO) override { Player* summoner = summonerWO->ToPlayer(); if (!summoner) return; me->SetFacingToObject(summoner); Talk(TALK_ARRIVED_AT_BEACH, summoner); me->DespawnOrUnsummon(5s); } }; // 156626 - Captain Garrick // 166782 - Warlord Breka Grimaxe // for Emergency first aid quest 54951 struct npc_captain_warlord_first_aid_private : public ScriptedAI { npc_captain_warlord_first_aid_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } void IsSummonedBy(WorldObject* summonerWO) override { Player* summoner = summonerWO->ToPlayer(); if (!summoner) return; _events.ScheduleEvent(EVENT_EMERGENCY_FIRST_AID_SCRIPT_SHEATH, 2s); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; switch (uiId) { case POINT_SECOND_SURVIVOR: if (Creature* mate = ObjectAccessor::GetCreature(*me, _quartermasterGUID)) me->CastSpell(mate, SPELL_BANDAGING); _events.ScheduleEvent(EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_HOME_BEACH, 6s); break; case POINT_BEACH_HOME: me->DespawnOrUnsummon(); break; default: break; } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_EMERGENCY_FIRST_AID_SCRIPT_SHEATH: me->SetSheath(SHEATH_STATE_UNARMED); _events.ScheduleEvent(EVENT_EMERGENCY_FIRST_AID_SCRIPT_BANDAGE, 1s); break; case EVENT_EMERGENCY_FIRST_AID_SCRIPT_BANDAGE: if (Creature* mate = ObjectAccessor::GetCreature(*me, _firstMateGUID)) me->CastSpell(mate, SPELL_BANDAGING); _events.ScheduleEvent(EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_SECOND_SURVIVOR, 5s); break; case EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_SECOND_SURVIVOR: me->GetMotionMaster()->MovePoint(POINT_SECOND_SURVIVOR, -414.15277f, -2605.2014f, 0.91079247f, false); break; case EVENT_EMERGENCY_FIRST_AID_SCRIPT_MOVE_HOME_BEACH: me->GetMotionMaster()->MovePoint(POINT_BEACH_HOME, -435.15277f, -2610.9915f, 0.649292f, false); break; default: break; } } } public: void SetFirstMateGUID(ObjectGuid coleGUID) { _firstMateGUID = coleGUID; } void SetQuartermasterGUID(ObjectGuid richterGUID) { _quartermasterGUID = richterGUID; } private: EventMap _events; ObjectGuid _firstMateGUID; ObjectGuid _quartermasterGUID; }; // 156626 - Captain Garrick struct npc_captain_garrick_beach : public ScriptedAI { npc_captain_garrick_beach(Creature* creature) : ScriptedAI(creature) { } void OnQuestAccept(Player* player, Quest const* quest) override { switch (quest->GetQuestId()) { case QUEST_MURLOC_MANIA_ALLIANCE: Conversation::CreateConversation(CONVERSATION_QUEST_MURLOC_MANIA_ALLIANCE, player, *player, player->GetGUID(), nullptr); break; case QUEST_EMERGENCY_FIRST_AID_ALLIANCE: { Creature* cole = FindCreatureIgnorePhase(player, "private_cole_beach", 50.0f); Creature* richter = FindCreatureIgnorePhase(player, "quartermaster_richter_beach", 50.0f); if (!cole || !richter) return; Creature* colePersonal = cole->SummonPersonalClone(cole->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* richterPersonal = richter->SummonPersonalClone(richter->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* mePersonal = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!colePersonal || !richterPersonal || !mePersonal) return; if (npc_captain_warlord_first_aid_private* personalAI = CAST_AI(npc_captain_warlord_first_aid_private, mePersonal->GetAI())) { personalAI->SetFirstMateGUID(colePersonal->GetGUID()); personalAI->SetQuartermasterGUID(richterPersonal->GetGUID()); } break; } default: break; } } }; // 166782 - Warlord Breka Grimaxe struct npc_warlord_grimaxe_beach : public ScriptedAI { npc_warlord_grimaxe_beach(Creature* creature) : ScriptedAI(creature) { } void OnQuestAccept(Player* player, Quest const* quest) override { switch (quest->GetQuestId()) { case QUEST_MURLOC_MANIA_HORDE: Conversation::CreateConversation(CONVERSATION_QUEST_MURLOC_MANIA_HORDE, player, *player, player->GetGUID(), nullptr); break; case QUEST_EMERGENCY_FIRST_AID_HORDE: { Creature* throg = FindCreatureIgnorePhase(player, "grunt_throg_beach", 50.0f); Creature* jinhake = FindCreatureIgnorePhase(player, "jin_hake_beach", 50.0f); if (!throg || !jinhake) return; Creature* throgPersonal = throg->SummonPersonalClone(throg->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* jinhakePersonal = jinhake->SummonPersonalClone(jinhake->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* mePersonal = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!throgPersonal || !jinhakePersonal || !mePersonal) return; if (npc_captain_warlord_first_aid_private* personalAI = CAST_AI(npc_captain_warlord_first_aid_private, mePersonal->AI())) { personalAI->SetFirstMateGUID(throgPersonal->GetGUID()); personalAI->SetQuartermasterGUID(jinhakePersonal->GetGUID()); } break; } default: break; } } }; CreatureAI* CaptainGarrickBeachAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_MURLOC_MANIA_ALLIANCE) == QUEST_STATUS_NONE) return new npc_captain_warlord_beach_arrive_private(creature); else return new npc_captain_warlord_first_aid_private(creature); } } return new npc_captain_garrick_beach(creature); }; CreatureAI* WarlordGrimaxeBeachAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_MURLOC_MANIA_HORDE) == QUEST_STATUS_NONE) return new npc_captain_warlord_beach_arrive_private(creature); else return new npc_captain_warlord_first_aid_private(creature); } } return new npc_warlord_grimaxe_beach(creature); }; enum HealedByLeaderBeachData { EVENT_SALUTE = 1, EVENT_LEAVE_BEACH, NPC_COLE_BEACH = 149917, NPC_RICHTER_BEACH = 156622, NPC_THROG_BEACH = 166784, NPC_JINHAKE_BEACH = 166800, PATH_LONG_BEACH = 10520070, PATH_SHORT_BEACH = 10520080 }; // 149917 - Private Cole // 156622 - Quartermaster Richter // 166784 - Grunt Throg // 166800 - Provisioner Jin'hake // for Emergency first aid quest template struct npc_survivors_healed_by_leader_beach_private : public ScriptedAI { npc_survivors_healed_by_leader_beach_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->SetStandState(UNIT_STAND_STATE_SLEEP); } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_BANDAGING) return; _casterGUID = caster->GetGUID(); me->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_SALUTE, 2s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SALUTE: if (Creature* caster = ObjectAccessor::GetCreature(*me, _casterGUID)) me->SetFacingToObject(caster); me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); _events.ScheduleEvent(EVENT_LEAVE_BEACH, 2s); break; case EVENT_LEAVE_BEACH: me->GetMotionMaster()->MovePath(PathId, false); me->DespawnOrUnsummon(Milliseconds(WaitTime)); break; default: break; } } } private: EventMap _events; ObjectGuid _casterGUID; }; CreatureAI* HealedByLeaderAllianceAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_survivors_healed_by_leader_beach_private(creature); return new NullCreatureAI(creature); }; CreatureAI* HealedByLeaderHordeAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_survivors_healed_by_leader_beach_private(creature); return new NullCreatureAI(creature); }; enum ExilesReachAllianceSurvivorsBeachData { CONVERSATION_STOUTHANDS_BEACH = 11685, CONVERSATION_HUXWORTH_BEACH = 12128, CONVERSATION_KEE_LA_BEACH = 12127, NPC_BJORN_STOUTHANDS_LAYING = 156609, NPC_AUSTIN_HUXWORTH_LAYING = 156610, NPC_KEE_LA_LAYING = 156612, NPC_KEE_LA_STANDING = 151088, NPC_BJORN_STOUTHANDS_STANDING = 151089, NPC_AUSTIN_HUXWORTH_STANDING = 154170, PATH_KEE_LA_STANDING = ((1052012 * 10) + 1) << 3, PATH_BJORN_STOUTHANDS_STANDING = ((1052013 * 10) + 1) << 3, PATH_AUSTIN_HUXWORTH_STANDING = ((1052014 * 10) + 1) << 3, SPELL_BANDAGING_QUEST = 297415 }; // 156609 - Bjorn Stouthands // 156610 - Austin Huxworth // 156612 - Kee-La template struct npc_alliance_survivors_beach_laying : public ScriptedAI { npc_alliance_survivors_beach_laying(Creature* creature) : ScriptedAI(creature) { } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_BANDAGING_QUEST) return; if (Player* player = caster->ToPlayer()) { player->KilledMonsterCredit(me->GetEntry()); Conversation::CreateConversation(ConversationId, player, *player, player->GetGUID(), nullptr); player->UpdateVisibilityForPlayer(); // Needed to make survivor stand instantly } } }; enum ExilesReachHordeSurvivorsBeachData { EVENT_SURVIVORS_HORDE_STAND_AND_TALK = 1, EVENT_SURVIVORS_HORDE_MOVE_TO_GRIMAXE, EVENT_SURVIVORS_SALUTE = 1, EVENT_SURVIVORS_LEAVE_BEACH, NPC_BO_LAYING_LAYING = 166786, NPC_MITHDRAN_LAYING = 166791, NPC_LANA_JORDAN_LAYING = 166796, NPC_BO_STANDING = 166787, NPC_MITHDRAN_STANDING = 166792, NPC_LANA_JORDAN_STANDING = 166797, QUEST_FINDING_THE_LOST_EXPEDITION_HORDE = 59931, QUEST_FINDING_THE_LOST_EXPEDITION_ALLIANCE = 54952, PATH_BO_TO_GRIMAXE = 10520210, PATH_MITHDRAN_TO_GRIMAXE = 10520220, PATH_LANA_JORDAN_TO_GRIMAXE = 10520230, PATH_BO_LEAVE_BEACH = ((1052021 * 10) + 1) << 3, PATH_MITHDRAN_LEAVE_BEACH = ((1052022 * 10) + 1) << 3, PATH_LANA_JORDAN_LEAVE_BEACH = ((1052023 * 10) + 1) << 3, TALK_HORDE_BEACH_THANK_PLAYER = 0 }; // 166786 - Bo struct npc_bo_beach_laying : public ScriptedAI { npc_bo_beach_laying(Creature* creature) : ScriptedAI(creature) { } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_BANDAGING_QUEST) return; static const Position BoCloneSpawnPosition = { -448.731f, -2606.03f, 0.602435f, 6.17441f }; if (Player* player = caster->ToPlayer()) { player->KilledMonsterCredit(me->GetEntry()); if (Creature* survivor = FindCreatureIgnorePhase(player, "bo_beach", 50.0f)) survivor->SummonPersonalClone(BoCloneSpawnPosition, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } } }; // 166791 - Mithdran Dawntracker struct npc_mithran_dawntracker_beach_laying : public ScriptedAI { npc_mithran_dawntracker_beach_laying(Creature* creature) : ScriptedAI(creature) { } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_BANDAGING_QUEST) return; static constexpr Position MithranCloneSpawnPosition = { -428.576f, -2593.93f, 0.152832f, 4.849576f }; if (Player* player = caster->ToPlayer()) { player->KilledMonsterCredit(me->GetEntry()); if (Creature* survivor = FindCreatureIgnorePhase(player, "mithran_beach", 50.0f)) survivor->SummonPersonalClone(MithranCloneSpawnPosition, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } } }; // 166796 - Lana Jordan struct npc_lana_jordan_beach_laying : public ScriptedAI { npc_lana_jordan_beach_laying(Creature* creature) : ScriptedAI(creature) { } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_BANDAGING_QUEST) return; static constexpr Position LanaCloneSpawnPosition = { -420.656f, -2600.28f, 0.556646f, 4.046853f }; if (Player* player = caster->ToPlayer()) { player->KilledMonsterCredit(me->GetEntry()); if (Creature* survivor = FindCreatureIgnorePhase(player, "lana_jordan_beach", 50.0f)) survivor->SummonPersonalClone(LanaCloneSpawnPosition, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); } } }; // 150228 - Murloc Spearhunter // 150229 - Murloc Watershaper struct npc_murloc_spearhunter_watershaper_higher_ground : public ScriptedAI { using ScriptedAI::ScriptedAI; void JustEngagedWith(Unit* who) override { me->GetMotionMaster()->MoveJump(who->GetPosition(), 16.0f, 6.2f); } }; // 166787 - Bo // 166792 - Mithdran Dawntracker // 166797 - Lana Jordan template struct npc_horde_survivors_beach_q59930_private : public ScriptedAI { npc_horde_survivors_beach_q59930_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->SetStandState(UNIT_STAND_STATE_SLEEP); } void JustAppeared() override { _events.ScheduleEvent(EVENT_SURVIVORS_HORDE_STAND_AND_TALK, 1s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SURVIVORS_HORDE_STAND_AND_TALK: Talk(TALK_HORDE_BEACH_THANK_PLAYER); me->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_SURVIVORS_HORDE_MOVE_TO_GRIMAXE, 6s); break; case EVENT_SURVIVORS_HORDE_MOVE_TO_GRIMAXE: me->GetMotionMaster()->MovePath(PathId, false); break; default: break; } } } private: EventMap _events; }; // 151088 - Kee La // 151089 - Bjorn Stouthands // 154170 - Austin Huxworth // 166787 - Bo // 166792 - Mithdran Dawntracker // 166797 - Lana Jordan template struct npc_survivors_beach_leave_private : public ScriptedAI { npc_survivors_beach_leave_private(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { _events.ScheduleEvent(EVENT_SURVIVORS_SALUTE, 6s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_SURVIVORS_SALUTE: me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); _events.ScheduleEvent(EVENT_SURVIVORS_LEAVE_BEACH, 2s); break; case EVENT_SURVIVORS_LEAVE_BEACH: me->GetMotionMaster()->MovePath(PathId, false); me->DespawnOrUnsummon(Milliseconds(WaitTime)); break; default: break; } } } private: EventMap _events; }; CreatureAI* BoBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if ((privateObjectOwner->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_HORDE) == QUEST_STATUS_NONE)) return new npc_horde_survivors_beach_q59930_private(creature); else return new npc_survivors_beach_leave_private(creature); } } return new NullCreatureAI(creature); }; CreatureAI* MithdranBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if ((privateObjectOwner->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_HORDE) == QUEST_STATUS_NONE)) return new npc_horde_survivors_beach_q59930_private(creature); else return new npc_survivors_beach_leave_private(creature); } } return new NullCreatureAI(creature); }; CreatureAI* LanaJordanBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if ((privateObjectOwner->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_HORDE) == QUEST_STATUS_NONE)) return new npc_horde_survivors_beach_q59930_private(creature); else return new npc_survivors_beach_leave_private(creature); } } return new NullCreatureAI(creature); }; CreatureAI* KeeLaBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_survivors_beach_leave_private(creature); return new NullCreatureAI(creature); }; CreatureAI* BjornBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_survivors_beach_leave_private(creature); return new NullCreatureAI(creature); }; CreatureAI* AustinBeachStandingAISelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_survivors_beach_leave_private(creature); return new NullCreatureAI(creature); }; enum LostExpeditionFollowerData { ACTOR_ID_ALLIANCE_SURVIVOR = 69830, ACTOR_ID_HORDE_SURVIVOR = 76283, AREA_ABANDONED_CAMP = 10452, CONVERSATION_LINE_ESCORT_ALLIANCE_SURVIVOR = 12044, CONVERSATION_LINE_ESCORT_HORDE_SURVIVOR = 14437, CONVERSATION_LINE_ESCORT_SURVIVOR_CAMP = 12058, EVENT_INITIAL_SPAWN_CHECK = 1, EVENT_FOLLOW_PLAYER, SPELL_GARRICK_PING = 313664, SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN = 297295, SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN = 325075, POINT_CAMP_POSITION = 0, }; static constexpr Position GarrickAbandonedCampPosition = { -249.059006f, -2492.520020f, 18.0742f }; static constexpr Position GrimaxeAbandonedCampPosition = { -249.20117f, -2492.6191f, 17.964903f }; // 165359 - Captain Garrick // This script is used by Captian Garrick Follower for Finding the Lost Expedition quest struct npc_garrick_summoned_beach : public ScriptedAI { npc_garrick_summoned_beach(Creature* creature) : ScriptedAI(creature), _reachedCamp(false) {} void IsSummonedBy(WorldObject* /*summoner*/) override { _events.ScheduleEvent(EVENT_INITIAL_SPAWN_CHECK, 1s); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_GARRICK_PING) return; if (_reachedCamp) return; _reachedCamp = true; if (Unit* owner = me->GetOwner()) { Conversation* conversation = Conversation::CreateConversation(CONVERSATION_LINE_ESCORT_SURVIVOR_CAMP, owner, *owner, owner->GetGUID(), nullptr, false); conversation->AddActor(ACTOR_ID_ALLIANCE_SURVIVOR, 1, me->GetGUID()); conversation->Start(); me->GetMotionMaster()->Remove(FOLLOW_MOTION_TYPE); me->GetMotionMaster()->MovePoint(POINT_CAMP_POSITION, GarrickAbandonedCampPosition, false); } } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE || uiId != POINT_CAMP_POSITION) return; if (Unit* owner = me->GetOwner()) { owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); owner->RemoveAura(SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_INITIAL_SPAWN_CHECK: { Unit* owner = me->GetOwner(); if (!owner) break; Creature* survivor = FindCreatureIgnorePhase(owner, "spawn_check"); if (!survivor) { if (owner->GetAreaId() != AREA_ABANDONED_CAMP) owner->RemoveAura(SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN); else _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 0s); } else { Conversation* conversation = Conversation::CreateConversation(CONVERSATION_LINE_ESCORT_ALLIANCE_SURVIVOR, owner, *owner, owner->GetGUID(), nullptr, false); conversation->AddActor(ACTOR_ID_ALLIANCE_SURVIVOR, 1, me->GetGUID()); conversation->Start(); _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 2s); } break; } case EVENT_FOLLOW_PLAYER: if (Unit* owner = me->GetOwner()) me->GetMotionMaster()->MoveFollow(owner, 0.0f, float(M_PI / 4.0f)); break; default: break; } } } private: EventMap _events; bool _reachedCamp; }; // 166805 - Warlord Breka Grimaxe // This script is used by Warlord Grimaxe Follower for Finding the Lost Expedition quest struct npc_grimaxe_summoned_beach : public ScriptedAI { npc_grimaxe_summoned_beach(Creature* creature) : ScriptedAI(creature), _reachedCamp(false) {} void IsSummonedBy(WorldObject* /*summoner*/) override { _reachedCamp = false; _events.ScheduleEvent(EVENT_INITIAL_SPAWN_CHECK, 1s); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_GARRICK_PING) return; if (_reachedCamp) return; if (Unit* owner = me->GetOwner()) { if (Conversation* conversation = Conversation::CreateConversation(CONVERSATION_LINE_ESCORT_SURVIVOR_CAMP, owner, *owner, owner->GetGUID(), nullptr, false)) { conversation->AddActor(ACTOR_ID_HORDE_SURVIVOR, 3, me->GetGUID()); conversation->Start(); } me->GetMotionMaster()->Remove(FOLLOW_MOTION_TYPE); me->GetMotionMaster()->MovePoint(POINT_CAMP_POSITION, GrimaxeAbandonedCampPosition, false); } } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE || uiId != POINT_CAMP_POSITION) return; if (Unit* owner = me->GetOwner()) { owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); owner->RemoveAura(SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_INITIAL_SPAWN_CHECK: { Unit* owner = me->GetOwner(); if (!owner) break; Creature* survivor = FindCreatureIgnorePhase(owner, "spawn_check"); if (!survivor) { if (owner->GetAreaId() != AREA_ABANDONED_CAMP) owner->RemoveAura(SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN); else _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 0s); } else { if (Conversation* conversation = Conversation::CreateConversation(CONVERSATION_LINE_ESCORT_HORDE_SURVIVOR, owner, *owner, owner->GetGUID(), nullptr, false)) { conversation->AddActor(ACTOR_ID_HORDE_SURVIVOR, 2, me->GetGUID()); conversation->Start(); } _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 2s); } break; } case EVENT_FOLLOW_PLAYER: if (Unit* owner = me->GetOwner()) me->GetMotionMaster()->MoveFollow(owner, 0.0f, float(M_PI / 4.0f)); break; default: break; } } } private: EventMap _events; bool _reachedCamp; }; // 54952 - Finding the Lost Expedition // 59931 - Finding the Lost Expedition class quest_finding_the_lost_expedition : public QuestScript { public: quest_finding_the_lost_expedition(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, uint32 summonSpellId, std::string_view survivor1StringId, std::string_view survivor2StringId, std::string_view survivor3StringId) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, summonSpellId); if (Creature* survivor1 = FindCreatureIgnorePhase(player, survivor1StringId, 25.0f)) { Creature* survivor1Personal = survivor1->SummonPersonalClone(survivor1->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); survivor1Personal->SetScriptStringId("spawn_check"); } if (Creature* survivor2 = FindCreatureIgnorePhase(player, survivor2StringId, 25.0f)) survivor2->SummonPersonalClone(survivor2->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (Creature* survivor3 = FindCreatureIgnorePhase(player, survivor3StringId, 25.0f)) survivor3->SummonPersonalClone(survivor3->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); break; case QUEST_STATUS_NONE: player->RemoveAura(summonSpellId); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; default: break; } } }; // 54952 - Finding the Lost Expedition class quest_finding_the_lost_expedition_alliance : public quest_finding_the_lost_expedition { public: quest_finding_the_lost_expedition_alliance() : quest_finding_the_lost_expedition("quest_finding_the_lost_expedition_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN, "kee_la_beach", "bjorn_stouthands_beach", "austin_huxworth_beach"); } }; // 59931 - Finding the Lost Expedition class quest_finding_the_lost_expedition_horde : public quest_finding_the_lost_expedition { public: quest_finding_the_lost_expedition_horde() : quest_finding_the_lost_expedition("quest_finding_the_lost_expedition_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN, "bo_beach", "mithran_beach", "lana_jordan_beach"); } }; // 305596 - Summon Admiral Garrick Guardian // 325076 - Summon Warlord Grimaxe class spell_summon_survivor_beach : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Player* caster = GetCaster()->ToPlayer(); if (!caster) return; Creature* survivor = FindCreatureIgnorePhase(caster, caster->GetTeam() == ALLIANCE ? "q54952_garrick" : "q59931_grimaxe", 5.0f); if (!survivor) return; target = survivor; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_survivor_beach::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; // ****************************************************************** // * Scripting in this section occurs after reaching Abandoned Camp * // ****************************************************************** enum CaptainGarrickAbandonedCampData { CONVERSATION_QUEST_COOKING_MEAT_ACCEPT_ALLIANCE = 11696, CONVERSATION_QUEST_COOKING_MEAT_COMPLETE_ALLIANCE = 12863, QUEST_COOKING_MEAT_ALLIANCE = 55174 }; enum WarlordGrimaxeAbandonedCampData { CONVERSATION_QUEST_COOKING_MEAT_ACCEPT_HORDE = 14439, CONVERSATION_QUEST_COOKING_MEAT_COMPLETE_HORDE = 14611, QUEST_COOKING_MEAT_HORDE = 59932 }; template struct npc_captain_abandoned_camp_exiles_reach : public ScriptedAI { npc_captain_abandoned_camp_exiles_reach(Creature* creature) : ScriptedAI(creature) { } void OnQuestAccept(Player* player, Quest const* quest) override { if (quest->GetQuestId() != QuestId) return; Conversation::CreateConversation(ConversationId, player, *player, player->GetGUID()); } }; enum CookingMeatQuestData { ANIMATION_KIT_INJURED = 14432 }; static constexpr Position InjuredNpcPositionAbandonedCamp = { -245.40973f, -2492.0886f, 18.404648f, 2.4754f }; // 55174 - Cooking Meat // 59932 - Cooking Meat class quest_cooking_meat : public QuestScript { public: quest_cooking_meat(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, uint32 completeConversationId, std::string_view injuredStringId) { switch (newStatus) { case QUEST_STATUS_COMPLETE: { Conversation::CreateConversation(completeConversationId, player, *player, player->GetGUID()); break; } case QUEST_STATUS_REWARDED: { Creature* injured = FindCreatureIgnorePhase(player, injuredStringId); if (!injured) break; Creature* injuredTemp = injured->SummonPersonalClone(InjuredNpcPositionAbandonedCamp, TEMPSUMMON_TIMED_DESPAWN, 2s, 0, 0, player); injuredTemp->SetAIAnimKitId(ANIMATION_KIT_INJURED); break; } default: break; } } }; // 55174 - Cooking Meat class quest_cooking_meat_alliance : public quest_cooking_meat { public: quest_cooking_meat_alliance() : quest_cooking_meat("quest_cooking_meat_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, CONVERSATION_QUEST_COOKING_MEAT_COMPLETE_ALLIANCE, "alaria_standing_abandoned_camp"); } }; // 59932 - Cooking Meat class quest_cooking_meat_horde : public quest_cooking_meat { public: quest_cooking_meat_horde() : quest_cooking_meat("quest_cooking_meat_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, CONVERSATION_QUEST_COOKING_MEAT_COMPLETE_HORDE, "wonza_standing_abandoned_camp"); } }; struct areatrigger_find_the_lost_expedition : AreaTriggerAI { areatrigger_find_the_lost_expedition(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player) return; if (player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_ALLIANCE) == QUEST_STATUS_COMPLETE || player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_HORDE) == QUEST_STATUS_INCOMPLETE) player->CastSpell(player, SPELL_GARRICK_PING); } }; struct areatrigger_find_the_lost_expedition_follower : AreaTriggerAI { areatrigger_find_the_lost_expedition_follower(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player) return; if (player->GetTeam() == ALLIANCE) { if (player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_ALLIANCE) != QUEST_STATUS_INCOMPLETE) return; if (player->HasAura(SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN)) return; player->CastSpell(player, SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN); } else { if (player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION_HORDE) != QUEST_STATUS_INCOMPLETE) return; if (player->HasAura(SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN)) return; player->CastSpell(player, SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN); } } }; enum EnhancedCombatTacticsData { SPELL_SUMMON_CAPTAIN_GARRICK_COMBAT = 320211, SPELL_SUMMON_WARLORD_GRIMAXE_COMBAT = 325180 }; // 59254 - Enhanced Combat Tactics (Alliance) // 59339 - Enhanced Combat Tactics (Alliance Monk) // 59933 - Enhanced Combat Tactics (Horde) // 59934 - Enhanced Combat Tactics (Horde Monk) class quest_enhanced_combat_tactics : public QuestScript { public: quest_enhanced_combat_tactics() : QuestScript("quest_enhanced_combat_tactics") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, player->GetTeam() == ALLIANCE ? SPELL_SUMMON_CAPTAIN_GARRICK_COMBAT : SPELL_SUMMON_WARLORD_GRIMAXE_COMBAT); break; case QUEST_STATUS_NONE: player->RemoveAura(player->GetTeam() == ALLIANCE ? SPELL_SUMMON_CAPTAIN_GARRICK_COMBAT : SPELL_SUMMON_WARLORD_GRIMAXE_COMBAT); player->UpdateObjectVisibility(); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; default: break; } } }; // 320175 - Summon Garrick - Combat Training (DNT) // 325181 - Summon Grimaxe - Combat Training (DNT) class spell_summon_combat_trainer : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Player* caster = GetCaster()->ToPlayer(); if (!caster) return; Creature* partner = FindCreatureIgnorePhase(caster, caster->GetTeam() == ALLIANCE ? "garrick_camp" : "grimaxe_camp", 10.0f); if (!partner) return; target = partner; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_combat_trainer::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; enum EnhancedCombatTrainerData { ACTOR_ID_ALLIANCE_ENHANCED_TRAINING = 74771, ACTOR_ID_HORDE_ENHANCED_TRAINING = 76285, CHARGE_CATEGORY_CHARGE_SPELL = 1386, CONVERSATION_PREFIGHT_WALK_ENHANCED = 13710, CONVERSATION_USE_SPELLS_AT_RANGE = 13630, CONVERSATION_READY_COMBAT = 14440, // Warrior CONVERSATION_READY_COMBAT_WARRIOR = 14441, CONVERSATION_CHARGE_ZERO_RES_ENHANCED = 14444, CONVERSATION_SLAM_ENHANCED = 14447, CONVERSATION_CHARGE_ONE_RES_ENHANCED = 14448, CONVERSATION_CHARGE_FINAL_ENHANCED = 14449, CONVERSATION_CHARGE_KICKBACK = 13611, // Paladin CONVERSATION_HOLY_POWER_ONE_PALADIN = 14452, CONVERSATION_CRUSADER_STRIKE_ONE_PALADIN = 14453, CONVERSATION_CRUSADER_STRIKE_TWO_PALADIN = 14454, CONVERSATION_SHIELD_SLAM_ONE_PALADIN = 14455, CONVERSATION_HOLY_POWER_TWO_PALADIN = 14456, CONVERSATION_SHIELD_SLAM_TWO_PALADIN = 14457, CONVERSATION_CRUSADER_STRIKE_THREE_PALADIN = 14458, CONVERSATION_HOLY_POWER_THREE_PALADIN = 14459, // Rogue CONVERSATION_SINISTER_STRIKE_ONE_ROGUE = 14486, CONVERSATION_REGULAR_ATTACKS_ROGUE = 14487, CONVERSATION_THREE_COMBO_POINTS_ROGUE = 14488, CONVERSATION_THREE_COMBO_EVISCERATE_ROGUE = 14489, CONVERSATION_SINISTER_STRIKE_TWO_ROGUE = 14490, CONVERSATION_FOUR_COMBO_POINTS_ROGUE = 14491, CONVERSATION_FOUR_COMBO_EVISCERATE_ROGUE = 14492, CONVERSATION_SINISTER_STRIKE_THREE_ROGUE = 14493, CONVERSATION_FIVE_COMBO_POINTS_ROGUE = 14494, CONVERSATION_FAILED_EVISCERATE_ROGUE = 14495, // Priest CONVERSATION_SHADOW_WORD_PAIN_QUEST_CREDIT_PRIEST = 13892, CONVERSATION_SMITE_PRE_COMBAT_PRIEST = 14460, CONVERSATION_SHADOW_WORD_PAIN_PRE_COMBAT_PRIEST = 14461, CONVERSATION_SHADOW_WORD_PAIN_TOO_SOON_PRIEST = 14462, CONVERSATION_SHADOW_WORD_PAIN_FADING_PRIEST = 14463, // Shaman CONVERSATION_LIGHTNINGBOLT_FIRST_SHAMAN = 13631, CONVERSATION_PRIMAL_STRIKE_FIRST_SHAMAN = 13632, CONVERSATION_PRIMAL_STRIKE_QUEST_CREDIT_SHAMAN = 13633, CONVERSATION_LIGHTNINGBOLT_RANGE_SHAMAN = 14475, // Mage CONVERSATION_FROSTBOLT_MAGE = 13634, CONVERSATION_FIRE_BLAST_QUEST_CREDIT_MAGE = 13635, CONVERSATION_FROSTBOLT_CLOSE_MAGE = 14476, CONVERSATION_FIRE_BLAST_MAGE_NO_CREDIT = 14477, // Warlock CONVERSATION_CORRUPTION_QUEST_CREDIT_WARLOCK = 13895, CONVERSATION_SHADOW_BOLT_PRE_COMBAT_WARLOCK = 14465, CONVERSATION_CORRUPTION_CAST_PRE_COMBAT_WARLOCK = 14466, CONVERSATION_CORRUPTION_CAST_TOO_SOON_WARLOCK = 14467, CONVERSATION_CORRUPTION_IS_FADING_WARLOCK = 14468, // Druid CONVERSATION_MOONFIRE_QUEST_CREDIT_DRUID = 13893, CONVERSATION_WRATH_PRE_COMBAT_DRUID = 14471, CONVERSATION_MOONFIRE_CAST_PRE_COMBAT_DRUID = 14472, CONVERSATION_MOONFIRE_CAST_TOO_SOON_DRUID = 14473, CONVERSATION_MOONFIRE_WEARING_OFF_DRUID = 14474, // All classes EVENT_COMBAT_TRAINING_WALK_AND_TALK = 1, EVENT_COMBAT_TRAINING_FACE_PLAYER, EVENT_COMBAT_RUN_BACK, EVENT_COMBAT_TRAINING_END, EVENT_COMBAT_CHECK_PLAYER, // Rogue EVENT_COMBAT_TRAINING_SINISTER_CHECK_ROGUE, // Priest, Warlock, Druid EVENT_COMBAT_TRAINING_SPELL_FADING, // Shaman EVENT_COMBAT_TRAINING_RESET_SHAMAN, EVENT_COMBAT_TRAINING_AGGRO_CHECK_SHAMAN, // Mage EVENT_COMBAT_TRAINING_RESET_MAGE, EVENT_COMBAT_TRAINING_AGGRO_CHECK_MAGE, NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED = 164577, NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED2 = 164775, //NPC_HORDE_SPARING_PARTNER_ENHANCED = 166916, NPC_INVISBUNNY_CAMP = 167761, PATH_COMBAT_TRAINER_HOME = 10512100, POINT_WALK_POINT_ENHANCED_TRAINING = 1, POINT_RUN_POINT_ENHANCED_TRAINING = 2, POINT_TRAINING_POINT_ENHANCED_TRAINING = 3, QUEST_ENHANCED_COMBAT_TACTICS_ALLIANCE = 59254, QUEST_ENHANCED_COMBAT_TACTICS_ALLIANCE_MONK = 59339, QUEST_ENHANCED_COMBAT_TACTICS_HORDE = 59933, QUEST_ENHANCED_COMBAT_TACTICS_HORDE_MONK = 59934, QUEST_OBJECTIVE_HORDE_ABILITIES_PROVEN = 397255, QUEST_OBJECTIVE_HORDE_TIGER_PALM = 397258, QUEST_OBJECTIVE_HORDE_BLACKOUT_KICK = 397259, QUEST_OBJECTIVE_ALLIANCE_ABILITIES_PROVEN = 396220, QUEST_OBJECTIVE_ALLIANCE_TIGER_PALM = 396353, QUEST_OBJECTIVE_ALLIANCE_BLACKOUT_KICK = 396354, SPELL_DRINK_HEALING_POTION = 320229, SPELL_KNOCKBACK = 320735, SPELL_CHARGE_KNOCKBACK_DRUID = 320767, SPELL_CHARGE = 100, SPELL_SLAM = 1464, SPELL_CHARGE_KNOCKBACK_WARRIOR = 320583, SPELL_SHIELD_OF_THE_RIGHTEOUS = 53600, SPELL_CRUSADER_STRIKE = 35395, SPELL_SINISTER_STRIKE = 1752, SPELL_EVISCERATE = 196819, SPELL_SMITE = 585, SPELL_SHADOW_WORD_PAIN = 589, SPELL_CHARGE_KNOCKBACK = 320605, SPELL_PRIMAL_STRIKE = 73899, SPELL_LIGHTNING_BOLT = 188196, SPELL_FIRE_BLAST = 319836, SPELL_FROSTBOLT = 116, SPELL_CORRUPTION = 172, SPELL_SHADOWBOLT = 686, SPELL_MOONFIRE = 164812, SPELL_WRATH = 5176, SPELL_TIGER_PALM = 100780, SPELL_BLACKOUT_KICK = 100784, SPELL_RANGED_ROOT_DNT = 320608, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR = 320741, SPELL_AGGRO_RADIUS_CHECK_DNT_PRIEST = 320649, SPELL_AGGRO_RADIUS_CHECK_DNT_SHAMAN = 320705, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE = 320741, SPELL_AGGRO_RADIUS_CHECK_DNT_WARLOCK = 320606, SPELL_AGGRO_RADIUS_CHECK_DNT_DRUID = 320766 }; static constexpr Position EnhancedTrainingWalkPosition = { -250.60243f, -2485.2517f, 17.787413f }; static constexpr Position EnhancedTrainingRunPosition = { -231.5225f, -2480.5276f, 19.019197f }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_combat_training : public ScriptedAI { npc_sparring_partner_combat_training(Creature* creature) : ScriptedAI(creature), _questID(0), _summonSpellAuraID(0) { } virtual void OnReadyPointReached() { } virtual void HandleClassEvent(uint32 /*eventId*/) { } void JustAppeared() override { _events.ScheduleEvent(EVENT_COMBAT_TRAINING_WALK_AND_TALK, 2s); } void IsSummonedBy(WorldObject* summonerWO) override { Player* player = summonerWO->GetAffectingPlayer(); if (!player) return; if (player->GetTeam() == ALLIANCE) { _summonSpellAuraID = SPELL_SUMMON_CAPTAIN_GARRICK_COMBAT; if (player->GetClass() == CLASS_MONK) _questID = QUEST_ENHANCED_COMBAT_TACTICS_ALLIANCE_MONK; else _questID = QUEST_ENHANCED_COMBAT_TACTICS_ALLIANCE; } else { _summonSpellAuraID = SPELL_SUMMON_WARLORD_GRIMAXE_COMBAT; if (player->GetClass() == CLASS_MONK) _questID = QUEST_ENHANCED_COMBAT_TACTICS_HORDE_MONK; else _questID = QUEST_ENHANCED_COMBAT_TACTICS_HORDE; } } uint8 GetQuestCredits() { Player* player = me->GetDemonCreatorPlayer(); if (!player) return 0; uint32 objectiveId = 0; switch (_questID) { case QUEST_ENHANCED_COMBAT_TACTICS_ALLIANCE: objectiveId = QUEST_OBJECTIVE_ALLIANCE_ABILITIES_PROVEN; break; case QUEST_ENHANCED_COMBAT_TACTICS_HORDE: objectiveId = QUEST_OBJECTIVE_HORDE_ABILITIES_PROVEN; break; default: break; } return player->GetQuestObjectiveData(_questID, objectiveId); } void EnterEvadeMode(EvadeReason /*why*/) override { if (!me->IsAlive()) return; me->CombatStop(true); EngagementOver(); me->ResetPlayerDamageReq(); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; switch (uiId) { case POINT_WALK_POINT_ENHANCED_TRAINING: me->SetWalk(false); me->GetMotionMaster()->MovePoint(POINT_RUN_POINT_ENHANCED_TRAINING, EnhancedTrainingRunPosition); break; case POINT_RUN_POINT_ENHANCED_TRAINING: { std::list sparpoints; GetCreatureListWithEntryInGrid(sparpoints, me, NPC_INVISBUNNY_CAMP, 100.0f); Trinity::Containers::RandomResize(sparpoints, 1); for (Creature* creature : sparpoints) me->GetMotionMaster()->MovePoint(POINT_TRAINING_POINT_ENHANCED_TRAINING, creature->GetPosition()); break; } case POINT_TRAINING_POINT_ENHANCED_TRAINING: { Unit* owner = me->GetDemonCreator(); if (!owner) break; me->SetFacingToObject(owner); me->SetImmuneToPC(false); me->SetUninteractible(false); _events.ScheduleEvent(EVENT_COMBAT_CHECK_PLAYER, 1s); OnReadyPointReached(); break; } default: break; } } void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { damage = me->GetHealth() - 1; if (me->HealthBelowPctDamaged(20, damage)) me->CastSpell(me, SPELL_DRINK_HEALING_POTION); } void DamageDealt(Unit* target, uint32& damage, DamageEffectType /*damageType*/) override { if (target->GetHealthPct() < 91) damage = 0; } void StartConversationWithPlayer(uint32 conversationId) { if (Player* player = me->GetDemonCreatorPlayer()) { Conversation* conversation = Conversation::CreateConversation(conversationId, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(ACTOR_ID_ALLIANCE_ENHANCED_TRAINING, 0, player->GetTeam() == ALLIANCE ? me->GetGUID() : ObjectGuid::Empty); conversation->AddActor(ACTOR_ID_HORDE_ENHANCED_TRAINING, 1, player->GetTeam() == HORDE ? me->GetGUID() : ObjectGuid::Empty); conversation->Start(); } } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { // Used to check if reached home if (pathId == PATH_COMBAT_TRAINER_HOME) { if (Unit* owner = me->GetDemonCreator()) { owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); owner->RemoveAura(_summonSpellAuraID); } } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_COMBAT_TRAINING_WALK_AND_TALK: // Used by all classes me->SetWalk(true); me->GetMotionMaster()->MovePoint(POINT_WALK_POINT_ENHANCED_TRAINING, EnhancedTrainingWalkPosition); StartConversationWithPlayer(CONVERSATION_PREFIGHT_WALK_ENHANCED); break; case EVENT_COMBAT_TRAINING_FACE_PLAYER: { // Used by all classes if (Unit* owner = me->GetDemonCreator()) me->SetFacingToObject(owner); me->SetImmuneToPC(false); me->SetUninteractible(false); break; } case EVENT_COMBAT_TRAINING_END: // Used by all classes me->SetImmuneToPC(true); me->SetUninteractible(true); me->RemoveAllAuras(); if (Unit* owner = me->GetDemonCreator()) { me->SetFacingToObject(owner); StartConversationWithPlayer(CONVERSATION_CHARGE_FINAL_ENHANCED); _events.ScheduleEvent(EVENT_COMBAT_RUN_BACK, 4s); } break; case EVENT_COMBAT_RUN_BACK: // Used by all classes me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePath(PATH_COMBAT_TRAINER_HOME, false); break; default: HandleClassEvent(eventId); break; } } if (!UpdateVictim()) return; } protected: uint32 _questID; uint32 _summonSpellAuraID; EventMap _events; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_warrior : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_warrior(Creature* creature) : npc_sparring_partner_combat_training(creature), _slamCounter(0), _secondaryCheck(false) { } void ResetWarrior(Player* player) { _slamCounter = 0; me->SetImmuneToPC(true); me->SetUninteractible(true); player->GetSpellHistory()->ResetCharges(CHARGE_CATEGORY_CHARGE_SPELL); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_FACE_PLAYER, 1s); StartConversationWithPlayer(CONVERSATION_CHARGE_KICKBACK); } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT_WARRIOR); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _secondaryCheck = true; } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_CHARGE) { me->RemoveAura(SPELL_RANGED_ROOT_DNT); me->RemoveAura(SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); switch (GetQuestCredits()) { case 1: StartConversationWithPlayer(CONVERSATION_CHARGE_ZERO_RES_ENHANCED); break; case 2: StartConversationWithPlayer(CONVERSATION_CHARGE_ONE_RES_ENHANCED); break; case 3: _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); break; default: break; } } else if (spellInfo->Id == SPELL_SLAM) { ++_slamCounter; if (_slamCounter == 3 && GetQuestCredits()) ResetWarrior(player); if (!_secondaryCheck) return; _secondaryCheck = false; StartConversationWithPlayer(CONVERSATION_SLAM_ENHANCED); } } private: uint8 _slamCounter; bool _secondaryCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_paladin : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_paladin(Creature* creature) : npc_sparring_partner_combat_training(creature), _secondaryCheck(false), _holyPowerCheck(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); _holyPowerCheck = true; _secondaryCheck = true; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_CHECK_PLAYER: { if (_holyPowerCheck) // Used by paladin { if (Unit* owner = me->GetDemonCreator()) { if (owner->GetPower(POWER_HOLY_POWER) >= 3) { switch (GetQuestCredits()) { case 0: StartConversationWithPlayer(CONVERSATION_HOLY_POWER_ONE_PALADIN); break; case 1: StartConversationWithPlayer(CONVERSATION_HOLY_POWER_TWO_PALADIN); break; case 2: StartConversationWithPlayer(CONVERSATION_HOLY_POWER_THREE_PALADIN); break; default: break; } _holyPowerCheck = false; } } } _events.ScheduleEvent(EVENT_COMBAT_CHECK_PLAYER, 500ms); break; } default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_SHIELD_OF_THE_RIGHTEOUS) { player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); switch (GetQuestCredits()) { case 1: StartConversationWithPlayer(CONVERSATION_SHIELD_SLAM_ONE_PALADIN); _secondaryCheck = true; break; case 2: StartConversationWithPlayer(CONVERSATION_SHIELD_SLAM_TWO_PALADIN); _secondaryCheck = true; break; case 3: _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); _events.CancelEvent(EVENT_COMBAT_CHECK_PLAYER); break; default: break; } } else if (spellInfo->Id == SPELL_CRUSADER_STRIKE) { if (_secondaryCheck) { switch (GetQuestCredits()) { case 0: StartConversationWithPlayer(CONVERSATION_CRUSADER_STRIKE_ONE_PALADIN); break; case 1: StartConversationWithPlayer(CONVERSATION_CRUSADER_STRIKE_TWO_PALADIN); break; case 2: StartConversationWithPlayer(CONVERSATION_CRUSADER_STRIKE_THREE_PALADIN); break; default: break; } _secondaryCheck = false; _holyPowerCheck = true; } } } private: bool _secondaryCheck; bool _holyPowerCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_rogue : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_rogue(Creature* creature) : npc_sparring_partner_combat_training(creature), _comboPointsCounter(0), _secondaryCheck(false), _comboPointCheck(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); _comboPointCheck = true; _secondaryCheck = true; } void JustEngagedWith(Unit* /*who*/) override { if (!GetQuestCredits()) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SINISTER_CHECK_ROGUE, 8s, 20s); } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_SINISTER_CHECK_ROGUE: StartConversationWithPlayer(CONVERSATION_REGULAR_ATTACKS_ROGUE); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SINISTER_CHECK_ROGUE, 8s, 20s); break; case EVENT_COMBAT_CHECK_PLAYER: { if (_comboPointCheck) // Used by rogue { if (Unit* owner = me->GetDemonCreator()) _comboPointsCounter = owner->GetPower(POWER_COMBO_POINTS); if (_comboPointsCounter >= (GetQuestCredits() + 3)) { switch (GetQuestCredits()) { case 0: StartConversationWithPlayer(CONVERSATION_THREE_COMBO_POINTS_ROGUE); break; case 1: StartConversationWithPlayer(CONVERSATION_FOUR_COMBO_POINTS_ROGUE); break; case 2: StartConversationWithPlayer(CONVERSATION_FIVE_COMBO_POINTS_ROGUE); break; default: break; } _comboPointCheck = false; } } _events.ScheduleEvent(EVENT_COMBAT_CHECK_PLAYER, 500ms); break; } default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_EVISCERATE) { _comboPointCheck = true; if (_comboPointsCounter >= (GetQuestCredits() + 3)) { player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); switch (GetQuestCredits()) { case 1: StartConversationWithPlayer(CONVERSATION_THREE_COMBO_EVISCERATE_ROGUE); _secondaryCheck = true; break; case 2: StartConversationWithPlayer(CONVERSATION_FOUR_COMBO_EVISCERATE_ROGUE); _secondaryCheck = true; break; case 3: _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); _events.CancelEvent(EVENT_COMBAT_CHECK_PLAYER); break; default: break; } } else { StartConversationWithPlayer(CONVERSATION_FAILED_EVISCERATE_ROGUE); } } else if (spellInfo->Id == SPELL_SINISTER_STRIKE) { if (!GetQuestCredits()) _events.RescheduleEvent(EVENT_COMBAT_TRAINING_SINISTER_CHECK_ROGUE, 8s, 20s); if (_secondaryCheck) { switch (GetQuestCredits()) { case 0: StartConversationWithPlayer(CONVERSATION_SINISTER_STRIKE_ONE_ROGUE); break; case 1: StartConversationWithPlayer(CONVERSATION_SINISTER_STRIKE_TWO_ROGUE); break; case 2: StartConversationWithPlayer(CONVERSATION_SINISTER_STRIKE_THREE_ROGUE); break; default: break; } _secondaryCheck = false; } } } private: uint8 _comboPointsCounter; bool _secondaryCheck; bool _comboPointCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_priest : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_priest(Creature* creature) : npc_sparring_partner_combat_training(creature), _shadowWordPainInPandemicWindow(false), _secondaryCheck(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_PRIEST); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _secondaryCheck = true; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_SPELL_FADING: { Aura* aura = me->GetAura(SPELL_SHADOW_WORD_PAIN); if (!aura) break; if (!_shadowWordPainInPandemicWindow) { int32 pandemicDuration = CalculatePct(aura->GetMaxDuration(), 30.0f); if (aura->GetDuration() <= pandemicDuration) { _shadowWordPainInPandemicWindow = true; StartConversationWithPlayer(CONVERSATION_SHADOW_WORD_PAIN_FADING_PRIEST); } } _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); break; } default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_SHADOW_WORD_PAIN) { if (_events.GetTimeUntilEvent(EVENT_COMBAT_TRAINING_SPELL_FADING) == Milliseconds::max()) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); if (!_shadowWordPainInPandemicWindow) { if (_secondaryCheck) { StartConversationWithPlayer(CONVERSATION_SHADOW_WORD_PAIN_PRE_COMBAT_PRIEST); me->SetImmuneToPC(false); me->SetUninteractible(false); me->RemoveAura(SPELL_RANGED_ROOT_DNT); _secondaryCheck = false; } else StartConversationWithPlayer(CONVERSATION_SHADOW_WORD_PAIN_TOO_SOON_PRIEST); } else { _shadowWordPainInPandemicWindow = false; player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); else StartConversationWithPlayer(CONVERSATION_SHADOW_WORD_PAIN_QUEST_CREDIT_PRIEST); } } else if (spellInfo->Id == SPELL_SMITE) { if (_secondaryCheck) StartConversationWithPlayer(CONVERSATION_SMITE_PRE_COMBAT_PRIEST); } } private: bool _shadowWordPainInPandemicWindow; bool _secondaryCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_shaman : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_shaman(Creature* creature) : npc_sparring_partner_combat_training(creature), _primalStrikeCounter(0), _secondaryCheck(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_SHAMAN); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _secondaryCheck = true; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_RESET_SHAMAN: if (Unit* owner = me->GetDemonCreator()) { me->CastSpell(owner, SPELL_KNOCKBACK); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_AGGRO_CHECK_SHAMAN, 2s); } break; case EVENT_COMBAT_TRAINING_AGGRO_CHECK_SHAMAN: me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_SHAMAN); me->SetImmuneToPC(false); me->SetUninteractible(false); _secondaryCheck = true; break; default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_PRIMAL_STRIKE) { if (!player->IsWithinDist(me, 2.0f)) return; ++_primalStrikeCounter; if (_primalStrikeCounter < 3) { if (_primalStrikeCounter == 1) StartConversationWithPlayer(CONVERSATION_PRIMAL_STRIKE_FIRST_SHAMAN); return; } _primalStrikeCounter = 0; player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) { _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); } else { StartConversationWithPlayer(CONVERSATION_PRIMAL_STRIKE_QUEST_CREDIT_SHAMAN); me->SetImmuneToPC(true); me->SetUninteractible(true); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_RESET_SHAMAN, 3s); } } else if (spellInfo->Id == SPELL_LIGHTNING_BOLT) { me->RemoveAura(SPELL_RANGED_ROOT_DNT); me->RemoveAura(SPELL_AGGRO_RADIUS_CHECK_DNT_SHAMAN); if (_secondaryCheck) { StartConversationWithPlayer(CONVERSATION_LIGHTNINGBOLT_FIRST_SHAMAN); _secondaryCheck = false; } else { if (player->IsWithinDist(me, 2.0f)) StartConversationWithPlayer(CONVERSATION_LIGHTNINGBOLT_RANGE_SHAMAN); } } } private: uint8 _primalStrikeCounter; bool _secondaryCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_mage : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_mage(Creature* creature) : npc_sparring_partner_combat_training(creature), _secondaryCheck(true) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _secondaryCheck = true; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_RESET_MAGE: if (Unit* owner = me->GetDemonCreator()) { me->CastSpell(owner, SPELL_KNOCKBACK); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_AGGRO_CHECK_MAGE, 2s); } break; case EVENT_COMBAT_TRAINING_AGGRO_CHECK_MAGE: me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); me->SetImmuneToPC(false); me->SetUninteractible(false); _secondaryCheck = true; break; default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_FIRE_BLAST) { if (player->IsWithinDist(me, 2.0f)) { player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) { _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); } else { StartConversationWithPlayer(CONVERSATION_FIRE_BLAST_QUEST_CREDIT_MAGE); me->SetImmuneToPC(true); me->SetUninteractible(true); _events.ScheduleEvent(EVENT_COMBAT_TRAINING_RESET_MAGE, 4s); } } else { StartConversationWithPlayer(CONVERSATION_FIRE_BLAST_MAGE_NO_CREDIT); } } else if (spellInfo->Id == SPELL_FROSTBOLT) { me->RemoveAura(SPELL_RANGED_ROOT_DNT); me->RemoveAura(SPELL_AGGRO_RADIUS_CHECK_DNT_WARRIOR_MAGE); if (_secondaryCheck) { StartConversationWithPlayer(CONVERSATION_FROSTBOLT_MAGE); _secondaryCheck = false; } else { if (player->IsWithinDist(me, 2.0f)) StartConversationWithPlayer(CONVERSATION_FROSTBOLT_CLOSE_MAGE); } } } private: bool _secondaryCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_warlock : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_warlock(Creature* creature) : npc_sparring_partner_combat_training(creature), _corruptionInPandemicWindow(false), _secondaryCheck(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_WARLOCK); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _secondaryCheck = true; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_SPELL_FADING: { Aura* aura = me->GetAura(SPELL_CORRUPTION); if (!aura) break; if (!_corruptionInPandemicWindow) { int32 pandemicDuration = CalculatePct(aura->GetMaxDuration(), 30.0f); if (aura->GetDuration() <= pandemicDuration) { _corruptionInPandemicWindow = true; StartConversationWithPlayer(CONVERSATION_CORRUPTION_IS_FADING_WARLOCK); } } _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); break; } default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_CORRUPTION) { if (_events.GetTimeUntilEvent(EVENT_COMBAT_TRAINING_SPELL_FADING) == Milliseconds::max()) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); if (!_corruptionInPandemicWindow) { if (_secondaryCheck) { StartConversationWithPlayer(CONVERSATION_CORRUPTION_CAST_PRE_COMBAT_WARLOCK); me->SetImmuneToPC(false); me->SetUninteractible(false); me->RemoveAura(SPELL_RANGED_ROOT_DNT); _secondaryCheck = false; } else StartConversationWithPlayer(CONVERSATION_CORRUPTION_CAST_TOO_SOON_WARLOCK); } else { _corruptionInPandemicWindow = false; player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); else StartConversationWithPlayer(CONVERSATION_CORRUPTION_QUEST_CREDIT_WARLOCK); } } else if (spellInfo->Id == SPELL_SHADOWBOLT) { if (_secondaryCheck) StartConversationWithPlayer(CONVERSATION_SHADOW_BOLT_PRE_COMBAT_WARLOCK); } } private: bool _corruptionInPandemicWindow; bool _secondaryCheck; }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_monk : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_monk(Creature* creature) : npc_sparring_partner_combat_training(creature) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_TIGER_PALM) player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); else if (spellInfo->Id == SPELL_BLACKOUT_KICK) player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED2); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); } }; // 164577 - Alliance Sparring Partner // 166916 - Horde Sparring Partner struct npc_sparring_partner_enhanced_combat_training_druid : public npc_sparring_partner_combat_training { npc_sparring_partner_enhanced_combat_training_druid(Creature* creature) : npc_sparring_partner_combat_training(creature), _hitByMoonfire(false), _moonfireInPandemicWindow(false) { } void OnReadyPointReached() override { StartConversationWithPlayer(CONVERSATION_READY_COMBAT); me->CastSpell(me, SPELL_AGGRO_RADIUS_CHECK_DNT_DRUID); me->CastSpell(me, SPELL_RANGED_ROOT_DNT); _moonfireInPandemicWindow = false; _hitByMoonfire = false; } void HandleClassEvent(uint32 eventId) override { switch (eventId) { case EVENT_COMBAT_TRAINING_SPELL_FADING: { Aura* aura = me->GetAura(SPELL_MOONFIRE); if (!aura) break; if (!_moonfireInPandemicWindow) { int32 pandemicDuration = CalculatePct(aura->GetMaxDuration(), 30.0f); if (aura->GetDuration() <= pandemicDuration) { _moonfireInPandemicWindow = true; StartConversationWithPlayer(CONVERSATION_MOONFIRE_WEARING_OFF_DRUID); } } _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); break; } default: break; } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { Player* player = caster->ToPlayer(); if (!player) return; if (spellInfo->Id == SPELL_MOONFIRE) { if (_events.GetTimeUntilEvent(EVENT_COMBAT_TRAINING_SPELL_FADING) == Milliseconds::max()) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_SPELL_FADING, 1s); if (!_moonfireInPandemicWindow) { if (!_hitByMoonfire) { StartConversationWithPlayer(CONVERSATION_MOONFIRE_CAST_PRE_COMBAT_DRUID); me->SetImmuneToPC(false); me->SetUninteractible(false); me->RemoveAura(SPELL_RANGED_ROOT_DNT); _hitByMoonfire = true; } else StartConversationWithPlayer(CONVERSATION_MOONFIRE_CAST_TOO_SOON_DRUID); } else { _moonfireInPandemicWindow = false; player->KilledMonsterCredit(NPC_ALLIANCE_SPARRING_PARTNER_ENHANCED); if (player->GetQuestStatus(_questID) == QUEST_STATUS_COMPLETE) _events.ScheduleEvent(EVENT_COMBAT_TRAINING_END, 1s); else StartConversationWithPlayer(CONVERSATION_MOONFIRE_QUEST_CREDIT_DRUID); } } else if (spellInfo->Id == SPELL_WRATH) { if (!_hitByMoonfire) StartConversationWithPlayer(CONVERSATION_WRATH_PRE_COMBAT_DRUID); } } private: bool _hitByMoonfire; bool _moonfireInPandemicWindow; }; CreatureAI* SparringPartnerEnhancedCombatTrainingSelector(Creature* creature) { TempSummon* summon = creature->ToTempSummon(); if (!summon) return new NullCreatureAI(creature); Unit* summoner = summon->GetSummonerUnit(); if (!summoner) return new NullCreatureAI(creature); Player* player = summoner->ToPlayer(); if (!player) return new NullCreatureAI(creature); switch (player->GetClass()) { case CLASS_WARRIOR: return new npc_sparring_partner_enhanced_combat_training_warrior(creature); case CLASS_PALADIN: return new npc_sparring_partner_enhanced_combat_training_paladin(creature); case CLASS_ROGUE: return new npc_sparring_partner_enhanced_combat_training_rogue(creature); case CLASS_PRIEST: return new npc_sparring_partner_enhanced_combat_training_priest(creature); case CLASS_SHAMAN: return new npc_sparring_partner_enhanced_combat_training_shaman(creature); case CLASS_MAGE: return new npc_sparring_partner_enhanced_combat_training_mage(creature); case CLASS_WARLOCK: return new npc_sparring_partner_enhanced_combat_training_warlock(creature); case CLASS_MONK: return new npc_sparring_partner_enhanced_combat_training_monk(creature); case CLASS_DRUID: return new npc_sparring_partner_enhanced_combat_training_druid(creature); default: return new NullCreatureAI(creature); } if (creature->IsPrivateObject()) return new npc_survivors_beach_leave_private(creature); return new NullCreatureAI(creature); }; struct at_aggro_radius_check_enhanced_combat_tactics : AreaTriggerAI { at_aggro_radius_check_enhanced_combat_tactics(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player) return; Unit* caster = at->GetCaster(); if (!caster) { at->RemoveFromWorld(); return; } caster->SetFacingToObject(player); switch (player->GetClass()) { case CLASS_WARRIOR: caster->CastSpell(player, SPELL_CHARGE_KNOCKBACK_WARRIOR); break; case CLASS_PRIEST: case CLASS_SHAMAN: case CLASS_MAGE: case CLASS_WARLOCK: caster->CastSpell(player, SPELL_CHARGE_KNOCKBACK); break; case CLASS_DRUID: caster->CastSpell(player, SPELL_CHARGE_KNOCKBACK_DRUID); break; default: break; } } }; // 320605 - Charge Knockback (DNT) class spell_knockback_charge_enhanced_training : public SpellScript { void HandleLaunch(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); } void HandleEffect(SpellEffIndex effIndex) { Unit* caster = GetCaster(); if (!caster) return; Player* player = GetHitUnit()->ToPlayer(); if (!player) return; Conversation* conversation = Conversation::CreateConversation(GetSpellInfo()->GetEffect(effIndex).MiscValue, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(ACTOR_ID_ALLIANCE_ENHANCED_TRAINING, 0, player->GetTeam() == ALLIANCE ? caster->GetGUID() : ObjectGuid::Empty); conversation->AddActor(ACTOR_ID_HORDE_ENHANCED_TRAINING, 1, player->GetTeam() == ALLIANCE ? ObjectGuid::Empty : caster->GetGUID()); conversation->Start(); } void Register() override { OnEffectLaunchTarget += SpellEffectFn(spell_knockback_charge_enhanced_training::HandleLaunch, EFFECT_1, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); OnEffectHitTarget += SpellEffectFn(spell_knockback_charge_enhanced_training::HandleEffect, EFFECT_1, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); } }; enum NorthboundData { CONVERSATION_QUEST_NORTHBOUND_ACCEPT_ALLIANCE = 12066, CONVERSATION_QUEST_NORTHBOUND_ACCEPT_HORDE = 14499, POINT_LEADER_RUN = 0, ACTOR_ID_0_NORTHBOUND_ACCEPT_ALLIANCE = 71310, ACTOR_ID_1_NORTHBOUND_ACCEPT_ALLIANCE = 71297, ACTOR_ID_0_NORTHBOUND_ACCEPT_HORDE = 79890, ACTOR_ID_1_NORTHBOUND_ACCEPT_HORDE = 79888, ACTOR_ID_0_NORTHBOUND_AREATRIGGER_ALLIANCE = 71317, ACTOR_ID_1_NORTHBOUND_AREATRIGGER_HORDE = 76319, QUEST_NORTHBOND_ALLIANCE = 55173, QUEST_NORTHBOND_HORDE = 59935, SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN_NORTHBOUND = 305660, SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN_NORTHBOUND = 344382, SPELL_LINGER_NORTHBOUND_ALLIANCE = 305665, SPELL_LINGER_NORTHBOUND_HORDE = 344385, }; static constexpr Position GarrickQuillboarBriarpatchPosition = { -142.62154f, -2641.0364f, 48.775497f }; static constexpr Position GrimaxeQuillboarBriarpatchPosition = { -142.56076f, -2640.9915f, 48.755478f }; // 165360 - Alliance Survivor // This script is used by Captian Garrick Follower for Northbound quest struct npc_leader_northbound : public ScriptedAI { npc_leader_northbound(Creature* creature) : ScriptedAI(creature), _conversationId(0), _actorIdOne(0), _actorIdTwo(0), _lingerSpellId(0), _guardianSpellId(0) {} void JustAppeared() override { Player* player = me->GetAffectingPlayer(); if (!player) return; player->UpdateVisibilityForPlayer(); Creature* survivor = FindCreatureIgnorePhase(player, player->GetTeam() == ALLIANCE ? "alaria_standing_abandoned_camp" : "wonza_standing_abandoned_camp", 5.0f); if (!survivor) return; if (player->GetTeam() == ALLIANCE) { _conversationId = CONVERSATION_QUEST_NORTHBOUND_ACCEPT_ALLIANCE; _actorIdOne = ACTOR_ID_0_NORTHBOUND_ACCEPT_ALLIANCE; _actorIdTwo = ACTOR_ID_1_NORTHBOUND_ACCEPT_ALLIANCE; _runToPosition = GarrickQuillboarBriarpatchPosition; _lingerSpellId = SPELL_LINGER_NORTHBOUND_ALLIANCE; _guardianSpellId = SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN_NORTHBOUND; } else { _conversationId = CONVERSATION_QUEST_NORTHBOUND_ACCEPT_HORDE; _actorIdOne = ACTOR_ID_0_NORTHBOUND_ACCEPT_HORDE; _actorIdTwo = ACTOR_ID_1_NORTHBOUND_ACCEPT_HORDE; _runToPosition = GrimaxeQuillboarBriarpatchPosition; _lingerSpellId = SPELL_LINGER_NORTHBOUND_HORDE; _guardianSpellId = SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN_NORTHBOUND; } Conversation* conversation = Conversation::CreateConversation(_conversationId, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(_actorIdOne, 1, me->GetGUID()); conversation->AddActor(_actorIdTwo, 2, survivor->GetGUID()); conversation->Start(); } void IsSummonedBy(WorldObject* /*summoner*/) override { _events.ScheduleEvent(EVENT_FOLLOW_PLAYER, 3s); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id == _lingerSpellId) { me->GetMotionMaster()->Remove(FOLLOW_MOTION_TYPE); me->GetMotionMaster()->MovePoint(POINT_LEADER_RUN, _runToPosition, false); } return; } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiId != POINT_LEADER_RUN) return; me->SetFacingTo(6.0737457275390625); if (Player* player = me->GetAffectingPlayer()) { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->RemoveAura(_guardianSpellId); player->UpdateVisibilityForPlayer(); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_FOLLOW_PLAYER: if (Player* player = me->GetAffectingPlayer()) me->GetMotionMaster()->MoveFollow(player, 0.0f, float(M_PI / 4.0f)); break; default: break; } } } private: EventMap _events; uint32 _conversationId; uint32 _actorIdOne; uint32 _actorIdTwo; Position _runToPosition; uint32 _lingerSpellId; uint32 _guardianSpellId; }; // 55173 - Northbound // 59935 - Northbound class quest_northbound : public QuestScript { public: quest_northbound(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, uint32 summonSpellId) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, summonSpellId); break; case QUEST_STATUS_NONE: player->RemoveAura(summonSpellId); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->UpdateVisibilityForPlayer(); break; default: break; } } }; // 55173 - Northbound class quest_northbound_alliance : public quest_northbound { public: quest_northbound_alliance() : quest_northbound("quest_northbound_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN_NORTHBOUND); } }; // 59935 - Northbound class quest_northbound_horde : public quest_northbound { public: quest_northbound_horde() : quest_northbound("quest_northbound_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN_NORTHBOUND); } }; // 305661 - Summon Admiral Garrick Guardian Summons Alliance Entry: 165360 // 344383 - Summon Admiral Garrick Guardian Summons Horde Entry: 175034 class spell_summon_leader_northbound : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Player* caster = GetCaster()->ToPlayer(); if (!caster) return; Creature* survivor = FindCreatureIgnorePhase(caster, caster->GetTeam() == ALLIANCE ? "garrick_camp" : "grimaxe_camp", 5.0f); if (!survivor) return; target = survivor; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_leader_northbound::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; struct at_northbound_linger : AreaTriggerAI { at_northbound_linger(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player) return; if (player->GetTeam() == ALLIANCE) { if (player->GetQuestStatus(QUEST_NORTHBOND_ALLIANCE) != QUEST_STATUS_COMPLETE) return; if (!player->HasAura(SPELL_SUMMON_ADMIRAL_GARRICK_GUARDIAN_NORTHBOUND)) return; if (player->HasAura(SPELL_LINGER_NORTHBOUND_ALLIANCE)) return; player->CastSpell(player, SPELL_LINGER_NORTHBOUND_ALLIANCE); } else { if (player->GetQuestStatus(QUEST_NORTHBOND_HORDE) != QUEST_STATUS_COMPLETE) return; if (!player->HasAura(SPELL_SUMMON_WARLORD_GRIMAXE_GUARDIAN_NORTHBOUND)) return; if (player->HasAura(SPELL_LINGER_NORTHBOUND_HORDE)) return; player->CastSpell(player, SPELL_LINGER_NORTHBOUND_HORDE); } } }; // @TODO: drop // 305665 - Scene Linger (DNT) // 344385 - Scene Linger (DNT) class spell_scene_linger_northbound: public SpellScript { void HandleLaunch(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); } void HandleEffect(SpellEffIndex effIndex) { Player* player = GetHitUnit()->ToPlayer(); if (!player) return; Creature* scout = FindCreatureIgnorePhase(player, player->GetTeam() == ALLIANCE ? "huxworth_briarpatch" : "dawntracker_briarpatch", 100.0f); if (!scout) return; Conversation* conversation = Conversation::CreateConversation(GetSpellInfo()->GetEffect(effIndex).MiscValue, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(ACTOR_ID_0_NORTHBOUND_AREATRIGGER_ALLIANCE, 0, player->GetTeam() == ALLIANCE ? scout->GetGUID() : ObjectGuid::Empty); conversation->AddActor(ACTOR_ID_1_NORTHBOUND_AREATRIGGER_HORDE, 1, player->GetTeam() == ALLIANCE ? ObjectGuid::Empty : scout->GetGUID()); conversation->Start(); } void Register() override { OnEffectLaunchTarget += SpellEffectFn(spell_scene_linger_northbound::HandleLaunch, EFFECT_2, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); OnEffectHitTarget += SpellEffectFn(spell_scene_linger_northbound::HandleEffect, EFFECT_2, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); } }; // *********************************************************************** // * Scripting in this section occurs after reaching Quilboar Briarpatch * // *********************************************************************** // Taming the Wild Quest enum TamingTheWilds { QUEST_TAMING_THE_WILDS_ALLIANCE = 59342, QUEST_TAMING_THE_WILDS_HORDE = 59937, QUEST_TRACKER_TAMING_THE_WILDS_COMPLETE = 55607, QUEST_OBJECTIVE_TRAINED_ALLIANCE = 84761, QUEST_OBJECTIVE_TRAINED_HORDE = 85021, QUEST_OBJECTIVE_BEAST_TAMED_ALLIANCE = 84759, QUEST_OBJECTIVE_BEAST_TAMED_HORDE = 85023, SPELL_TAME_BEAST = 1515 }; // 59342 - Taming the Wilds // 59937 - Taming the Wilds class quest_taming_the_wilds : public QuestScript { public: quest_taming_the_wilds(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, std::string_view creatureString, uint32 questObjective1, uint32 questObjective2) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: if (Creature* survivor = FindCreatureIgnorePhase(player, creatureString, 5.0f)) survivor->SummonPersonalClone(survivor->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); // Hacks QUEST_OBJECTIVE_CRITERIA_TREE needs research if (player->HasSpell(SPELL_TAME_BEAST)) player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, questObjective1, 1); if (player->GetQuestStatus(QUEST_TRACKER_TAMING_THE_WILDS_COMPLETE) == QUEST_STATUS_REWARDED) player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, questObjective2, 1); break; default: break; } } }; // 59342 - Taming The Wild class quest_taming_the_wilds_alliance : public quest_taming_the_wilds { public: quest_taming_the_wilds_alliance() : quest_taming_the_wilds("quest_taming_the_wilds_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "huxworth_briarpatch", QUEST_OBJECTIVE_TRAINED_ALLIANCE, QUEST_OBJECTIVE_BEAST_TAMED_ALLIANCE); } }; // 59937 - Taming The Wild class quest_taming_the_wilds_horde : public quest_taming_the_wilds { public: quest_taming_the_wilds_horde() : quest_taming_the_wilds("quest_taming_the_wilds_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "dawntracker_briarpatch", QUEST_OBJECTIVE_TRAINED_HORDE, QUEST_OBJECTIVE_BEAST_TAMED_HORDE); } }; enum TamingTheWildsData { CONVERSATION_HORDE_TRAINER = 14613, CONVERSATION_HORDE_ACTOR = 76440, EVENT_ME_TURN_TO_PLAYER = 1, EVENT_ME_END_OF_CAST = 2, SPELL_TUTORIAL_HEALTH_DNT = 316840, SPELL_LEARNING_TAME_BEAST = 320852, SPELL_LEARN_TAME_BEAST = 320840, SPELL_LEARN_CALL_PET = 320842, SPELL_TAME_BEAST_EFFECT = 13481, SAY_PET_TRAINING_ALLIANCE = 0, SAY_FIND_A_BEAST_ALLIANCE = 1, SAY_FIND_A_BEAST_HORDE = 0 }; // 154327 - Austin Huxsworth struct npc_huxsworth_hunter_quest_private : public ScriptedAI { npc_huxsworth_hunter_quest_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP); } void JustAppeared() override { me->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_ME_TURN_TO_PLAYER, 1s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_ME_TURN_TO_PLAYER: if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { me->SetFacingToObject(player); me->SetEmoteState(EMOTE_STATE_TALK); Talk(SAY_PET_TRAINING_ALLIANCE); player->CastSpell(player, SPELL_LEARNING_TAME_BEAST); _events.ScheduleEvent(EVENT_ME_END_OF_CAST, 8s); } break; case EVENT_ME_END_OF_CAST: if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { if (player->GetQuestStatus(QUEST_TRACKER_TAMING_THE_WILDS_COMPLETE) != QUEST_STATUS_REWARDED) player->CastSpell(player, SPELL_TUTORIAL_HEALTH_DNT); if (!player->HasSpell(SPELL_TAME_BEAST)) { player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, QUEST_OBJECTIVE_TRAINED_ALLIANCE, 1); player->CastSpell(player, SPELL_LEARN_TAME_BEAST); player->CastSpell(player, SPELL_LEARN_CALL_PET); } me->SetEmoteState(EMOTE_STATE_NONE); Talk(SAY_FIND_A_BEAST_ALLIANCE); } me->DespawnOrUnsummon(4s); break; default: break; } } } private: EventMap _events; }; enum HuxsworthBriarpatchData { CONVERSATION_BRIARPATCH_ALLIANCE = 12073, CONVERSATION_ACTOR_GARRICK_BRIARPATCH = 71326, CONVERSATION_ACTOR_HUXSWORTH_BRIARPATCH = 71327, EVENT_HUXSWORTH_GARRICK_CONVERSATION = 1, EVENT_HUXSWORTH_GARRICK_RUN_BRIARPATCH = 2, }; static constexpr Position GarrickBriarpatchDespawnPosition = { -112.92383f, -2640.541f, 52.35042f }; static constexpr Position HuxworthBriarpatchDespawnPosition = { -112.61979f, -2645.9775f, 52.22835f }; // 154327 - Austin Huxsworth struct npc_huxsworth_briarpatch_quest_private : public ScriptedAI { npc_huxsworth_briarpatch_quest_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP); } void JustAppeared() override { me->SetStandState(UNIT_STAND_STATE_STAND); if (Creature* garrick = ObjectAccessor::GetCreature(*me, _garrickGUID)) garrick->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_HUXSWORTH_GARRICK_CONVERSATION, 2s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_HUXSWORTH_GARRICK_CONVERSATION: { if (Unit* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { Conversation* conversation = Conversation::CreateConversation(CONVERSATION_BRIARPATCH_ALLIANCE, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(CONVERSATION_ACTOR_GARRICK_BRIARPATCH, 0, _garrickGUID); conversation->AddActor(CONVERSATION_ACTOR_HUXSWORTH_BRIARPATCH, 1, me->GetGUID()); conversation->Start(); _events.ScheduleEvent(EVENT_HUXSWORTH_GARRICK_RUN_BRIARPATCH, 13s); } break; } case EVENT_HUXSWORTH_GARRICK_RUN_BRIARPATCH: if (Creature* garrick = ObjectAccessor::GetCreature(*me, _garrickGUID)) { garrick->GetMotionMaster()->MovePoint(0, GarrickBriarpatchDespawnPosition); garrick->DespawnOrUnsummon(3s); } me->GetMotionMaster()->MovePoint(0, HuxworthBriarpatchDespawnPosition); me->DespawnOrUnsummon(3s); break; default: break; } } } public: void SetGarrickGUID(ObjectGuid garrickGUID) { _garrickGUID = garrickGUID; } private: EventMap _events; ObjectGuid _garrickGUID; }; // 166996 - Mithdran Dawntracker struct npc_dawntracker_hunter_quest_private : public ScriptedAI { npc_dawntracker_hunter_quest_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP); } void JustAppeared() override { me->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_ME_TURN_TO_PLAYER, 1s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_ME_TURN_TO_PLAYER: if (Unit* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { me->SetFacingToObject(player); me->SetEmoteState(EMOTE_STATE_TALK); Conversation* conversation = Conversation::CreateConversation(CONVERSATION_HORDE_TRAINER, player, *player, player->GetGUID(), nullptr, false); if (conversation) { conversation->AddActor(CONVERSATION_HORDE_ACTOR, 0, me->GetGUID()); conversation->Start(); } player->CastSpell(player, SPELL_LEARNING_TAME_BEAST); _events.ScheduleEvent(EVENT_ME_END_OF_CAST, 8s); } break; case EVENT_ME_END_OF_CAST: if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { if (player->GetQuestStatus(QUEST_TRACKER_TAMING_THE_WILDS_COMPLETE) != QUEST_STATUS_REWARDED) player->CastSpell(player, SPELL_TUTORIAL_HEALTH_DNT); if (!player->HasSpell(SPELL_TAME_BEAST)) { player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, QUEST_OBJECTIVE_TRAINED_HORDE, 1); player->CastSpell(player, SPELL_LEARN_TAME_BEAST); player->CastSpell(player, SPELL_LEARN_CALL_PET); } } me->SetEmoteState(EMOTE_STATE_NONE); Talk(SAY_FIND_A_BEAST_HORDE); me->DespawnOrUnsummon(4s); break; default: break; } } } private: EventMap _events; }; enum DawntrackerBriarpatch { CONVERSATION_BRIARPATCH_HORDE = 14513, CONVERSATION_ACTOR_GRIMAXE_BRIARPATCH = 76330, CONVERSATION_ACTOR_DAWNTRACKER_BRIARPATCH = 76331, EVENT_DAWNTRACKER_GRIMAXE_CONVERSATION = 1, EVENT_DAWNTRACKER_GRIMAXE_RUN_BRIARPATCH = 2, }; static constexpr Position GrimaxeBriarpatchDespawnPosition = { -112.92383f, -2640.541f, 52.35042f }; static constexpr Position DawntrackerBriarpatchDespawnPosition = { -112.61979f, -2645.9775f, 52.22835f }; // 166996 - Mithdran Dawntracker struct npc_dawntracker_briarpatch_quest_private : public ScriptedAI { npc_dawntracker_briarpatch_quest_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER | UNIT_NPC_FLAG_GOSSIP); } void JustAppeared() override { me->SetStandState(UNIT_STAND_STATE_STAND); if (Creature* grimaxe = ObjectAccessor::GetCreature(*me, _grimaxeGUID)) grimaxe->SetStandState(UNIT_STAND_STATE_STAND); _events.ScheduleEvent(EVENT_DAWNTRACKER_GRIMAXE_CONVERSATION, 2s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_DAWNTRACKER_GRIMAXE_CONVERSATION: { if (Unit* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { Conversation* conversation = Conversation::CreateConversation(CONVERSATION_BRIARPATCH_HORDE, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(CONVERSATION_ACTOR_GRIMAXE_BRIARPATCH, 0, _grimaxeGUID); conversation->AddActor(CONVERSATION_ACTOR_DAWNTRACKER_BRIARPATCH, 1, me->GetGUID()); conversation->Start(); _events.ScheduleEvent(EVENT_HUXSWORTH_GARRICK_RUN_BRIARPATCH, 13s); } break; } case EVENT_DAWNTRACKER_GRIMAXE_RUN_BRIARPATCH: if (Creature* grimaxe = ObjectAccessor::GetCreature(*me, _grimaxeGUID)) { grimaxe->GetMotionMaster()->MovePoint(0, GrimaxeBriarpatchDespawnPosition ); grimaxe->DespawnOrUnsummon(2s); } me->GetMotionMaster()->MovePoint(0, DawntrackerBriarpatchDespawnPosition); me->DespawnOrUnsummon(2s); break; default: break; } } } public: void SetGrimaxeGUID(ObjectGuid grimaxeGUID) { _grimaxeGUID = grimaxeGUID; } private: EventMap _events; ObjectGuid _grimaxeGUID; }; CreatureAI* HuxsworthBriarpatchSelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_TAMING_THE_WILDS_ALLIANCE) == QUEST_STATUS_INCOMPLETE) return new npc_huxsworth_hunter_quest_private(creature); else return new npc_huxsworth_briarpatch_quest_private(creature); } } return new NullCreatureAI(creature); }; CreatureAI* DawntrackerBriarpatchSelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_TAMING_THE_WILDS_HORDE) == QUEST_STATUS_INCOMPLETE) return new npc_dawntracker_hunter_quest_private(creature); else return new npc_dawntracker_briarpatch_quest_private(creature); } } return new NullCreatureAI(creature); }; // 316840 - Tutorial - Health (DNT) class spell_tutorial_health_dnt_proc_aura : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_TAME_BEAST_EFFECT }); } bool CheckProc(ProcEventInfo& eventInfo) { if (eventInfo.GetSpellInfo() && eventInfo.GetSpellInfo()->Id == SPELL_TAME_BEAST_EFFECT) return true; return false; } void Register() override { DoCheckProc += AuraCheckProcFn(spell_tutorial_health_dnt_proc_aura::CheckProc); } }; // 316841 - Tutorial - Health (DNT) class spell_tutorial_health_dnt : public SpellScript { void HandleScript(SpellEffIndex /*effIndex*/) { // This shouldn't happen until tame beast spell completes if (Player* player = GetCaster()->ToPlayer()) { if (player->GetTeam() == ALLIANCE) player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, QUEST_OBJECTIVE_BEAST_TAMED_ALLIANCE, 1); else player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_CRITERIA_TREE, QUEST_OBJECTIVE_BEAST_TAMED_HORDE, 1); } } void Register() override { OnEffectHit += SpellEffectFn(spell_tutorial_health_dnt::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; enum QuilboarQuest { QUEST_DOWN_WITH_THE_QUILBOAR_ALLIANCE = 55186, QUEST_FORBIDDEN_QUILBOAR_NECROMANY_ALLIANCE = 55184, QUEST_DOWN_WITH_THE_QUILBOAR_HORDE = 59938, QUEST_FORBIDDEN_QUILBOAR_NECROMANY_HORDE = 59939, SPELL_VALIDATED_QUEST_ACCEPT_BRIARPATCH_ALLIANCE = 298984, SPELL_VALIDATED_QUEST_ACCEPT_BRIARPATCH_HORDE = 325309 }; // 55186 - Quest Down with the Quilboar "Alliance" // 55184 - Forbidden Quilboar Necromancy "Alliance" // 59938 - Quest Down with the Quilboar "Horde" // 59939 - Forbidden Quilboar Necromancy "Horde" class quest_briarpatch : public QuestScript { public: quest_briarpatch(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, uint32 questDown, uint32 questForbidden, uint32 spellValidated) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: if (player->GetQuestStatus(questDown) != QUEST_STATUS_NONE && player->GetQuestStatus(questForbidden) != QUEST_STATUS_NONE) { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, spellValidated); } break; case QUEST_STATUS_NONE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; default: break; } } }; // 55186 - Quest Down with the Quilboar "Alliance" // 55184 - Forbidden Quilboar Necromancy "Alliance" class quest_briarpatch_alliance : public quest_briarpatch { public: quest_briarpatch_alliance() : quest_briarpatch("quest_briarpatch_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, QUEST_DOWN_WITH_THE_QUILBOAR_ALLIANCE, QUEST_FORBIDDEN_QUILBOAR_NECROMANY_ALLIANCE, SPELL_VALIDATED_QUEST_ACCEPT_BRIARPATCH_ALLIANCE); } }; // 59938 - Quest Down with the Quilboar "Horde" // 59939 - Forbidden Quilboar Necromancy "Horde" class quest_briarpatch_horde : public quest_briarpatch { public: quest_briarpatch_horde() : quest_briarpatch("quest_briarpatch_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, QUEST_DOWN_WITH_THE_QUILBOAR_HORDE, QUEST_FORBIDDEN_QUILBOAR_NECROMANY_HORDE, SPELL_VALIDATED_QUEST_ACCEPT_BRIARPATCH_HORDE); } }; // 298984 - Validated Quest Accept class spell_validated_quest_accept_briarpatch_alliance : public SpellScript { void HandleScript(SpellEffIndex /*effIndex*/) { if (Player* player = GetCaster()->ToPlayer()) { Creature* huxsworth = FindCreatureIgnorePhase(player, "huxworth_briarpatch", 10.0f); Creature* garrick = FindCreatureIgnorePhase(player, "garrick_briarpatch", 10.0f); if (!huxsworth || !garrick) return; Creature* huxsworthPersonal = huxsworth->SummonPersonalClone(huxsworth->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* garrickPersonal = garrick->SummonPersonalClone(garrick->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!huxsworthPersonal || !garrickPersonal) return; if (npc_huxsworth_briarpatch_quest_private* huxworthAI = CAST_AI(npc_huxsworth_briarpatch_quest_private, huxsworthPersonal->AI())) huxworthAI->SetGarrickGUID(garrickPersonal->GetGUID()); } } void Register() override { OnEffectHit += SpellEffectFn(spell_validated_quest_accept_briarpatch_alliance::HandleScript, EFFECT_0, SPELL_EFFECT_SEND_EVENT); } }; // 325309 - Validated Quest Accept class spell_validated_quest_accept_briarpatch_horde : public SpellScript { void HandleScript(SpellEffIndex /*effIndex*/) { if (Player* player = GetCaster()->ToPlayer()) { Creature* dawntracker = FindCreatureIgnorePhase(player, "dawntracker_briarpatch", 10.0f); Creature* grimaxe = FindCreatureIgnorePhase(player, "grimaxe_briarpatch", 10.0f); if (!dawntracker || !grimaxe) return; Creature* dawntrackerPersonal = dawntracker->SummonPersonalClone(dawntracker->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* grimaxePersonal = grimaxe->SummonPersonalClone(grimaxe->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!dawntrackerPersonal || !grimaxePersonal) return; if (npc_dawntracker_briarpatch_quest_private* dawntrackerAI = CAST_AI(npc_dawntracker_briarpatch_quest_private, dawntrackerPersonal->AI())) dawntrackerAI->SetGrimaxeGUID(grimaxePersonal->GetGUID()); } } void Register() override { OnEffectHit += SpellEffectFn(spell_validated_quest_accept_briarpatch_horde::HandleScript, EFFECT_0, SPELL_EFFECT_SEND_EVENT); } }; enum GeolordData { CONVERSATION_GEOLORD_AGGRO = 13712, CONVERSATION_ACTOR_GEOLORD = 70670, CONVERSATION_ACTOR_LINDIE = 71238, CONVERSATION_ACTOR_CORK = 75976, EVENT_CAST_EARTH_BOLT = 1, EVENT_CAST_UPHEAVAL = 2, NPC_CORK_FIZZLEPOP = 167008, NPC_LINDIE_SPRINGSTOCK = 154301, NPC_INVIS_BUNNY_GEOLORD = 155371, ACTION_FREE_PRISONER = 1, SPELL_NECROTIC_RITUAL_DNT = 305513, SPELL_EARTH_BOLT = 270453, SPELL_UPHEAVAL = 319273, }; static constexpr Position PrisonerPosition = { 16.4271f, -2511.82f, 78.8215f, 5.66398f }; // 151091 - Geolord Grek'og struct npc_geolord_grekog : public ScriptedAI { npc_geolord_grekog(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { uint32 prisonerEntry = NPC_LINDIE_SPRINGSTOCK; if (sWorldStateMgr->GetValue(WS_TEAM_IN_INSTANCE_HORDE, me->GetMap()) == 1) prisonerEntry = NPC_CORK_FIZZLEPOP; Creature* bunny = me->FindNearestCreatureWithOptions(25.0f, { .CreatureId = NPC_INVIS_BUNNY_GEOLORD, .IgnorePhases = true }); if (!bunny) return; if (Creature* prisoner = bunny->SummonCreature(prisonerEntry, PrisonerPosition, TEMPSUMMON_MANUAL_DESPAWN)) _prisonerGUID = prisoner->GetGUID(); } void JustDied(Unit* /*killer*/) override { if (Creature* prisoner = ObjectAccessor::GetCreature(*me, _prisonerGUID)) prisoner->AI()->DoAction(ACTION_FREE_PRISONER); } void JustEngagedWith(Unit* who) override { if (Player* player = who->ToPlayer()) { Conversation::CreateConversation(CONVERSATION_GEOLORD_AGGRO, player, *player, player->GetGUID(), nullptr, true); _events.ScheduleEvent(EVENT_CAST_EARTH_BOLT, 3s, 5s); _events.ScheduleEvent(EVENT_CAST_UPHEAVAL, 10s, 15s); } } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CAST_EARTH_BOLT: { DoCastVictim(SPELL_EARTH_BOLT); _events.ScheduleEvent(EVENT_CAST_EARTH_BOLT, 10s, 12s); break; } case EVENT_CAST_UPHEAVAL: { DoCastSelf(SPELL_UPHEAVAL); _events.ScheduleEvent(EVENT_CAST_UPHEAVAL, 10s, 15s); break; } default: break; } } } private: EventMap _events; ObjectGuid _prisonerGUID; }; enum BriarpatchPrisonerData { EVENT_RUN_TO_PLAINS = 1, SAY_GET_OUT_OF_HERE = 0 }; static constexpr Position BriarpatchPrisonerJumpToPosition = { 19.5174f, -2513.75f, 74.0545f }; static constexpr Position PrisonerBriarpatchDespawnPosition = { 51.005207f, -2485.644f, 78.15223f }; // 167008 - Cork Fizzlepop // 154301 - Lindie Springstock struct npc_briarpatch_prisoner : public ScriptedAI { npc_briarpatch_prisoner(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { me->SetDisableGravity(true); me->SetControlled(true, UNIT_STATE_ROOT); me->CastSpell(me, SPELL_NECROTIC_RITUAL_DNT); } void DoAction(int32 param) override { if (param == ACTION_FREE_PRISONER) { me->RemoveAllAuras(); me->SetDisableGravity(false); me->SetControlled(false, UNIT_STATE_ROOT); me->GetMotionMaster()->MoveJump(BriarpatchPrisonerJumpToPosition, 7.9894905f, 19.29110336303710937f); Talk(SAY_GET_OUT_OF_HERE); _events.ScheduleEvent(EVENT_RUN_TO_PLAINS, 4s); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_RUN_TO_PLAINS: me->GetMotionMaster()->MovePoint(0, PrisonerBriarpatchDespawnPosition); me->DespawnOrUnsummon(5s); break; default: break; } } } private: EventMap _events; }; enum OgreOverseerQuilboarText { SAY_AGGRO = 0, SAY_DEATH = 1, }; enum QuilboarWarriorGeomancerData { EVENT_BRUTAL_STRIKE = 1, EVENT_GEOMANCER_EARTH_BOLT = 1, SPELL_NECROTIC_BURST = 313261, SPELL_QUILBOAR_SLEEP_DNT = 313265, SPELL_BRUTAL_STRIKE = 317383, SPELL_GEOMANCER_EARTH_BOLT = 321188 }; // 150237 - Quilboar Warrior struct npc_quilboar_warrior : public ScriptedAI { npc_quilboar_warrior(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _events.Reset(); } void JustEngagedWith(Unit* who) override { me->RemoveAura(SPELL_QUILBOAR_SLEEP_DNT); if (roll_chance_f(33.33f)) Talk(SAY_AGGRO, who); _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 3s, 5s); } void JustDied(Unit* killer) override { if (roll_chance_f(33.33f)) Talk(SAY_DEATH, killer); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_BRUTAL_STRIKE: DoCastVictim(SPELL_BRUTAL_STRIKE); _events.ScheduleEvent(EVENT_BRUTAL_STRIKE, 8s, 12s); break; default: break; } } } private: EventMap _events; }; // 150238 - Quilboar Geomancer struct npc_quilboar_geomancer : public ScriptedAI { npc_quilboar_geomancer(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _events.Reset(); } void JustEngagedWith(Unit* who) override { me->RemoveAura(SPELL_QUILBOAR_SLEEP_DNT); if (roll_chance_f(33.33f)) Talk(SAY_AGGRO, who); _events.ScheduleEvent(EVENT_GEOMANCER_EARTH_BOLT, 3s, 5s); } void JustDied(Unit* killer) override { if (roll_chance_f(33.33f)) Talk(SAY_DEATH, killer); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_GEOMANCER_EARTH_BOLT: DoCastVictim(SPELL_GEOMANCER_EARTH_BOLT); _events.ScheduleEvent(EVENT_GEOMANCER_EARTH_BOLT, 3s, 10s); break; default: break; } } } private: EventMap _events; }; enum ExilesReachOgreOverseerData { EVENT_OVERSEER_BACKHAND = 1, EVENT_OVERSEER_EARTHSHATTER = 2, SPELL_BACKHAND = 276991, SPELL_EARTHSHATTER = 319292 }; // 156676 - Ogre Overseer struct npc_ogre_overseer : public ScriptedAI { npc_ogre_overseer(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _events.Reset(); } void JustEngagedWith(Unit* who) override { Talk(SAY_AGGRO, who); _events.ScheduleEvent(EVENT_OVERSEER_BACKHAND, 5s); _events.ScheduleEvent(EVENT_OVERSEER_EARTHSHATTER, 10s, 15s); } void JustDied(Unit* killer) override { Talk(SAY_DEATH, killer); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_OVERSEER_BACKHAND: DoCastVictim(SPELL_BACKHAND); _events.ScheduleEvent(EVENT_OVERSEER_BACKHAND, 15s, 20s); break; case EVENT_OVERSEER_EARTHSHATTER: DoCastAOE(SPELL_EARTHSHATTER); _events.ScheduleEvent(EVENT_OVERSEER_EARTHSHATTER, 15s, 20s); break; default: break; } } } private: EventMap _events; }; enum BriarpathPlainsConversations { CONVERSATION_DOWN_WITH_THE_QUILLBOAR_COMPLETE_ALLIANCE = 12076, CONVERSATION_DOWN_WITH_THE_QUILLBOAR_COMPLETE_HORDE = 14514 }; struct at_briarpatch_to_plains : AreaTriggerAI { at_briarpatch_to_plains(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } // @TODO: remove when conversation cooldown is implemented void StartConversation(Player* player, uint32 conversationId) { std::vector objs; Trinity::ObjectEntryAndPrivateOwnerIfExistsCheck check(player->GetGUID(), conversationId); Trinity::ConversationListSearcher searcher(PhasingHandler::GetAlwaysVisiblePhaseShift(), objs, check); Cell::VisitGridObjects(player, searcher, 100.0f); if (objs.empty()) Conversation::CreateConversation(conversationId, player, *player, player->GetGUID(), nullptr); } void OnUnitEnter(Unit* unit) override { Player* player = unit->ToPlayer(); if (!player) return; if (player->GetTeam() == ALLIANCE) { if (player->GetQuestStatus(QUEST_DOWN_WITH_THE_QUILBOAR_ALLIANCE) != QUEST_STATUS_COMPLETE) return; StartConversation(player, CONVERSATION_DOWN_WITH_THE_QUILLBOAR_COMPLETE_ALLIANCE); } else { if (player->GetQuestStatus(QUEST_DOWN_WITH_THE_QUILBOAR_HORDE) != QUEST_STATUS_COMPLETE) return; StartConversation(player, CONVERSATION_DOWN_WITH_THE_QUILLBOAR_COMPLETE_HORDE); } } }; class spell_quilboar_sleep_dnt : public AuraScript { void ApplyEffect(AuraEffect const* /* aurEff */, AuraEffectHandleModes /*mode*/) { if (Creature* target = GetTarget()->ToCreature()) target->SetReactState(REACT_PASSIVE); } void RemoveEffect(AuraEffect const* /* aurEff */, AuraEffectHandleModes /*mode*/) { if (Creature* target = GetTarget()->ToCreature()) { target->SetReactState(REACT_AGGRESSIVE); target->SetStandState(UNIT_STAND_STATE_STAND); } } void Register() override { OnEffectRemove += AuraEffectRemoveFn(spell_quilboar_sleep_dnt::RemoveEffect, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); AfterEffectApply += AuraEffectApplyFn(spell_quilboar_sleep_dnt::ApplyEffect, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // ************************************************************** // * Scripting in this section occurs after reaching The Plains * // ************************************************************** enum LindieSpringStockData { CONVERSATION_RESIZE_COPTER_ALLIANCE = 12078, CONVERSATION_RESIZE_COPTER_HORDE = 14516, CONVERSATION_ACTOR_GOBLIN_ALLIANCE = 71345, CONVERSATION_ACTOR_GOBLIN_HORDE = 76337, CONVERSATION_ACTOR_COPTER = 71344, EVENT_CONVERSATION = 1, EVENT_RESIZE_COPTER_1 = 2, EVENT_RESIZE_COPTER_2 = 3, EVENT_RESIZE_COPTER_3 = 4, EVENT_RESIZE_COPTER_4 = 5, EVENT_RESIZE_COPTER_5 = 6, EVENT_RESIZE_COPTER_6 = 7, NPC_LINDIE_SPRINGSTOCK_PLAINS = 149899, QUEST_THE_SCOUT_O_MATIC_5000 = 55193, QUEST_THE_CHOPPY_BOOSTER_MK5 = 59940, SPELL_RE_SIZING = 313269, SPELL_GROW_ONE = 129310, SPELL_GROW_TWO = 94214, SPELL_GROW_THREE = 111701 }; static constexpr Position MiniChopperJumpPosition = { 107.979f, -2414.13f, 95.6243f }; // 149899 - Lindie Springstock // 167019 - Cork Fizzlepop struct npc_gnome_goblin_plains_make_copter_private : public ScriptedAI { npc_gnome_goblin_plains_make_copter_private(Creature* creature) : ScriptedAI(creature), _conversationId(0), _conversationActorId(0), _timer(0ms) { } void JustAppeared() override { if (me->GetEntry() == NPC_LINDIE_SPRINGSTOCK_PLAINS) { _conversationId = CONVERSATION_RESIZE_COPTER_ALLIANCE; _conversationActorId = CONVERSATION_ACTOR_GOBLIN_ALLIANCE; _timer = 1350ms; } else { _conversationId = CONVERSATION_RESIZE_COPTER_HORDE; _conversationActorId = CONVERSATION_ACTOR_GOBLIN_HORDE; _timer = 750ms; } _events.ScheduleEvent(EVENT_CONVERSATION, 1s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CONVERSATION: { if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetPrivateObjectOwner())) { Conversation* conversation = Conversation::CreateConversation(_conversationId, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(_conversationActorId, 0, me->GetGUID()); conversation->AddActor(CONVERSATION_ACTOR_COPTER, 1, _copterGUID); conversation->Start(); } if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) copter->GetMotionMaster()->MoveJump(MiniChopperJumpPosition, 19.29f, 6.99f); _events.ScheduleEvent(EVENT_RESIZE_COPTER_1, 6s); break; } case EVENT_RESIZE_COPTER_1: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) { me->SetFacingTo(0.488383f); me->CastSpell(copter, SPELL_RE_SIZING); copter->CastSpell(copter, SPELL_GROW_ONE); } _events.ScheduleEvent(EVENT_RESIZE_COPTER_2, 2s); break; } case EVENT_RESIZE_COPTER_2: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) copter->RemoveAura(SPELL_GROW_ONE); _events.ScheduleEvent(EVENT_RESIZE_COPTER_3, _timer); break; } case EVENT_RESIZE_COPTER_3: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) copter->CastSpell(copter, SPELL_GROW_TWO); _events.ScheduleEvent(EVENT_RESIZE_COPTER_4, _timer); break; } case EVENT_RESIZE_COPTER_4: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) copter->RemoveAura(SPELL_GROW_TWO); _events.ScheduleEvent(EVENT_RESIZE_COPTER_5, _timer); break; } case EVENT_RESIZE_COPTER_5: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) copter->CastSpell(copter, SPELL_GROW_THREE); me->CastStop(SPELL_RE_SIZING); me->SetFacingTo(4.50382f); me->DespawnOrUnsummon(27s); _events.ScheduleEvent(EVENT_RESIZE_COPTER_6, _timer); break; } case EVENT_RESIZE_COPTER_6: { if (Creature* copter = ObjectAccessor::GetCreature(*me, _copterGUID)) { copter->RemoveAura(SPELL_GROW_THREE); copter->DespawnOrUnsummon(2s); } break; } default: break; } } } public: void SetCopterGUID(ObjectGuid copterGUID) { _copterGUID = copterGUID; } private: EventMap _events; ObjectGuid _copterGUID; uint32 _conversationId; uint32 _conversationActorId; Milliseconds _timer; }; CreatureAI* LindieSpringstockSelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_THE_SCOUT_O_MATIC_5000) == QUEST_STATUS_INCOMPLETE) return new npc_gnome_goblin_plains_make_copter_private(creature); } } return new NullCreatureAI(creature); }; CreatureAI* CorkFizzlepopSelector(Creature* creature) { if (creature->IsPrivateObject()) { if (Player* privateObjectOwner = ObjectAccessor::GetPlayer(*creature, creature->GetPrivateObjectOwner())) { if (privateObjectOwner->GetQuestStatus(QUEST_THE_CHOPPY_BOOSTER_MK5) == QUEST_STATUS_INCOMPLETE) return new npc_gnome_goblin_plains_make_copter_private(creature); } } return new NullCreatureAI(creature); }; enum CopterRideData { CONVERSATION_RIDE_TO_OGRE_RUINS_ALLIANCE = 12083, CONVERSATION_RIDE_FROM_OGRE_RUINS_ALLIANCE = 12084, CONVERSATION_RIDE_TO_OGRE_RUINS_HORDE = 14517, CONVERSATION_RIDE_FROM_OGRE_RUINS_HORDE = 14520, EVENT_START_SCOUT_OGRE_RUINS = 1, EVENT_RETURN_FROM_OGRE_RUINS = 2, EVENT_TRIGGER_CREW_MOVE = 3, NPC_SCOUT_O_MATIC_5000 = 156518, NPC_CHOPPY_BOOSTER_MK5 = 167027, PATH_COPTER_TO_RUINS = 15652600, PATH_COPTER_FROM_RUINS = 15652601, PATH_WONSA_PLAINS = 16790900, PATH_BO_PLAINS = 16791000, PATH_LANA_PLAINS = 16791100, PATH_JINHAKE_PLAINS = 16791200, PATH_THROG_PLAINS = 16791300, SPELL_SCENE_OGRE_RUINS_ALLIANCE = 321342, SPELL_SCENE_OGRE_RUINS_HORDE = 326626, SPELL_ROPED_DNT = 303067, SPELL_SCOUT_O_MATIC_PING_DNT = 321340, SCOUT_O_MATIC_DESUMMON = 305548 }; // 156526 - Scout-o-Matic 5000 struct npc_scoutomatic_5000 : public ScriptedAI { npc_scoutomatic_5000(Creature* creature) : ScriptedAI(creature) { } void IsSummonedBy(WorldObject* summoner) override { if (Player* player = summoner->ToPlayer()) player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override { if (apply && passenger->IsPlayer()) { me->CastSpell(passenger, SPELL_ROPED_DNT); _events.ScheduleEvent(EVENT_START_SCOUT_OGRE_RUINS, 2s); } } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID()); if (!player) return; if (pathId == PATH_COPTER_TO_RUINS) { player->CastSpell(player, SPELL_SCENE_OGRE_RUINS_ALLIANCE); } else { player->CastSpell(player, SCOUT_O_MATIC_DESUMMON, CastSpellExtraArgs(TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE)); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_SCOUT_O_MATIC_PING_DNT) { if (Player* player = caster->ToPlayer()) player->KilledMonsterCredit(NPC_SCOUT_O_MATIC_5000); _events.ScheduleEvent(EVENT_RETURN_FROM_OGRE_RUINS, 1s); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_START_SCOUT_OGRE_RUINS: { if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID())) { me->SetSpeed(MOVE_WALK, 5.5f); me->GetMotionMaster()->MovePath(PATH_COPTER_TO_RUINS, false); Conversation::CreateConversation(CONVERSATION_RIDE_TO_OGRE_RUINS_ALLIANCE, player, *player, player->GetGUID(), nullptr); } break; } case EVENT_RETURN_FROM_OGRE_RUINS: { if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID())) { me->SetSpeed(MOVE_WALK, 5.0f); me->GetMotionMaster()->MovePath(PATH_COPTER_FROM_RUINS, false); Conversation::CreateConversation(CONVERSATION_RIDE_FROM_OGRE_RUINS_ALLIANCE, player, *player, player->GetGUID(), nullptr); } break; } default: break; } } } private: EventMap _events; }; static constexpr Position HordeCrewPersonalSpawnLocation[] = { { 50.920593f, -2477.466f, 79.444374f, 0.8753076f }, { 60.51328f, -2476.4822f, 81.034775f, 0.9128374f }, { 53.08128f, -2476.5154f, 79.822624f, 0.9394135f }, { 53.281864f, -2480.052f, 79.18003f, 0.78539818f }, { 53.936935f, -2475.588f, 80.24179f, 0.91009599f } }; // 167905 - Choppy Booster Mk. 5 struct npc_choppy_booster_scout : public ScriptedAI { npc_choppy_booster_scout(Creature* creature) : ScriptedAI(creature) { } void IsSummonedBy(WorldObject* summoner) override { if (Player* player = summoner->ToPlayer()) player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override { if (apply && passenger->IsPlayer()) { me->CastSpell(passenger, SPELL_ROPED_DNT); _events.ScheduleEvent(EVENT_START_SCOUT_OGRE_RUINS, 2s); } } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID()); if (!player) return; if (pathId == PATH_COPTER_TO_RUINS) { player->CastSpell(player, SPELL_SCENE_OGRE_RUINS_HORDE); } else { player->CastSpell(player, SCOUT_O_MATIC_DESUMMON, CastSpellExtraArgs(TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE)); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_SCOUT_O_MATIC_PING_DNT) { if (Player* player = caster->ToPlayer()) player->KilledMonsterCredit(NPC_CHOPPY_BOOSTER_MK5); _events.ScheduleEvent(EVENT_RETURN_FROM_OGRE_RUINS, 1s); } return; } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_START_SCOUT_OGRE_RUINS: { if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID())) { me->SetSpeed(MOVE_WALK, 6.0f); me->GetMotionMaster()->MovePath(PATH_COPTER_TO_RUINS, false); Conversation::CreateConversation(CONVERSATION_RIDE_TO_OGRE_RUINS_HORDE, player, *player, player->GetGUID(), nullptr); } break; } case EVENT_RETURN_FROM_OGRE_RUINS: { if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID())) { me->SetSpeed(MOVE_WALK, 4.5f); me->GetMotionMaster()->MovePath(PATH_COPTER_FROM_RUINS, false); Conversation::CreateConversation(CONVERSATION_RIDE_FROM_OGRE_RUINS_HORDE, player, *player, player->GetGUID(), nullptr); _events.ScheduleEvent(EVENT_TRIGGER_CREW_MOVE, 11s); } break; } case EVENT_TRIGGER_CREW_MOVE: if (Player* player = ObjectAccessor::GetPlayer(*me, me->GetOwnerGUID())) { if (Creature* wonsa = FindCreatureIgnorePhase(player, "wonsa_darkmaul_plains")) if (Creature* wonsaClone = wonsa->SummonPersonalClone(HordeCrewPersonalSpawnLocation[0], TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player)) wonsaClone->GetMotionMaster()->MovePath(PATH_WONSA_PLAINS, false); if (Creature* bo = FindCreatureIgnorePhase(player, "bo_darkmaul_plains")) if (Creature* boClone = bo->SummonPersonalClone(HordeCrewPersonalSpawnLocation[1], TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player)) boClone->GetMotionMaster()->MovePath(PATH_BO_PLAINS, false); if (Creature* lana = FindCreatureIgnorePhase(player, "lana_darkmaul_plains")) if (Creature* lanaClone = lana->SummonPersonalClone(HordeCrewPersonalSpawnLocation[2], TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player)) lanaClone->GetMotionMaster()->MovePath(PATH_LANA_PLAINS, false); if (Creature* jinhake = FindCreatureIgnorePhase(player, "jinhake_darkmaul_plains")) if (Creature* jinhakeClone = jinhake->SummonPersonalClone(HordeCrewPersonalSpawnLocation[3], TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player)) jinhakeClone->GetMotionMaster()->MovePath(PATH_JINHAKE_PLAINS, false); if (Creature* throg = FindCreatureIgnorePhase(player, "throg_darkmaul_plains")) if (Creature* throgClone = throg->SummonPersonalClone(HordeCrewPersonalSpawnLocation[4], TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player)) throgClone->GetMotionMaster()->MovePath(PATH_THROG_PLAINS, false); } break; default: break; } } } private: EventMap _events; }; CreatureAI* ChoppyBoosterSelector(Creature* creature) { if (Player* player = ObjectAccessor::GetPlayer(*creature, creature->GetOwnerGUID())) { if (player->GetQuestStatus(QUEST_THE_CHOPPY_BOOSTER_MK5) == QUEST_STATUS_INCOMPLETE) return new npc_choppy_booster_scout(creature); } return new NullCreatureAI(creature); }; // 167909 - Won'sa // 167910 - Bo // 167911 - Lana Jordan // 167912 - Provisoner Jin'hake // 167913 - Grunt Throg struct npc_horde_crew_plains_private : public ScriptedAI { npc_horde_crew_plains_private(Creature* creature) : ScriptedAI(creature) { } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { me->DespawnOrUnsummon(); } }; CreatureAI* HordeCrewPlainsSelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_horde_crew_plains_private(creature); return new NullCreatureAI(creature); }; static constexpr Position CopterCloneSpawnPosition = { 100.583f, -2417.87f, 90.268f, 0.0f }; // Quest 55193 - The Scout-o-Matic 5000 "Alliance" // Quest 59940 - The Choppy Booster Mk. 5 "Horde" class quest_scout_chopper : public QuestScript { public: quest_scout_chopper(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, std::string_view goblinString, std::string_view copterString) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: { Creature* goblin = FindCreatureIgnorePhase(player, goblinString, 10.0f); Creature* copter = FindCreatureIgnorePhase(player, copterString, 10.0f); if (!goblin || !copter) return; Creature* goblinPersonal = goblin->SummonPersonalClone(goblin->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); Creature* copterPersonal = copter->SummonPersonalClone(CopterCloneSpawnPosition, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!goblinPersonal || !copterPersonal) return; copterPersonal->SetObjectScale(0.2f); copterPersonal->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); if (npc_gnome_goblin_plains_make_copter_private* personalAI = CAST_AI(npc_gnome_goblin_plains_make_copter_private, goblinPersonal->AI())) personalAI->SetCopterGUID(copterPersonal->GetGUID()); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; } case QUEST_STATUS_NONE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; default: break; } } }; // 55193 - The Scout-o-Matic 5000 "Alliance" class quest_scout_o_matic_5000 : public quest_scout_chopper { public: quest_scout_o_matic_5000() : quest_scout_chopper("quest_scout_o_matic_5000") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "lindie_springstock_plains", "scout_o_matic"); } }; // 59940 - The Choppy Booster Mk. 5 "Horde" class quest_choppy_booster_mk5 : public quest_scout_chopper { public: quest_choppy_booster_mk5() : quest_scout_chopper("quest_choppy_booster_mk5") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "cork_fizzlepop_plains", "choppy_booster"); } }; // Quest 56034 - Re-sizing the Situation "Alliance" // Quest 59941 - Re-sizing the Situation "Horde" enum ResizingQuestData { ACTOR_LINDIE_RESIZING_QUEST = 71366, ACTOR_CORK_RESIZING_QUEST = 76343, CONVERSATION_RESIZING_QUEST_ACCEPT = 12086, CONVERSATION_RESIZING_REPORT_BACK = 12089, EVENT_RESIZING_FOLLOW_PLAYER = 1, EVENT_RESIZING_RUN_HOME = 2, POINT_HOME_POSITION = 0, SPELL_SUMMON_LINDIE_SPRINGSTOCK_GUARDIAN_Q56034 = 305750, SPELL_SUMMON_CORK_FIZZLEPOP_GUARDIAN_Q59941 = 326634, SPELL_LINDIE_DESUMMON_Q56034 = 305756, SPELL_PING_LINDIE_Q56034_Q59941 = 305754, }; Position ResizingGuardianPosition = { 100.56077f, -2418.0713f, 90.34765f }; // 156749 - Lindie Springstock struct npc_lindie_springstock_q56034 : public ScriptedAI { npc_lindie_springstock_q56034(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { Unit* owner = me->GetOwner(); Player* player = owner->ToPlayer(); if (!player) return; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_RESIZING_QUEST_ACCEPT, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(ACTOR_LINDIE_RESIZING_QUEST, 1, me->GetGUID()); conversation->AddActor(ACTOR_CORK_RESIZING_QUEST, 2, ObjectGuid::Empty); conversation->Start(); _events.ScheduleEvent(EVENT_RESIZING_FOLLOW_PLAYER, 2s); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiId != 0) return; if (Unit* owner = me->GetOwner()) owner->CastSpell(owner, SPELL_LINDIE_DESUMMON_Q56034); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_PING_LINDIE_Q56034_Q59941) return; _events.ScheduleEvent(EVENT_RESIZING_RUN_HOME, 2s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_RESIZING_FOLLOW_PLAYER: { if (Unit* owner = me->GetOwner()) me->GetMotionMaster()->MoveFollow(owner, 0.0f, float(M_PI / 4.0f)); break; } case EVENT_RESIZING_RUN_HOME: { me->GetMotionMaster()->MovePoint(POINT_HOME_POSITION, ResizingGuardianPosition); break; } default: break; } } } private: EventMap _events; }; // 167915 - Cork Fizzlepop struct npc_cork_fizzlepop_q59941 : public ScriptedAI { npc_cork_fizzlepop_q59941(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { Unit* owner = me->GetOwner(); if (!owner) return; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_RESIZING_QUEST_ACCEPT, owner, *owner, owner->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, owner->GetGUID()); conversation->AddActor(ACTOR_LINDIE_RESIZING_QUEST, 1, ObjectGuid::Empty); conversation->AddActor(ACTOR_CORK_RESIZING_QUEST, 2, me->GetGUID()); conversation->Start(); _events.ScheduleEvent(EVENT_RESIZING_FOLLOW_PLAYER, 2s); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiId != 0) return; if (Unit* owner = me->GetOwner()) { owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); owner->RemoveAura(SPELL_SUMMON_CORK_FIZZLEPOP_GUARDIAN_Q59941); } } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id != SPELL_PING_LINDIE_Q56034_Q59941) return; Unit* owner = me->GetOwner(); if (!owner) return; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_RESIZING_REPORT_BACK, owner, *owner, owner->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, owner->GetGUID()); conversation->AddActor(ACTOR_LINDIE_RESIZING_QUEST, 1, ObjectGuid::Empty); conversation->AddActor(ACTOR_CORK_RESIZING_QUEST, 2, me->GetGUID()); conversation->Start(); _events.ScheduleEvent(EVENT_RESIZING_RUN_HOME, 2s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_RESIZING_FOLLOW_PLAYER: { if (Unit* owner = me->GetOwner()) me->GetMotionMaster()->MoveFollow(owner, 0.0f, float(M_PI / 4.0f)); break; } case EVENT_RESIZING_RUN_HOME: { me->GetMotionMaster()->MovePoint(POINT_HOME_POSITION, ResizingGuardianPosition); break; } default: break; } } } private: EventMap _events; }; enum ReSizedBoarData { EVENT_BOAR_GROW = 1, EVENT_BOAR_MOVE = 2, SPELL_GROW_Q56034 = 129310, SOUND_GROW_Q56034 = 157469 }; Position GiantBoarPosition = { 116.146f, -2430.48f, 90.508415f }; // 156736 - Wandering Boar struct npc_re_sized_boar_q56034 : public ScriptedAI { npc_re_sized_boar_q56034(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { _events.ScheduleEvent(EVENT_BOAR_GROW, 1s); } void MovementInform(uint32 uiType, uint32 uiId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiId != POINT_HOME_POSITION) return; me->SetFacingTo(0.785398f); if (Unit* summoner = me->GetDemonCreator()) summoner->CastSpell(summoner, SPELL_UPDATE_PHASE_SHIFT); me->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_BOAR_GROW: me->CastSpell(me, SPELL_GROW_Q56034); me->PlayDirectSound(SOUND_GROW_Q56034); _events.ScheduleEvent(EVENT_BOAR_MOVE, 1s); break; case EVENT_BOAR_MOVE: me->SetWalk(false); me->GetMotionMaster()->MovePoint(POINT_HOME_POSITION, GiantBoarPosition); break; default: break; } } } private: EventMap _events; }; // Spell 305749 - Summon Admiral Garrick Guardian // Spell 326635 - Summon Cork (DNT) class spell_summon_guardian_q56034_q59941 : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Unit* caster = GetCaster(); if (!caster) return; Player* player = caster->ToPlayer(); if (!player) return; Creature* survivor = FindCreatureIgnorePhase(player, player->GetTeam() == ALLIANCE ? "lindie_springstock_plains" : "cork_fizzlepop_plains", 5.0f); if (!survivor) return; target = survivor; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_guardian_q56034_q59941::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; enum ReSizingData { NPC_WANDERING_BOAR = 156716, NPC_LINDIE_SPRINGSTOCK_GUARDIAN = 156749, NPC_CORK_FIZZLEPOP_GUARDIAN = 167915, QUEST_RE_SIZING_THE_SITUATION_ALLIANCE = 56034, QUEST_RE_SIZING_THE_SITUATION_HORDE = 59941, QUEST_OBJECTIVE_RE_SIZING_THE_SITUATION_ALLIANCE = 390101, QUEST_OBJECTIVE_RE_SIZING_THE_SITUATION_HORDE = 397274, SPELL_RESIZER_HIT_ONE_Q56034_Q59941 = 305724, SPELL_RESIZER_HIT_TWO_Q56034_Q59941 = 305721, SPELL_RESIZER_HIT_THREE_Q56034 = 305742, SPELL_RESIZING_Q59941 = 325345, SPELL_RE_SIZER_OVERCHARGED_Q56034 = 325347 }; // 305716 - Re-Sizing class spell_re_sizing_q56034 : public SpellScript { SpellCastResult CheckCast() { if (!GetExplTargetUnit()) return SPELL_FAILED_BAD_TARGETS; Creature* target = GetExplTargetUnit()->ToCreature(); if (!target) return SPELL_FAILED_BAD_TARGETS; if (target->GetEntry() != NPC_WANDERING_BOAR) return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_re_sizing_q56034::CheckCast); } }; // 305716 - Re-Sizing class spell_re_sizing_aura_q56034 : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_RESIZER_HIT_ONE_Q56034_Q59941, SPELL_RESIZER_HIT_TWO_Q56034_Q59941, SPELL_PING_LINDIE_Q56034_Q59941, }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Player* player = Object::ToPlayer(GetCaster()); Creature* creature = Object::ToCreature(GetTarget()); if (!player || !creature) return; switch (player->GetQuestObjectiveData(QUEST_RE_SIZING_THE_SITUATION_ALLIANCE, QUEST_OBJECTIVE_RE_SIZING_THE_SITUATION_ALLIANCE)) { case 0: player->CastSpell(creature, SPELL_RESIZER_HIT_ONE_Q56034_Q59941, true); creature->DespawnOrUnsummon(2s); break; case 1: player->CastSpell(creature, SPELL_RESIZER_HIT_TWO_Q56034_Q59941, true); creature->DespawnOrUnsummon(); break; case 2: player->CastSpell(creature, SPELL_RESIZER_HIT_THREE_Q56034, true); player->CastSpell(player, SPELL_PING_LINDIE_Q56034_Q59941, true); creature->DespawnOrUnsummon(); break; default: break; } } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_re_sizing_aura_q56034::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 305724 - Resizer Hit // 305721 - Resizer Hit class spell_resizer_hit_one_two_q56034_q59941 : public SpellScript { void HandleLaunch(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); } void HandleEffect(SpellEffIndex effIndex) { Player* player = Object::ToPlayer(GetCaster()); if (!player) return; uint32 guardianID = player->GetTeam() == ALLIANCE ? NPC_LINDIE_SPRINGSTOCK_GUARDIAN : NPC_CORK_FIZZLEPOP_GUARDIAN; Creature* guardian = player->FindNearestCreatureWithOptions(10.0f, { .CreatureId = guardianID, .OwnerGuid = player->GetGUID() }); if (!guardian) return; Conversation* conversation = Conversation::CreateConversation(GetSpellInfo()->GetEffect(effIndex).MiscValue, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(ACTOR_LINDIE_RESIZING_QUEST, 1, player->GetTeam() == ALLIANCE ? guardian->GetGUID() : ObjectGuid::Empty); conversation->AddActor(ACTOR_CORK_RESIZING_QUEST, 2, player->GetTeam() == ALLIANCE ? ObjectGuid::Empty : guardian->GetGUID()); conversation->Start(); } void Register() override { OnEffectLaunchTarget += SpellEffectFn(spell_resizer_hit_one_two_q56034_q59941::HandleLaunch, EFFECT_3, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); OnEffectHitTarget += SpellEffectFn(spell_resizer_hit_one_two_q56034_q59941::HandleEffect, EFFECT_3, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); } }; // 305742 - Resizer Hit class spell_resizer_hit_three_q56034 : public SpellScript { void HandleLaunch(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); } void HandleEffect(SpellEffIndex effIndex) { Player* player = Object::ToPlayer(GetCaster()); if (!player) return; uint32 guardianID = player->GetTeam() == ALLIANCE ? NPC_LINDIE_SPRINGSTOCK_GUARDIAN : NPC_CORK_FIZZLEPOP_GUARDIAN; Creature* guardian = player->FindNearestCreatureWithOptions(10.0f, { .CreatureId = guardianID, .OwnerGuid = player->GetGUID() }); if (!guardian) return; Conversation* conversation = Conversation::CreateConversation(GetSpellInfo()->GetEffect(effIndex).MiscValue, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(ACTOR_LINDIE_RESIZING_QUEST, 1, player->GetTeam() == ALLIANCE ? guardian->GetGUID() : ObjectGuid::Empty); conversation->AddActor(ACTOR_CORK_RESIZING_QUEST, 2, player->GetTeam() == ALLIANCE ? ObjectGuid::Empty : guardian->GetGUID()); conversation->Start(); } void Register() override { OnEffectLaunchTarget += SpellEffectFn(spell_resizer_hit_three_q56034::HandleLaunch, EFFECT_4, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); OnEffectHitTarget += SpellEffectFn(spell_resizer_hit_three_q56034::HandleEffect, EFFECT_4, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); } }; // 325346 - Re-Sizing class spell_re_sizing_q59941 : public SpellScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_RESIZING_Q59941, SPELL_RE_SIZER_OVERCHARGED_Q56034, SPELL_PING_LINDIE_Q56034_Q59941, }); } SpellCastResult CheckCast() { if (!GetExplTargetUnit()) return SPELL_FAILED_BAD_TARGETS; Creature* target = GetExplTargetUnit()->ToCreature(); if (!target) return SPELL_FAILED_BAD_TARGETS; if (target->GetEntry() != NPC_WANDERING_BOAR) return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; } void HandleScript(SpellEffIndex /*effIndex*/) { Player* player = Object::ToPlayer(GetCaster()); Creature* creature = Object::ToCreature(GetHitUnit()); if (!player || !creature) return; switch (player->GetQuestObjectiveData(QUEST_RE_SIZING_THE_SITUATION_HORDE, QUEST_OBJECTIVE_RE_SIZING_THE_SITUATION_HORDE)) { case 0: case 1: player->CastSpell(creature, SPELL_RESIZING_Q59941, true); break; case 2: player->CastSpell(creature, SPELL_RE_SIZER_OVERCHARGED_Q56034, true); player->CastSpell(player, SPELL_PING_LINDIE_Q56034_Q59941, true); creature->DespawnOrUnsummon(3s); break; default: break; } } void Register() override { OnCheckCast += SpellCheckCastFn(spell_re_sizing_q59941::CheckCast); OnEffectHitTarget += SpellEffectFn(spell_re_sizing_q59941::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; // 325345 - Re-Sizing class spell_re_sizing_aura_q59941 : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_RESIZER_HIT_ONE_Q56034_Q59941, SPELL_RESIZER_HIT_TWO_Q56034_Q59941 }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Player* player = Object::ToPlayer(GetCaster()); Creature* creature = Object::ToCreature(GetTarget()); if (!player || !creature) return; switch (player->GetQuestObjectiveData(QUEST_RE_SIZING_THE_SITUATION_HORDE, QUEST_OBJECTIVE_RE_SIZING_THE_SITUATION_HORDE)) { case 0: player->CastSpell(creature, SPELL_RESIZER_HIT_ONE_Q56034_Q59941, true); creature->DespawnOrUnsummon(2s); break; case 1: player->CastSpell(creature, SPELL_RESIZER_HIT_TWO_Q56034_Q59941, true); creature->DespawnOrUnsummon(); break; default: break; } } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_re_sizing_aura_q59941::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 325368 - Re-sizer Slaughter (DNT) class spell_re_sizer_slaughter : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_UPDATE_PHASE_SHIFT }); } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { GetTarget()->CastSpell(nullptr, SPELL_UPDATE_PHASE_SHIFT); } void Register() override { AfterEffectApply += AuraEffectRemoveFn(spell_re_sizer_slaughter::OnApply, EFFECT_0, SPELL_AURA_PLAY_SCENE, AURA_EFFECT_HANDLE_REAL); AfterEffectRemove += AuraEffectRemoveFn(spell_re_sizer_slaughter::OnApply, EFFECT_0, SPELL_AURA_PLAY_SCENE, AURA_EFFECT_HANDLE_REAL); } }; // 56034 - Re-sizing the Situation "Alliance" // 59941 - Re-sizing the Situation "Horde" class quest_resizing_the_situation : public QuestScript { public: quest_resizing_the_situation(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, uint32 SummonSpell) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, SummonSpell); break; case QUEST_STATUS_NONE: player->RemoveAura(SummonSpell); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; default: break; } } }; // 56034 - Re-sizing the Situation "Alliance" class quest_resizing_the_situation_alliance : public quest_resizing_the_situation { public: quest_resizing_the_situation_alliance() : quest_resizing_the_situation("quest_resizing_the_situation_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_LINDIE_SPRINGSTOCK_GUARDIAN_Q56034); } }; // 59941 - Re-sizing the Situation "Horde" class quest_resizing_the_situation_horde : public quest_resizing_the_situation { public: quest_resizing_the_situation_horde() : quest_resizing_the_situation("quest_resizing_the_situation_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, SPELL_SUMMON_CORK_FIZZLEPOP_GUARDIAN_Q59941); } }; enum QuestRideBoar { NPC_ALLIANCE_CAPTAIN = 174955, NPC_HENRY_GARRICK_PRISONER = 156799, SPELL_SUMMON_DARKMAUL_PLAINS_QUESTGIVERS_SUMMON = 305779, SPELL_SUMMON_DARKMAUL_PLAINS_QUESTGIVERS_AURA = 305776, SPELL_PING_GARRICK_TORGOK = 316982, SPELL_REUNION_DNT_ALLIANCE = 305893, SPELL_RITUAL_SCENE_OGRE_CITADEL_DNT = 321693, SPELL_RITUAL_SCENE_HRUN_BEAM_DNT = 321692, SPELL_RITUAL_SCENE_HARPY_BEAM_DNT = 321691, SPELL_RITUAL_SCENE_MAIN_BEAM_DNT = 321690 }; static constexpr Position ReDeatherAbandonTeleportPos = { 102.3f, -2422.5f, 90.1f, 0.764454185962677001f }; // 55879 - Ride of the Scientifically Enhanced Boar class quest_ride_of_the_scientifically_enhanced_boar : public QuestScript { public: quest_ride_of_the_scientifically_enhanced_boar() : QuestScript("quest_ride_of_the_scientifically_enhanced_boar") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->CastSpell(player, SPELL_SUMMON_DARKMAUL_PLAINS_QUESTGIVERS_SUMMON); break; case QUEST_STATUS_COMPLETE: player->CombatStop(); player->CastSpell(player, SPELL_PING_GARRICK_TORGOK); break; case QUEST_STATUS_REWARDED: player->CastSpell(player, SPELL_REUNION_DNT_ALLIANCE); player->CastSpell(player, SPELL_RITUAL_SCENE_OGRE_CITADEL_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_HRUN_BEAM_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_HARPY_BEAM_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_MAIN_BEAM_DNT); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; case QUEST_STATUS_NONE: player->RemoveAura(SPELL_RITUAL_SCENE_OGRE_CITADEL_DNT); player->RemoveAura(SPELL_RITUAL_SCENE_HRUN_BEAM_DNT); player->RemoveAura(SPELL_RITUAL_SCENE_HARPY_BEAM_DNT); player->RemoveAura(SPELL_RITUAL_SCENE_MAIN_BEAM_DNT); player->RemoveAura(SPELL_SUMMON_DARKMAUL_PLAINS_QUESTGIVERS_AURA); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->NearTeleportTo(ReDeatherAbandonTeleportPos); break; default: break; } } }; enum SceneOgreRuinsRideBoar { QUEST_RIDE_ENHANCED_BOAR = 55879, QUEST_RIDE_BOAR_OBJECTIVE_TWO = 396499, QUEST_RIDE_BOAR_OBJECTIVE_TWO_MAX = 8, SPELL_ENHANCED_BOAR_TRAMPLE = 305557, SPELL_ENHANCED_BOAR_CHARGE = 321627, SPELL_ENHANCED_BOAR_KILL_CREDIT = 321668, SPELL_ENHANCED_BOAR_PING_VEHICLE = 305559, SPELL_ENHANCED_BOAR_CHARGE_CONVO = 305815, SPELL_ENHANCED_BOAR_KNOCKBACK = 306356, SPELL_ENHANCED_BOAR_KNOCKBACK_HINT = 306357 }; // Script scene for Ride of the Scientifically Enhanced Boar quest class scene_darkmaul_plains_skeleton_army_alliance : public SceneScript { public: scene_darkmaul_plains_skeleton_army_alliance() : SceneScript("scene_darkmaul_plains_skeleton_army_alliance") { } void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override { if (triggerName == "Trampling Time") { player->CastSpell(player, SPELL_ENHANCED_BOAR_TRAMPLE, true); if (Unit* boar = player->GetVehicleBase()) boar->CastSpell(boar, SPELL_ENHANCED_BOAR_CHARGE, true); } else if (triggerName == "Big Kill Credit") { player->CastSpell(player, SPELL_ENHANCED_BOAR_KILL_CREDIT, true); if (player->GetQuestObjectiveData(QUEST_RIDE_ENHANCED_BOAR, QUEST_RIDE_BOAR_OBJECTIVE_TWO) == QUEST_RIDE_BOAR_OBJECTIVE_TWO_MAX) player->CastSpell(player, SPELL_ENHANCED_BOAR_PING_VEHICLE); } else if (triggerName == "Conversation") { player->CastSpell(player, SPELL_ENHANCED_BOAR_CHARGE_CONVO, true); } else if (triggerName == "Knockback") { player->CastSpell(player, SPELL_ENHANCED_BOAR_KNOCKBACK, true); } else if (triggerName == "Hint") { player->CastSpell(player, SPELL_ENHANCED_BOAR_KNOCKBACK_HINT, true); } } }; // Spell 305779 - Summon Darkmaul Plains Questgivers (DNT) class spell_summon_darkmaul_plains_questgivers_q55879 : public SpellScript { // @TODO: drop after TARGET_UNK_142 impl void SelectTarget(WorldObject*& target) { Player* player = Object::ToPlayer(GetCaster()); if (!player) return; Creature* survivor = FindCreatureIgnorePhase(player, "captain_garrick_plains", 5.0f); if (!survivor) return; target = survivor; } void Register() override { OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_summon_darkmaul_plains_questgivers_q55879::SelectTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY_OR_DB); } }; enum SpellRidingGiantBoar { SPELL_RIDING_GIANT_BOAR_305068 = 305068, SPELL_RIDING_GIANT_BOAR_321670 = 321670 }; // 173426 - Riding Giant Boar class spell_riding_giant_boar_q55879 : public AuraScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_RIDING_GIANT_BOAR_305068, SPELL_RIDING_GIANT_BOAR_321670, SPELL_UPDATE_PHASE_SHIFT }); } void OnAuraRemoveHandler(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Player* player = Object::ToPlayer(GetCaster()); if (!player) return; player->RemoveAura(SPELL_RIDING_GIANT_BOAR_305068); player->RemoveAura(SPELL_RIDING_GIANT_BOAR_321670); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_riding_giant_boar_q55879::OnAuraRemoveHandler, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); } }; enum SpellKnockbackHint { ACTOR_ALLIANCE_CAPTAIN = 71372 }; // 305742 - Resizer Hit class spell_knockback_hint_q56034 : public SpellScript { void HandleLaunch(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); } void HandleEffect(SpellEffIndex effIndex) { Player* player = Object::ToPlayer(GetCaster()); if (!player) return; Creature* garrick = player->FindNearestCreatureWithOptions(10.0f, { .CreatureId = NPC_ALLIANCE_CAPTAIN, .OwnerGuid = player->GetGUID() }); if (!garrick) return; Conversation* conversation = Conversation::CreateConversation(GetSpellInfo()->GetEffect(effIndex).MiscValue, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(ACTOR_ALLIANCE_CAPTAIN, 0, garrick->GetGUID()); conversation->Start(); } void Register() override { OnEffectLaunchTarget += SpellEffectFn(spell_knockback_hint_q56034::HandleLaunch, EFFECT_0, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); OnEffectHitTarget += SpellEffectFn(spell_knockback_hint_q56034::HandleEffect, EFFECT_0, SPELL_EFFECT_CREATE_PRIVATE_CONVERSATION); } }; enum CaptainGarrickGiantBoar { ACTION_EXIT_BOAR = 1, ACTOR_HENRY_GARRICK_PRISONER = 78493, CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_ACCEPT = 12090, CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_HENRY = 15615, CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_EXIT = 12092, EVENT_CAPTAIN_GARRICK_RIDE_BOAR = 1, EVENT_CAPTAIN_GARRICK_RIDE_BOAR_CHECK_OWNER = 2, EVENT_CAPTAIN_GARRICK_RIDE_BOAR_TALK_TO_HENRY = 3, EVENT_CAPTAIN_GARRICK_RIDE_BOAR_HENRY_DESPAWN = 4, EVENT_CAPTAIN_GARRICK_RIDE_BOAR_EXIT_BOAR_CONVERSATION = 5, NPC_GIANT_BOAR = 156267, PHASE_SEE_TORGOK = 14663, POINT_HENRY_POSITION = 0, SPELL_PING_GARRICK_TO_RIDE_BOAR = 316984, SPELL_RIDE_VEHICLE_CAPTIAN_BOAR = 63315 }; Position MoveToPrisonerPosition = { 232.16145f, -2292.5347f, 80.91198f }; // 174955 - Captain Garrick struct npc_captain_garrick_q55879 : public ScriptedAI { npc_captain_garrick_q55879(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) return; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_ACCEPT, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(ACTOR_ALLIANCE_CAPTAIN, 1, me->GetGUID()); conversation->Start(); me->SetReactState(REACT_PASSIVE); me->GetMotionMaster()->MoveFollow(player, 0.0f, float(M_PI / 4.0f)); } void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (me->GetHealth() <= damage) damage = me->GetHealth() - 1; } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { switch (spellInfo->Id) { case SPELL_PING_GARRICK_TO_RIDE_BOAR: { Unit* owner = me->GetOwner(); if (!owner) break; PhasingHandler::InheritPhaseShift(me, owner); PhasingHandler::ResetPhaseShift(me); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR, 2s); break; } case SPELL_ENHANCED_BOAR_PING_VEHICLE: { PhasingHandler::AddPhase(me, PHASE_SEE_TORGOK, true); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR_EXIT_BOAR_CONVERSATION, 500ms); break; } case SPELL_PING_GARRICK_TORGOK: { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; Creature* henry = FindCreatureIgnorePhase(me, "henry_garrick_ogre_ruins_prisoner"); if (!henry) break; Creature* henryPersonal = henry->SummonPersonalClone(henry->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!henryPersonal) break; me->SetReactState(REACT_AGGRESSIVE); _henryGUID = henryPersonal->GetGUID(); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR_TALK_TO_HENRY, 1s); break; } default: break; } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CAPTAIN_GARRICK_RIDE_BOAR: { if (Unit* owner = me->GetOwner()) { Creature* boar = owner->FindNearestCreatureWithOptions(10.0f, { .CreatureId = NPC_GIANT_BOAR, .OwnerGuid = owner->GetGUID() }); if (!boar) return; boar->SetControlled(false, UNIT_STATE_ROOT); me->CastSpell(boar, SPELL_RIDE_VEHICLE_CAPTIAN_BOAR); } break; } case EVENT_CAPTAIN_GARRICK_RIDE_BOAR_TALK_TO_HENRY: { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_HENRY, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(ACTOR_ALLIANCE_CAPTAIN, 0, me->GetGUID()); conversation->AddActor(ACTOR_HENRY_GARRICK_PRISONER, 1, _henryGUID); conversation->Start(); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(POINT_HENRY_POSITION, MoveToPrisonerPosition); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR_HENRY_DESPAWN, 18s); break; } case EVENT_CAPTAIN_GARRICK_RIDE_BOAR_HENRY_DESPAWN: { me->DespawnOrUnsummon(); if (Creature* henry = ObjectAccessor::GetCreature(*me, _henryGUID)) henry->DespawnOrUnsummon(); Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; } case EVENT_CAPTAIN_GARRICK_RIDE_BOAR_EXIT_BOAR_CONVERSATION: { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_CAPTAIN_GARRICK_RIDE_BOAR_QUEST_EXIT, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(0, 0, player->GetGUID()); conversation->AddActor(ACTOR_ALLIANCE_CAPTAIN, 1, me->GetGUID()); conversation->Start(); break; } default: break; } } UpdateVictim(); } private: EventMap _events; ObjectGuid _henryGUID; }; enum GiantBoar { EVENT_GIANT_BOAR_SIZE_ONE = 1, EVENT_GIANT_BOAR_SIZE_TWO = 2, EVENT_GIANT_BOAR_SIZE_THREE = 3, EVENT_GIANT_BOAR_SIZE_FOUR = 4, EVENT_GIANT_BOAR_EJECT_PASSENGERS = 5, EVENT_GIANT_BOAR_UNROOT = 6, SOUND_ENLARGE_BOAR = 157516, SOUND_SHRINK_BOAR = 157517, VEHICLE_BOAR_SEAT_ONE = 1 }; // 156267 - Giant Boar struct npc_giant_boar_vehicle_q55879 : public VehicleAI { npc_giant_boar_vehicle_q55879(Creature* creature) : VehicleAI(creature), _endOfScene(false) { me->SetOrientation(0.844224f); } void JustAppeared() override { me->SetSpeed(MOVE_RUN, 14.0f); } void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override { if (apply && passenger->IsPlayer()) { me->SetControlled(true, UNIT_STATE_ROOT); passenger->SetMovedUnit(me); passenger->CastSpell(passenger, SPELL_PING_GARRICK_TO_RIDE_BOAR); // Ping Garrick to ride Boar (DNT) passenger->CastSpell(passenger, SPELL_UPDATE_PHASE_SHIFT); } else if (apply && passenger->IsCreature()) { passenger->ChangeSeat(VEHICLE_BOAR_SEAT_ONE); } } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_ENHANCED_BOAR_PING_VEHICLE) { me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_01); me->SetControlled(true, UNIT_STATE_ROOT); me->CastSpell(me, SPELL_ENHANCED_BOAR_CHARGE); _endOfScene = true; _events.ScheduleEvent(EVENT_GIANT_BOAR_SIZE_ONE, 4s); if (Unit* owner = me->GetOwner()) owner->CastSpell(owner, SPELL_UPDATE_PHASE_SHIFT); } } void UpdateAI(uint32 diff) override { if (!_endOfScene) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_GIANT_BOAR_SIZE_ONE: me->PlayDirectSound(SOUND_ENLARGE_BOAR); me->SetObjectScale(1.2f); _events.ScheduleEvent(EVENT_GIANT_BOAR_SIZE_TWO, 1000ms); break; case EVENT_GIANT_BOAR_SIZE_TWO: me->PlayDirectSound(SOUND_SHRINK_BOAR); me->SetObjectScale(0.7f); _events.ScheduleEvent(EVENT_GIANT_BOAR_SIZE_THREE, 1000ms); break; case EVENT_GIANT_BOAR_SIZE_THREE: me->PlayDirectSound(SOUND_ENLARGE_BOAR); me->SetObjectScale(1.2f); _events.ScheduleEvent(EVENT_GIANT_BOAR_SIZE_FOUR, 500ms); break; case EVENT_GIANT_BOAR_SIZE_FOUR: me->PlayDirectSound(SOUND_SHRINK_BOAR); me->SetObjectScale(0.1f); _events.ScheduleEvent(EVENT_GIANT_BOAR_EJECT_PASSENGERS, 500ms); break; case EVENT_GIANT_BOAR_EJECT_PASSENGERS: me->RemoveAllAuras(); _events.ScheduleEvent(EVENT_GIANT_BOAR_UNROOT, 500ms); break; case EVENT_GIANT_BOAR_UNROOT: me->SetControlled(false, UNIT_STATE_ROOT); break; default: break; } } } private: EventMap _events; bool _endOfScene; }; enum TorgokData { EVENT_CAST_SPIRIT_BOLT = 1, EVENT_CAST_SOUL_GRASP = 2, SPELL_SPIRIT_BOLT = 319294, SPELL_SOUL_GRASP = 319298 }; // 162817 - Torgok struct npc_torgok_q55879 : public ScriptedAI { npc_torgok_q55879(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _events.Reset(); } void JustEngagedWith(Unit* who) override { Talk(SAY_AGGRO, who); _events.ScheduleEvent(EVENT_CAST_SPIRIT_BOLT, 4s); _events.ScheduleEvent(EVENT_CAST_SOUL_GRASP, 14s); } void JustDied(Unit* killer) override { Talk(SAY_DEATH, killer); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CAST_SPIRIT_BOLT: DoCastVictim(SPELL_SPIRIT_BOLT); _events.ScheduleEvent(EVENT_CAST_SPIRIT_BOLT, 6s); break; case EVENT_CAST_SOUL_GRASP: DoCastAOE(SPELL_SOUL_GRASP); _events.ScheduleEvent(EVENT_CAST_SOUL_GRASP, 14s); break; default: break; } } } private: EventMap _events; }; enum PrisonerQuest55879 { PATH_PRISONER_TO_GROUND = 80000230 }; // 156799 - Henry Garrick // 167126 - Shuja Grimaxe struct npc_prisoner_q55879_private : public ScriptedAI { npc_prisoner_q55879_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } void JustAppeared() override { me->RemoveAllAuras(); me->GetMotionMaster()->MovePath(PATH_PRISONER_TO_GROUND, false); } }; CreatureAI* PrisonerQ55879Selector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_prisoner_q55879_private(creature); else return new NullCreatureAI(creature); }; enum TheReDeather { CONVERSATION_ACCEPT_RE_DEATHER_QUEST = 14525, CONVERSATION_RE_DEATHER_EXPLODE = 14526, NPC_HORDE_WARRIOR = 167146, NPC_SHUJA_GRIMAXE_PRISONER = 167126, QUEST_RE_DEATHER = 59942, OBJECTIVE_RE_DEATHER_CADAVERS_KILLED = 397279, RE_DEATHER_CADAVERS_KILLED_MAX = 8, SPELL_REUNION_DNT_HORDE = 326678, SPELL_RE_DEATHER_TEMP_OBJECTIVE_CHECK = 325394, SPELL_RE_DEATHER_ROUGH_LANDING_DNT = 325401, SPELL_RE_DEATHER_SUMMON_GRIMAXE = 325429 }; // 59942 - The Re-Deather class quest_the_re_deather : public QuestScript { public: quest_the_re_deather() : QuestScript("quest_the_re_deather") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); Conversation::CreateConversation(CONVERSATION_ACCEPT_RE_DEATHER_QUEST, player, *player, player->GetGUID(), nullptr); break; case QUEST_STATUS_COMPLETE: player->CombatStop(); player->CastSpell(player, SPELL_PING_GARRICK_TORGOK); break; case QUEST_STATUS_REWARDED: player->CastSpell(player, SPELL_REUNION_DNT_HORDE); player->CastSpell(player, SPELL_RITUAL_SCENE_OGRE_CITADEL_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_HRUN_BEAM_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_HARPY_BEAM_DNT); player->CastSpell(player, SPELL_RITUAL_SCENE_MAIN_BEAM_DNT); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; case QUEST_STATUS_NONE: { player->CastSpell(player, SPELL_RITUAL_SCENE_OGRE_CITADEL_DNT); player->RemoveAura(SPELL_RE_DEATHER_SUMMON_GRIMAXE); player->RemoveAura(SPELL_RITUAL_SCENE_HRUN_BEAM_DNT); player->RemoveAura(SPELL_RITUAL_SCENE_HARPY_BEAM_DNT); player->RemoveAura(SPELL_RITUAL_SCENE_MAIN_BEAM_DNT); player->RemoveAura(SPELL_RE_DEATHER_TEMP_OBJECTIVE_CHECK); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); player->NearTeleportTo(ReDeatherAbandonTeleportPos); break; } default: break; } } }; // 2489 class scene_darkmaul_plains_skeleton_army_horde : public SceneScript { public: scene_darkmaul_plains_skeleton_army_horde() : SceneScript("scene_darkmaul_plains_skeleton_army_horde") { } void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override { if (triggerName == "Big Kill Credit") { player->CastSpell(player, SPELL_ENHANCED_BOAR_KILL_CREDIT, true); if (player->GetQuestObjectiveData(QUEST_RE_DEATHER, OBJECTIVE_RE_DEATHER_CADAVERS_KILLED) == RE_DEATHER_CADAVERS_KILLED_MAX) { player->CastSpell(player, SPELL_ENHANCED_BOAR_PING_VEHICLE); // Ping Vehicle player->CastSpell(player, SPELL_RE_DEATHER_TEMP_OBJECTIVE_CHECK); // Temp Objective Check Conversation::CreateConversation(CONVERSATION_RE_DEATHER_EXPLODE, player, *player, player->GetGUID(), nullptr); } } else if (triggerName == "Conversation") { player->CastSpell(player, SPELL_ENHANCED_BOAR_CHARGE_CONVO, true); // Does nothing but it's blizzlike } else if (triggerName == "Teleport") { player->CastSpell(player, SPELL_RE_DEATHER_ROUGH_LANDING_DNT); } } void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); } }; enum GrimaxeReDeather { ACTOR_SHUJA_GRIMAXE_PRISONER = 76004, ACTOR_WARLORD_GRIMAXE_Q59942 = 76357, ACTOR_SHUJA_GRIMAXE_FREED = 78501, CONVERSATION_WARLORD_GRIMAXE_SPAWN_Q59942 = 14527, CONVERSATION_WARLORD_GRIMAXE_QUEST_COMPLETE_Q59942 = 15618 }; // 167146 - Warlord Grimaxe struct npc_warlord_grimaxe_q59942 : public ScriptedAI { npc_warlord_grimaxe_q59942(Creature* creature) : ScriptedAI(creature) { me->SetUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED); } void JustAppeared() override { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) return; Creature* shuja = FindCreatureIgnorePhase(me, "shuja_grimaxe_ogre_ruins_prisoner"); if (!shuja) return; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_WARLORD_GRIMAXE_SPAWN_Q59942, player, *player, player->GetGUID(), nullptr, false); if (!conversation) return; conversation->AddActor(ACTOR_SHUJA_GRIMAXE_PRISONER, 0, shuja->GetGUID()); conversation->AddActor(ACTOR_WARLORD_GRIMAXE_Q59942, 1, me->GetGUID()); conversation->Start(); me->GetMotionMaster()->MoveFollow(player, 0.0f, float(M_PI / 4.0f)); } void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (me->GetHealth() <= damage) damage = me->GetHealth() - 1; } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override { switch (spellInfo->Id) { case SPELL_PING_GARRICK_TORGOK: { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; Creature* shuja = FindCreatureIgnorePhase(me, "shuja_grimaxe_ogre_ruins_prisoner"); if (!shuja) break; Creature* shujaPersonal = shuja->SummonPersonalClone(shuja->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); if (!shujaPersonal) break; me->SetReactState(REACT_AGGRESSIVE); _shujaGUID = shujaPersonal->GetGUID(); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR_TALK_TO_HENRY, 1s); break; } default: break; } } void OnDespawn() override { if (Creature* shuja = ObjectAccessor::GetCreature(*me, _shujaGUID)) shuja->DespawnOrUnsummon(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_CAPTAIN_GARRICK_RIDE_BOAR_TALK_TO_HENRY: { Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; Conversation* conversation = Conversation::CreateConversation(CONVERSATION_WARLORD_GRIMAXE_QUEST_COMPLETE_Q59942, player, *player, player->GetGUID(), nullptr, false); if (!conversation) break; conversation->AddActor(ACTOR_WARLORD_GRIMAXE_Q59942, 0, me->GetGUID()); conversation->AddActor(ACTOR_SHUJA_GRIMAXE_FREED, 1, _shujaGUID); conversation->Start(); me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MovePoint(POINT_HENRY_POSITION, MoveToPrisonerPosition); _events.ScheduleEvent(EVENT_CAPTAIN_GARRICK_RIDE_BOAR_HENRY_DESPAWN, 22s); break; } case EVENT_CAPTAIN_GARRICK_RIDE_BOAR_HENRY_DESPAWN: { me->DespawnOrUnsummon(); if (Creature* shuja = ObjectAccessor::GetCreature(*me, _shujaGUID)) shuja->DespawnOrUnsummon(); Player* player = Object::ToPlayer(me->GetOwner()); if (!player) break; player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; } default: break; } } UpdateVictim(); } private: EventMap _events; ObjectGuid _shujaGUID; }; // *************************************************************** // * Scripting in this section occurs between Ogre Ruins and Pit * // *************************************************************** enum WestwardBound { NPC_BJORN_STOUTHANDS_PIT_ONE = 156891, NPC_ALARIA_PIT_ONE = 156803, NPC_LANAJORDAN_PIT_ONE = 167225, NPC_WONSA_PIT_ONE = 167226 }; static constexpr Position BjornWestwardBoundRuinsPos = { 192.181f, -2311.44f, 80.6975f, 3.368485450744628906f }; static constexpr Position AlariaWestwardBoundRuinsPos = { 190.953f, -2308.32f, 80.6586f, 2.984513044357299804f }; static constexpr Position LanaWestwardBoundRuinsPos = { 160.486f, -2307.31f, 84.053f, 2.932153224945068359f }; static constexpr Position WonsaWestwardBoundRuinsPos = { 160.431f, -2310.11f, 84.4598f, 3.03687286376953125f }; // 55965 - Quest Westward Bound "Alliance" // 59948 - Quest Westward Bound "Horde" class quest_westward_bound : public QuestScript { public: quest_westward_bound(char const* script) : QuestScript(script) { } void HandleQuestStatusChange(Player* player, QuestStatus newStatus, std::string_view creatureStringOne, std::string_view creatureStringTwo, uint32 questEnderEntry, uint32 questEnderCompanionEntry, Position questGiverPos, Position companionPos) { switch (newStatus) { case QUEST_STATUS_INCOMPLETE: { Creature* questEnder = FindCreatureIgnorePhase(player, creatureStringOne, 125.0f); if (!questEnder) return; Creature* questEnderCompanion = FindCreatureIgnorePhase(player, creatureStringTwo, 125.0f); if (!questEnderCompanion) return; questEnder->SummonPersonalClone(questGiverPos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); questEnderCompanion->SummonPersonalClone(companionPos, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player); player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); break; } case QUEST_STATUS_NONE: { player->CastSpell(player, SPELL_UPDATE_PHASE_SHIFT); if (Creature* questGiver = player->FindNearestCreatureWithOptions(100.0f, { .CreatureId = questEnderEntry, .IgnorePhases = true, .PrivateObjectOwnerGuid = player->GetGUID() })) questGiver->DespawnOrUnsummon(); if (Creature* companion = player->FindNearestCreatureWithOptions(100.0f, { .CreatureId = questEnderCompanionEntry, .IgnorePhases = true, .PrivateObjectOwnerGuid = player->GetGUID() })) companion->DespawnOrUnsummon(); break; } default: break; } } }; // 55965 - Quest Westward Bound "Alliance" class quest_westward_bound_alliance : public quest_westward_bound { public: quest_westward_bound_alliance() : quest_westward_bound("quest_westward_bound_alliance") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "bjorn_stouthands_pit_pre_quest", "alaria_pit_pre_quest", NPC_BJORN_STOUTHANDS_PIT_ONE, NPC_ALARIA_PIT_ONE, BjornWestwardBoundRuinsPos, AlariaWestwardBoundRuinsPos); } }; // 59948 - Quest Westward Bound "Horde" class quest_westward_bound_horde : public quest_westward_bound { public: quest_westward_bound_horde() : quest_westward_bound("quest_westward_bound_horde") { } void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override { HandleQuestStatusChange(player, newStatus, "lana_joran_pit_pre_quest", "wonsa_pit_pre_quest", NPC_LANAJORDAN_PIT_ONE, NPC_WONSA_PIT_ONE, LanaWestwardBoundRuinsPos, WonsaWestwardBoundRuinsPos); } }; enum BjornRunToPit { EVENT_BJORN_RUN_TO_PIT = 1, PATH_BJORN_RUN_TO_PIT = 10518900, SAY_BJORN_RUN_TO_PIT = 0, SAY_BJORN_REACHED_PIT = 1 }; // 156891 - Bjorn Stouthands struct npc_bjorn_stouthands_q55965_private : public ScriptedAI { npc_bjorn_stouthands_q55965_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } void JustAppeared() override { _events.ScheduleEvent(EVENT_BJORN_RUN_TO_PIT, 1s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { Talk(SAY_BJORN_REACHED_PIT); me->DespawnOrUnsummon(4s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_BJORN_RUN_TO_PIT: Talk(SAY_BJORN_RUN_TO_PIT); me->GetMotionMaster()->MovePath(PATH_BJORN_RUN_TO_PIT, false); break; default: break; } } } private: EventMap _events; }; CreatureAI* BjornRuinsSelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_bjorn_stouthands_q55965_private(creature); else return new NullCreatureAI(creature); }; enum LanaRunToPit { EVENT_LANA_SAY_AT_RUINS = 1, EVENT_LANA_RUN_TO_PIT = 2, PATH_LANA_RUN_TO_PIT = 80000570, SAY_LANA_RUN_TO_PIT = 0, SAY_LANA_REACHED_PIT = 1 }; // 167225 - Lana Jordan struct npc_lana_jordan_q59948_private : public ScriptedAI { npc_lana_jordan_q59948_private(Creature* creature) : ScriptedAI(creature) { } void InitializeAI() override { me->RemoveNpcFlag(UNIT_NPC_FLAG_QUESTGIVER); } void JustAppeared() override { _events.ScheduleEvent(EVENT_LANA_SAY_AT_RUINS, 1s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { Talk(SAY_LANA_REACHED_PIT); me->DespawnOrUnsummon(7s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_LANA_SAY_AT_RUINS: Talk(SAY_BJORN_RUN_TO_PIT); _events.ScheduleEvent(EVENT_LANA_RUN_TO_PIT, 5s); break; case EVENT_LANA_RUN_TO_PIT: me->GetMotionMaster()->MovePath(PATH_LANA_RUN_TO_PIT, false); break; default: break; } } } private: EventMap _events; }; CreatureAI* LanaRuinsSelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_lana_jordan_q59948_private(creature); else return new NullCreatureAI(creature); }; enum CompanionRunToPit { EVENT_COMPANION_RUN_TO_PIT = 1, PATH_ALARIA_RUN_TO_PIT = 10518890, PATH_WONSA_RUN_TO_PIT = 80000580 }; // 156891 - Alaria // 167226 - Won'sa template struct npc_companion_q55965_q59948_private : public ScriptedAI { npc_companion_q55965_q59948_private(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { _events.ScheduleEvent(EVENT_COMPANION_RUN_TO_PIT, 1s); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 /*pathId*/) override { me->DespawnOrUnsummon(1s); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_COMPANION_RUN_TO_PIT: me->GetMotionMaster()->MovePath(PitPathId, false); break; default: break; } } } private: EventMap _events; }; CreatureAI* AlariaRuinsSelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_companion_q55965_q59948_private(creature); else return new NullCreatureAI(creature); }; CreatureAI* WansaRuinsSelector(Creature* creature) { if (creature->IsPrivateObject()) return new npc_companion_q55965_q59948_private(creature); else return new NullCreatureAI(creature); }; void AddSC_zone_exiles_reach() { // Ship RegisterSpellScript(spell_attention_exiles_reach_tutorial); new q59926_warming_up(); new q56775_warming_up(); new quest_stand_your_ground(); RegisterCreatureAI(npc_sparring_partner_exiles_reach); RegisterSpellScript(spell_summon_sparring_partner); new FactoryCreatureScript("npc_captain_garrick"); RegisterPrivatePublicCreatureAIPair("npc_warlord_grimaxe_lower_ship", npc_ship_captain_warming_up_private, NullCreatureAI); RegisterPrivatePublicCreatureAIPair("npc_warlord_grimaxe_upper_ship", npc_ship_captain_brace_for_impact_private, NullCreatureAI); RegisterPrivatePublicCreatureAIPair("npc_cole_ship", npc_first_mate_brace_for_impact_private, npc_first_mate_stand_your_ground); RegisterPrivatePublicCreatureAIPair("npc_throg_ship", npc_first_mate_brace_for_impact_private, npc_first_mate_stand_your_ground); RegisterPrivatePublicCreatureAIPair("npc_crew_ship", npc_crew_ship_private, NullCreatureAI); RegisterPrivatePublicCreatureAIPair("npc_pet_ship", npc_pet_ship_private, NullCreatureAI); new quest_brace_for_impact(); new player_exiles_reach_ship_crash(); new scene_alliance_and_horde_ship(); // Beach RegisterSpellScript(spell_knocked_down_exiles_reach_beach); new scene_alliance_and_horde_crash(); RegisterSpellScriptWithArgs(spell_crash_landed_generic, "spell_crash_landed_alliance"); RegisterSpellScriptWithArgs(spell_crash_landed_generic, "spell_crash_landed_horde"); new FactoryCreatureScript("npc_captain_garrick_beach"); new FactoryCreatureScript("npc_warlord_grimaxe_beach"); new FactoryCreatureScript("npc_healed_by_leader_alliance_beach"); new FactoryCreatureScript("npc_healed_by_leader_horde_beach"); new GenericCreatureScript>("npc_bjorn_stouthands_beach_laying"); new GenericCreatureScript>("npc_austin_huxworth_beach_laying"); new GenericCreatureScript>("npc_kee_la_beach_laying"); // Note: alliance survivor do not need a script for Emergency First Aid quest RegisterCreatureAI(npc_bo_beach_laying); RegisterCreatureAI(npc_mithran_dawntracker_beach_laying); RegisterCreatureAI(npc_lana_jordan_beach_laying); RegisterCreatureAI(npc_murloc_spearhunter_watershaper_higher_ground); new FactoryCreatureScript("npc_bo_beach_standing"); new FactoryCreatureScript("npc_mithdran_dawntracker_beach_standing"); new FactoryCreatureScript("npc_lana_jordan_beach_standing"); new FactoryCreatureScript("npc_kee_la_beach_standing"); new FactoryCreatureScript("npc_bjorn_stouthands_beach_standing"); new FactoryCreatureScript("npc_austin_huxworth_beach_standing"); RegisterCreatureAI(npc_garrick_summoned_beach); RegisterCreatureAI(npc_grimaxe_summoned_beach); new quest_finding_the_lost_expedition_alliance(); new quest_finding_the_lost_expedition_horde(); RegisterSpellScript(spell_summon_survivor_beach); // Abandoned Camp new GenericCreatureScript>("npc_captain_garrick_abandoned_camp"); new GenericCreatureScript>("npc_warlord_grimaxe_abandoned_camp"); new quest_cooking_meat_alliance(); new quest_cooking_meat_horde(); RegisterAreaTriggerAI(areatrigger_find_the_lost_expedition); RegisterAreaTriggerAI(areatrigger_find_the_lost_expedition_follower); // Quest Enhanced Combat Tactics new quest_enhanced_combat_tactics(); RegisterSpellScript(spell_summon_combat_trainer); new FactoryCreatureScript("npc_sparring_partner_combat_training"); RegisterAreaTriggerAI(at_aggro_radius_check_enhanced_combat_tactics); RegisterSpellScript(spell_knockback_charge_enhanced_training); // Quest Northbound RegisterCreatureAI(npc_leader_northbound); new quest_northbound_alliance(); new quest_northbound_horde(); RegisterSpellScript(spell_summon_leader_northbound); RegisterAreaTriggerAI(at_northbound_linger); RegisterSpellScript(spell_scene_linger_northbound); // Quest Taming The Wilds new quest_taming_the_wilds_alliance(); new quest_taming_the_wilds_horde(); new FactoryCreatureScript("npc_huxsworth_briarpatch"); new FactoryCreatureScript("npc_dawntracker_briarpatch"); RegisterSpellScript(spell_tutorial_health_dnt_proc_aura); RegisterSpellScript(spell_tutorial_health_dnt); // Briarpatch new quest_briarpatch_alliance(); new quest_briarpatch_horde(); RegisterSpellScript(spell_validated_quest_accept_briarpatch_alliance); RegisterSpellScript(spell_validated_quest_accept_briarpatch_horde); RegisterCreatureAI(npc_geolord_grekog); new GenericCreatureScript("npc_cork_fizzlepop_briarpatch"); new GenericCreatureScript("npc_lindie_springstock_briarpatch"); RegisterCreatureAI(npc_quilboar_warrior); RegisterCreatureAI(npc_quilboar_geomancer); RegisterCreatureAI(npc_ogre_overseer); RegisterAreaTriggerAI(at_briarpatch_to_plains); RegisterSpellScript(spell_quilboar_sleep_dnt); // Plains scouting quest new quest_scout_o_matic_5000(); new quest_choppy_booster_mk5(); new FactoryCreatureScript("npc_lindie_springstock_plains"); new FactoryCreatureScript("npc_cork_fizzlepop_plains"); RegisterCreatureAI(npc_scoutomatic_5000); new FactoryCreatureScript("npc_choppy_booster"); new FactoryCreatureScript("npc_horde_crew_plains"); // Plains Resizing the situation new quest_resizing_the_situation_alliance(); new quest_resizing_the_situation_horde(); RegisterCreatureAI(npc_lindie_springstock_q56034); RegisterCreatureAI(npc_cork_fizzlepop_q59941); RegisterCreatureAI(npc_re_sized_boar_q56034); RegisterSpellScript(spell_summon_guardian_q56034_q59941); RegisterSpellAndAuraScriptPair(spell_re_sizing_q56034, spell_re_sizing_aura_q56034); RegisterSpellScript(spell_resizer_hit_one_two_q56034_q59941); RegisterSpellScript(spell_resizer_hit_three_q56034); RegisterSpellScript(spell_re_sizing_q59941); RegisterSpellScript(spell_re_sizing_aura_q59941); RegisterSpellScript(spell_re_sizer_slaughter); // Ride Boar new quest_ride_of_the_scientifically_enhanced_boar(); new scene_darkmaul_plains_skeleton_army_alliance(); RegisterSpellScript(spell_summon_darkmaul_plains_questgivers_q55879); RegisterSpellScript(spell_riding_giant_boar_q55879); RegisterSpellScript(spell_knockback_hint_q56034); RegisterCreatureAI(npc_captain_garrick_q55879); RegisterCreatureAI(npc_giant_boar_vehicle_q55879); RegisterCreatureAI(npc_torgok_q55879); new FactoryCreatureScript("npc_prisoner_q55879"); // The Re-Deather new quest_the_re_deather(); new scene_darkmaul_plains_skeleton_army_horde(); RegisterCreatureAI(npc_warlord_grimaxe_q59942); // Westward Bound new quest_westward_bound_alliance(); new quest_westward_bound_horde(); new FactoryCreatureScript("npc_bjorn_stouthands_q55965"); new FactoryCreatureScript("npc_lana_jordan_q59948"); new FactoryCreatureScript("npc_alaria_q55965"); new FactoryCreatureScript("npc_wonsa_q59948"); };