diff options
author | Aqua Deus <95978183+aquadeus@users.noreply.github.com> | 2025-02-01 18:58:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-01 18:58:48 +0100 |
commit | fa75f796d5f8a5e8f51a32ea36ee11beb541eb06 (patch) | |
tree | bba94a6b9fa509930fbd4d13737a97e391c05cf5 /src | |
parent | 4db19d3a1aa766ab2e6a5f4916df87a6326210b7 (diff) |
Scripts/Auchindoun: Implement Auchindoun events until first boss (#30034)
Diffstat (limited to 'src')
4 files changed, 555 insertions, 0 deletions
diff --git a/src/server/scripts/Draenor/Auchindoun/auchindoun.cpp b/src/server/scripts/Draenor/Auchindoun/auchindoun.cpp new file mode 100644 index 00000000000..6bbf61e3903 --- /dev/null +++ b/src/server/scripts/Draenor/Auchindoun/auchindoun.cpp @@ -0,0 +1,410 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "AreaTrigger.h" +#include "AreaTriggerAI.h" +#include "GameObject.h" +#include "InstanceScript.h" +#include "Map.h" +#include "MotionMaster.h" +#include "ObjectAccessor.h" +#include "PhasingHandler.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "ScriptMgr.h" +#include "SpellScript.h" +#include "TaskScheduler.h" +#include "auchindoun.h" + +enum AuchindounSpells +{ + SPELL_HALO_HEAL = 157795, + SPELL_TUULANI_UNLOCK_VISUAL = 160415, + SPELL_GRIMRAIL_DEPOT_SCENE = 178747, + SPELL_GRIMRAIL_DEPOT_SELECTOR = 178800, + SPELL_GRIMRAIL_DEPOT_TELEPORT = 178799, + SPELL_GRIMRAIL_DEPOT_REMOVE_AURA = 178746 + + // SPELL_INSTANCE_BOOTSTRAPPER = 171344 // This spell appears in a lot of sniffs, but the purpose is unknown +}; + +enum AuchindounActions +{ + ACTION_TUULANI_INTRO = 1, + ACTION_TUULANI_BREAK_BARRIER, + ACTION_AUCHENAI_DEFENDER_TALK +}; + +enum AuchindounTexts +{ + // Auchenai Defender + SAY_NYAMI_AWAITS = 0, + + // Soulbinder Tuulani + SAY_WELCOME_1 = 0, + SAY_WELCOME_2 = 1, + SAY_WELCOME_3 = 2, + SAY_BREAK_BARRIER_1 = 3, + SAY_BREAK_BARRIER_2 = 4, + SAY_HEROES_SOULS = 5 +}; + +enum AuchindounMisc +{ + // Waypoint + PATH_BARRIER = 7924800, + PATH_MOVE_TO_BOSS = 7924801, + + POINT_TALK = 2, + POINT_BARRIER = 8, + + POINT_SOULS = 5, + + // Spawngroups + SPAWNGROUP_TUULANI_IMPRISONED = 1264 +}; + +// 9973 - Areatrigger +class at_auchindoun_entrance : public OnlyOnceAreaTriggerScript +{ +public: + at_auchindoun_entrance() : OnlyOnceAreaTriggerScript("at_auchindoun_entrance") { } + + bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + { + if (Creature* tuulani = instance->GetCreature(DATA_SOULBINDER_TUULANI)) + tuulani->AI()->DoAction(ACTION_TUULANI_INTRO); + } + return true; + } +}; + +// 10072 - Areatrigger +class at_auchindoun_auchenai_defender_intro : public OnlyOnceAreaTriggerScript +{ +public: + at_auchindoun_auchenai_defender_intro() : OnlyOnceAreaTriggerScript("at_auchindoun_auchenai_defender_intro") { } + + bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (Creature* auchenaiDefender = player->FindNearestCreatureWithOptions(30.0f, { .StringId = "npc_auchenai_defender_intro" })) + auchenaiDefender->AI()->DoAction(ACTION_AUCHENAI_DEFENDER_TALK); + + return true; + } +}; + +// 9974 - Areatrigger +// Not OnlyOnce because players can trigger this AT before Tuulani reaches the barrier +class at_auchindoun_barrier : public AreaTriggerScript +{ +public: + at_auchindoun_barrier() : AreaTriggerScript("at_auchindoun_barrier") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + { + if (Creature* tuulani = instance->GetCreature(DATA_SOULBINDER_TUULANI)) + tuulani->AI()->DoAction(ACTION_TUULANI_BREAK_BARRIER); + } + return true; + } +}; + +// 10280 - Areatrigger +class at_auchindoun_soulbinder_nyami_scene : public OnlyOnceAreaTriggerScript +{ +public: + at_auchindoun_soulbinder_nyami_scene() : OnlyOnceAreaTriggerScript("at_auchindoun_soulbinder_nyami_scene") { } + + bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + player->CastSpell(player, SPELL_GRIMRAIL_DEPOT_SELECTOR, true); + + if (InstanceScript* instance = player->GetInstanceScript()) + { + if (Creature* tuulani = instance->GetCreature(DATA_SOULBINDER_TUULANI)) + tuulani->DespawnOrUnsummon(); + } + return true; + } +}; + +// 77693 - Auchenai Defender +struct npc_auchindoun_auchenai_defender : public ScriptedAI +{ + npc_auchindoun_auchenai_defender(Creature* creature) : ScriptedAI(creature) { } + + void DoAction(int32 action) override + { + if (action == ACTION_AUCHENAI_DEFENDER_TALK) + { + me->SetStandState(UNIT_STAND_STATE_STAND); + + _scheduler.Schedule(1s + 300ms, [this](TaskContext /*task*/) + { + me->SetFacingTo(3.8194849f); + Talk(SAY_NYAMI_AWAITS); + }); + } + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +// 79248 - Soulbinder Tuulani +struct npc_auchindoun_soulbinder_tuulani : public ScriptedAI +{ + npc_auchindoun_soulbinder_tuulani(Creature* creature) : ScriptedAI(creature), _isAtBarrier(false), _actionStarted(false) { } + + void DoAction(int32 action) override + { + if (action == ACTION_TUULANI_INTRO) + { + Talk(SAY_WELCOME_1); + + _scheduler.Schedule(4s + 300ms, [this](TaskContext task) + { + Talk(SAY_WELCOME_2); + + task.Schedule(6s, [this](TaskContext /*task*/) + { + me->GetMotionMaster()->MovePath(PATH_BARRIER, false); + }); + }); + } + else if (action == ACTION_TUULANI_BREAK_BARRIER) + { + if (!_isAtBarrier || _actionStarted) + return; + + _actionStarted = true; + + Talk(SAY_BREAK_BARRIER_1); + + _scheduler.Schedule(3s, [this](TaskContext task) + { + DoCast(SPELL_TUULANI_UNLOCK_VISUAL); + + task.Schedule(4s, [this](TaskContext task) + { + if (GameObject* holyBarrier = me->GetInstanceScript()->GetGameObject(DATA_HOLY_BARRIER)) + holyBarrier->SetGoState(GO_STATE_ACTIVE); + + task.Schedule(2s + 300ms, [this](TaskContext task) + { + Talk(SAY_BREAK_BARRIER_2); + + task.Schedule(1s + 300ms, [this](TaskContext /*task*/) + { + me->GetMotionMaster()->MovePath(PATH_MOVE_TO_BOSS, false); + }); + }); + }); + }); + } + } + + void WaypointReached(uint32 waypointId, uint32 pathId) override + { + if (pathId == PATH_BARRIER) + { + switch (waypointId) + { + case POINT_TALK: + { + _scheduler.Schedule(500ms, [this](TaskContext /*task*/) + { + Talk(SAY_WELCOME_3); + }); + break; + } + case POINT_BARRIER: + { + _isAtBarrier = true; + break; + } + default: + break; + } + } + else if (pathId == PATH_MOVE_TO_BOSS) + { + if (waypointId == POINT_SOULS) + { + _scheduler.Schedule(500ms, [this](TaskContext /*task*/) + { + me->SetFacingTo(1.727875f); + Talk(SAY_HEROES_SOULS); + }); + } + } + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; + bool _isAtBarrier; + bool _actionStarted; +}; + +// 155647 - NPC Reaction +struct at_auchindoun_npc_reaction : AreaTriggerAI +{ + at_auchindoun_npc_reaction(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { } + + void OnUnitEnter(Unit* unit) override + { + if (!unit->IsCreature() || unit->GetEmoteState() == EMOTE_STATE_READY1H_ALLOW_MOVEMENT || unit->GetEntry() == NPC_SOULBINDER_TUULANI) + return; + + _scheduler.Schedule(1500ms, [this, unitGUID = unit->GetGUID()](TaskContext task) + { + Creature* auchenaiDefender = ObjectAccessor::GetCreature(*at, unitGUID); + if (!auchenaiDefender) + return; + + if (Unit* caster = at->GetCaster()) + auchenaiDefender->SetFacingToObject(caster); + auchenaiDefender->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + + task.Schedule(4s, [this, unitGUID](TaskContext /*task*/) + { + Creature* auchenaiDefender = ObjectAccessor::GetCreature(*at, unitGUID); + if (!auchenaiDefender) + return; + + auchenaiDefender->SetFacingTo(auchenaiDefender->GetHomePosition().GetOrientation()); + }); + }); + } + + void OnUpdate(uint32 diff) override + { + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; +}; + +// 157762 - Halo +class spell_auchindoun_halo : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_HALO_HEAL }); + } + + void HandleHit(SpellEffIndex /*effIndex*/) const + { + if (!GetHitUnit()->IsCreature()) + return; + + GetCaster()->CastSpell(GetHitUnit(), SPELL_HALO_HEAL, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_auchindoun_halo::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +// 178800 - Grimrail Depot +class spell_auchindoun_grimrail_depot_scene_selector : public SpellScript +{ + void HandleDummy(SpellEffIndex /*effIndex*/) const + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_GRIMRAIL_DEPOT_SCENE, true); + // GetCaster()->CastSpell(GetHitUnit(), SPELL_INSTANCE_BOOTSTRAPPER, false); + } + + void HandleEvent(SpellEffIndex /*effIndex*/) const + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + instance->SendEncounterUnit(ENCOUNTER_FRAME_PHASE_SHIFT_CHANGED, nullptr); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_auchindoun_grimrail_depot_scene_selector::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHit += SpellEffectFn(spell_auchindoun_grimrail_depot_scene_selector::HandleEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); + } +}; + +// 178747 - Grimrail Depot +class scene_auchindoun_soulbinder_nyami : public SceneScript +{ +public: + scene_auchindoun_soulbinder_nyami() : SceneScript("scene_auchindoun_soulbinder_nyami") { } + + static void HandleScene(Player* player) + { + player->ClearUnitState(UNIT_STATE_ROOT); + player->CastSpell(player, SPELL_GRIMRAIL_DEPOT_TELEPORT, true); + player->CastSpell(player, SPELL_GRIMRAIL_DEPOT_REMOVE_AURA, TRIGGERED_FULL_MASK); + PhasingHandler::OnConditionChange(player); + + Map* map = player->GetMap(); + if (!map->IsSpawnGroupActive(SPAWNGROUP_TUULANI_IMPRISONED)) + map->SpawnGroupSpawn(SPAWNGROUP_TUULANI_IMPRISONED); + } + + void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override + { + player->AddUnitState(UNIT_STATE_ROOT); + } + + void OnSceneComplete(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override + { + HandleScene(player); + } + + void OnSceneCancel(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override + { + HandleScene(player); + } +}; + +void AddSC_auchindoun() +{ + new at_auchindoun_entrance(); + new at_auchindoun_auchenai_defender_intro(); + new at_auchindoun_barrier(); + new at_auchindoun_soulbinder_nyami_scene(); + + RegisterAuchindounCreatureAI(npc_auchindoun_auchenai_defender); + RegisterAuchindounCreatureAI(npc_auchindoun_soulbinder_tuulani); + RegisterAreaTriggerAI(at_auchindoun_npc_reaction); + RegisterSpellScript(spell_auchindoun_halo); + RegisterSpellScript(spell_auchindoun_grimrail_depot_scene_selector); + + new scene_auchindoun_soulbinder_nyami(); +} diff --git a/src/server/scripts/Draenor/Auchindoun/auchindoun.h b/src/server/scripts/Draenor/Auchindoun/auchindoun.h new file mode 100644 index 00000000000..9383fe3aa0b --- /dev/null +++ b/src/server/scripts/Draenor/Auchindoun/auchindoun.h @@ -0,0 +1,66 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef _Auchindoun_h__ +#define _Auchindoun_h__ + +#include "CreatureAIImpl.h" + +constexpr char const* DataHeader = "Auchindoun"; +constexpr char const* AuchindounScriptName = "instance_auchindoun"; + +constexpr uint32 EncounterCount = 4; + +enum AuchindounDataTypes +{ + // Encounters + DATA_VIGILANT_KAATHAR = 0, + DATA_SOULBINDER_NYAMI = 1, + DATA_AZZAKEL = 2, + DATA_TERONGOR = 3, + + DATA_SOULBINDER_TUULANI, + + // GameObjects + DATA_HOLY_BARRIER, +}; + +enum AuchindounCreatureIds +{ + // Bosses + BOSS_VIGILANT_KAATHAR = 75839, + BOSS_SOULBINDER_NYAMI = 76177, + BOSS_AZZAKEL = 75927, + BOSS_TERONGOR = 77734, + + NPC_SOULBINDER_TUULANI = 79248 +}; + +enum AuchindounGameobjectIds +{ + GO_HOLY_BARRIER = 230398 +}; + +template <class AI, class T> +inline AI* GetAuchindounAI(T* obj) +{ + return GetInstanceAI<AI>(obj, AuchindounScriptName); +} + +#define RegisterAuchindounCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetAuchindounAI) + +#endif // _Auchindoun_h__ diff --git a/src/server/scripts/Draenor/Auchindoun/instance_auchindoun.cpp b/src/server/scripts/Draenor/Auchindoun/instance_auchindoun.cpp new file mode 100644 index 00000000000..8f5fc172a4a --- /dev/null +++ b/src/server/scripts/Draenor/Auchindoun/instance_auchindoun.cpp @@ -0,0 +1,71 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "InstanceScript.h" +#include "ScriptMgr.h" +#include "auchindoun.h" + +constexpr ObjectData creatureData[] = +{ + { BOSS_VIGILANT_KAATHAR, DATA_VIGILANT_KAATHAR }, + { BOSS_SOULBINDER_NYAMI, DATA_SOULBINDER_NYAMI }, + { BOSS_AZZAKEL, DATA_AZZAKEL }, + { BOSS_TERONGOR, DATA_TERONGOR }, + { NPC_SOULBINDER_TUULANI, DATA_SOULBINDER_TUULANI }, + { 0, 0 } // END +}; + +constexpr ObjectData objectData[] = +{ + { GO_HOLY_BARRIER, DATA_HOLY_BARRIER }, + { 0, 0 } // END +}; + +constexpr DungeonEncounterData encounters[] = +{ + { DATA_VIGILANT_KAATHAR, {{ 1678 }} }, + { DATA_SOULBINDER_NYAMI, {{ 1685 }} }, + { DATA_AZZAKEL, {{ 1686 }} }, + { DATA_TERONGOR, {{ 1714 }} } +}; + +class instance_auchindoun : public InstanceMapScript +{ +public: + instance_auchindoun() : InstanceMapScript("instance_auchindoun", 1182) { } + + struct instance_auchindoun_InstanceMapScript : public InstanceScript + { + instance_auchindoun_InstanceMapScript(InstanceMap* map) : InstanceScript(map) + { + SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadObjectData(creatureData, objectData); + LoadDungeonEncounterData(encounters); + } + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_auchindoun_InstanceMapScript(map); + } +}; + +void AddSC_instance_auchindoun() +{ + new instance_auchindoun(); +} diff --git a/src/server/scripts/Draenor/draenor_script_loader.cpp b/src/server/scripts/Draenor/draenor_script_loader.cpp index b913ee77253..a9ea6c61bd0 100644 --- a/src/server/scripts/Draenor/draenor_script_loader.cpp +++ b/src/server/scripts/Draenor/draenor_script_loader.cpp @@ -20,6 +20,10 @@ void AddSC_assault_on_the_dark_portal(); void AddSC_draenor_shadowmoon_valley(); void AddSC_garrison_generic(); +// Auchindoun +void AddSC_instance_auchindoun(); +void AddSC_auchindoun(); + // The name of this function should match: // void Add${NameOfDirectory}Scripts() void AddDraenorScripts() @@ -27,4 +31,8 @@ void AddDraenorScripts() AddSC_assault_on_the_dark_portal(); AddSC_draenor_shadowmoon_valley(); AddSC_garrison_generic(); + + // Auchindoun + AddSC_instance_auchindoun(); + AddSC_auchindoun(); } |