diff options
author | Ovahlord <dreadkiller@gmx.de> | 2023-12-23 17:03:59 +0100 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2023-12-24 05:41:44 +0100 |
commit | 44921878f1e659f8697f242b294144f695748a54 (patch) | |
tree | c26b29b520c878c14c01413ec3c87237de79238c /src/server/scripts/Kalimdor | |
parent | e05541665b67e55c4ff70073854886df1222643d (diff) |
Scripts/Vortex Pinnacle: implemented Slipstreams and shortcuts
Diffstat (limited to 'src/server/scripts/Kalimdor')
4 files changed, 307 insertions, 6 deletions
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp index 5cfc57b39cb..0f62b30aac5 100644 --- a/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp +++ b/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp @@ -17,6 +17,7 @@ #include "ScriptMgr.h" #include "vortex_pinnacle.h" +#include "Creature.h" #include "InstanceScript.h" ObjectData const creatureData[] = @@ -34,6 +35,10 @@ DungeonEncounterData const encounters[] = { BOSS_ASAAD, {{ 1042 }} } }; +// These StringIds must be set in DB to properly identify the first and second landing zone for the entrance shortcut teleporters +constexpr std::string_view SlipStreamLandingZoneStringId1 = "vp_slipstream_landing_zone_1"; +constexpr std::string_view SlipStreamLandingZoneStringId2 = "vp_slipstream_landing_zone_2"; + class instance_vortex_pinnacle : public InstanceMapScript { public: @@ -48,6 +53,40 @@ public: LoadObjectData(creatureData, nullptr); LoadDungeonEncounterData(encounters); } + + void OnCreatureCreate(Creature* creature) override + { + InstanceScript::OnCreatureCreate(creature); + + switch (creature->GetEntry()) + { + case NPC_SLIPSTREAM_LANDING_ZONE: + if (creature->HasStringId(SlipStreamLandingZoneStringId1)) + AddObject(creature, DATA_SLIPSTREAM_LANDING_ZONE_1, true); + else if (creature->HasStringId(SlipStreamLandingZoneStringId2)) + AddObject(creature, DATA_SLIPSTREAM_LANDING_ZONE_2, true); + break; + default: + break; + } + } + + void OnCreatureRemove(Creature* creature) override + { + InstanceScript::OnCreatureRemove(creature); + + switch (creature->GetEntry()) + { + case NPC_SLIPSTREAM_LANDING_ZONE: + if (creature->HasStringId(SlipStreamLandingZoneStringId1)) + AddObject(creature, DATA_SLIPSTREAM_LANDING_ZONE_1, false); + else if (creature->HasStringId(SlipStreamLandingZoneStringId2)) + AddObject(creature, DATA_SLIPSTREAM_LANDING_ZONE_2, false); + break; + default: + break; + } + } }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp new file mode 100644 index 00000000000..e7d9643ca11 --- /dev/null +++ b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp @@ -0,0 +1,253 @@ +/* + * 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 "vortex_pinnacle.h" +#include "Creature.h" +#include "DB2Structure.h" +#include "EventMap.h" +#include "InstanceScript.h" +#include "ObjectAccessor.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptMgr.h" +#include "SpellInfo.h" +#include "SpellScript.h" +#include "Vehicle.h" + +enum VPVehicleIds +{ + VEHICLE_ID_SLIPSTREAM_ENTRANCE_1 = 1305, + VEHICLE_ID_SLIPSTREAM_ENTRANCE_2 = 1306, + VEHICLE_ID_SLIPSTREAM_1 = 1111, + VEHICLE_ID_SLIPSTREAM_2 = 1112, + VEHICLE_ID_SLIPSTREAM_3 = 1113, + VEHICLE_ID_SLIPSTREAM_4 = 1149, + VEHICLE_ID_SLIPSTREAM_5 = 1150, + VEHICLE_ID_SLIPSTREAM_BACK_TO_ENTRANCE = 1551 +}; + +enum VPSlipstreamSpells +{ + // Spells + SPELL_SLIPSTREAM_ENTER = 84965, + SPELL_SLIPSTREAM_FIRST = 84980, + SPELL_SLIPSTREAM_SECOND = 84988, + SPELL_SLIPSTREAM_THIRD = 85394, + SPELL_SLIPSTREAM_FOURTH = 85397, + SPELL_SLIPSTREAM_LAST = 85016, + SPELL_SLIPSTREAM_ASAAD = 95911, + SPELL_SLIPSTREAM_SHORTCUT_ALTAIRUS = 89498, + SPELL_SLIPSTREAM_SHORTCUT_ALTAIRUS_TELEPORT = 89499, + SPELL_SLIPSTREAM_SHORTCUT_ASAAD = 89500, + SPELL_SLIPSTREAM_SHORTCUT_ASAAD_TELEPORT = 89501, + SPELL_GENERIC_EJECT_ALL_PASSENGERS = 79737 +}; + +struct SlipstreamInfo +{ + SlipstreamInfo(std::string_view const& stringId, std::string_view const& targetStringId, uint32 vehicleId, bool spellClick, uint32 chainSpellId) : + StringId(stringId), TargetStringId(targetStringId), VehicleId(vehicleId), SpellClick(spellClick), ChainSpellId(chainSpellId) { } + + std::string_view StringId; + std::string_view TargetStringId; + uint32 VehicleId; + bool SpellClick; + uint32 ChainSpellId; +}; + +static std::array<SlipstreamInfo const, 11> const SlipstreamData = +{ + // Sequence for Grandvizier Ertan's Slipstreams + SlipstreamInfo("vp_slipstream_ertan_1", "vp_slipstream_ertan_2", VEHICLE_ID_SLIPSTREAM_1, true, SPELL_SLIPSTREAM_FIRST), + SlipstreamInfo("vp_slipstream_ertan_2", "vp_slipstream_ertan_3", VEHICLE_ID_SLIPSTREAM_2, false, SPELL_SLIPSTREAM_SECOND), + SlipstreamInfo("vp_slipstream_ertan_3", "vp_slipstream_landing_zone_1", VEHICLE_ID_SLIPSTREAM_3, false, SPELL_SLIPSTREAM_LAST), + + // Sequence for Altairus' Slipstreams + SlipstreamInfo("vp_slipstream_altairus_1", "vp_slipstream_altairus_2", VEHICLE_ID_SLIPSTREAM_1, true, SPELL_SLIPSTREAM_FIRST), + SlipstreamInfo("vp_slipstream_altairus_2", "vp_slipstream_altairus_3", VEHICLE_ID_SLIPSTREAM_2, false, SPELL_SLIPSTREAM_SECOND), + SlipstreamInfo("vp_slipstream_altairus_3", "vp_slipstream_altairus_4", VEHICLE_ID_SLIPSTREAM_3, false, SPELL_SLIPSTREAM_THIRD), + SlipstreamInfo("vp_slipstream_altairus_4", "vp_slipstream_altairus_5", VEHICLE_ID_SLIPSTREAM_4, false, SPELL_SLIPSTREAM_FOURTH), + SlipstreamInfo("vp_slipstream_altairus_5", "vp_slipstream_landing_zone_2", VEHICLE_ID_SLIPSTREAM_5, false, SPELL_SLIPSTREAM_LAST), + + // Shortcuts + SlipstreamInfo("vp_slipstream_entrance_1", "", VEHICLE_ID_SLIPSTREAM_ENTRANCE_1, true, SPELL_SLIPSTREAM_SHORTCUT_ALTAIRUS), + SlipstreamInfo("vp_slipstream_entrance_2", "", VEHICLE_ID_SLIPSTREAM_ENTRANCE_2, true, SPELL_SLIPSTREAM_SHORTCUT_ASAAD), + SlipstreamInfo("vp_slipstream_back_to_entrance", "", VEHICLE_ID_SLIPSTREAM_BACK_TO_ENTRANCE, true, SPELL_SLIPSTREAM_ASAAD) +}; + +struct npc_vp_slipstream : public NullCreatureAI +{ + npc_vp_slipstream(Creature* creature) : NullCreatureAI(creature) { } + + // This is a bit hacky but we have to set the vehicleId before the npc is being sent out via UpdateObject to prevent client visuals from breaking + void InitializeAI() override + { + for (SlipstreamInfo const& slipstreamInfo : SlipstreamData) + { + if (!me->HasStringId(slipstreamInfo.StringId)) + continue; + + Vehicle const* vehicle = me->GetVehicleKit(); + // Uninstall the existing vehicle kit when the vehicleId mismatches + if (vehicle && vehicle->GetVehicleInfo()->ID != slipstreamInfo.VehicleId) + { + me->RemoveVehicleKit(true); + vehicle = nullptr; + } + + if (!vehicle) + me->CreateVehicleKit(slipstreamInfo.VehicleId, me->GetEntry(), true); + + if (slipstreamInfo.SpellClick) + { + me->SetNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); + me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE); + } + break; + } + } + + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override + { + if (!apply || !who->IsPlayer()) + return; + + for (SlipstreamInfo const& slipstreamInfo : SlipstreamData) + { + if (!me->HasStringId(slipstreamInfo.StringId)) + continue; + + // The cast of the chain spell is slightly delayed + me->m_Events.AddEventAtOffset([caster = me, playerGuid = who->GetGUID(), chainSpellId = slipstreamInfo.ChainSpellId]() + { + if (Player* player = ObjectAccessor::FindPlayer(playerGuid)) + if (player->IsOnVehicle(caster)) + caster->CastSpell(player, chainSpellId); + }, 500ms); + break; + } + } +}; + +static constexpr uint32 const EVENT_EJECT_ALL_PASSENGERS = 1; + +struct npc_vp_slipstream_landing_zone : public NullCreatureAI +{ + npc_vp_slipstream_landing_zone(Creature* creature) : NullCreatureAI(creature) { } + + void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override + { + if (!apply) + return; + + // Every time a player enters the landing zone vehicle before it can eject passengers, it will delay its cast + _events.RescheduleEvent(EVENT_EJECT_ALL_PASSENGERS, 2s); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (_events.ExecuteEvent()) + DoCastSelf(SPELL_GENERIC_EJECT_ALL_PASSENGERS); + } + +private: + EventMap _events; +}; + +// 84978, 84989, 85395, 85396, 85017 - Slipstream +class spell_vp_slipstream : public SpellScript +{ + bool Load() override + { + Creature const* vehicle = GetCaster()->GetVehicleCreatureBase(); + if (!vehicle) + return false; + + for (SlipstreamInfo const& slipstreamInfo : SlipstreamData) + { + if (!vehicle->HasStringId(slipstreamInfo.StringId)) + continue; + + _targetStringId = slipstreamInfo.TargetStringId; + return true; + } + + return false; + } + + void SelectNextSlipstream(WorldObject*& target) + { + target = GetCaster()->FindNearestCreatureWithOptions(200.f, { .StringId = _targetStringId }); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_vp_slipstream::SelectNextSlipstream, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + } +private: + std::string_view _targetStringId; +}; + +// 89499, 89501 - Slipstream +class spell_vp_slipstream_shortcut : public SpellScript +{ + bool Load() override + { + _instance = GetCaster()->GetInstanceScript(); + return _instance != nullptr; + } + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SLIPSTREAM_SHORTCUT_ALTAIRUS_TELEPORT, SPELL_SLIPSTREAM_SHORTCUT_ASAAD_TELEPORT }); + } + + // The distance between the shortcut Slipstreams and the Slipstream Landing Platforms is beyond our grid searching limit, we have to manually select the target + void SetDestination(SpellDestination& target) + { + switch (GetSpellInfo()->Id) + { + case SPELL_SLIPSTREAM_SHORTCUT_ALTAIRUS_TELEPORT: + if (Creature* landingZone = _instance->GetCreature(DATA_SLIPSTREAM_LANDING_ZONE_1)) + target.Relocate(landingZone->GetPosition()); + break; + case SPELL_SLIPSTREAM_SHORTCUT_ASAAD_TELEPORT: + if (Creature* landingZone = _instance->GetCreature(DATA_SLIPSTREAM_LANDING_ZONE_2)) + target.Relocate(landingZone->GetPosition()); + break; + default: + break; + } + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_vp_slipstream_shortcut::SetDestination, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + } +private: + InstanceScript* _instance; +}; + +void AddSC_vortex_pinnacle() +{ + RegisterVortexPinnacleCreatureAI(npc_vp_slipstream); + RegisterVortexPinnacleCreatureAI(npc_vp_slipstream_landing_zone); + RegisterSpellScript(spell_vp_slipstream); + RegisterSpellScript(spell_vp_slipstream_shortcut); +} diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h index 4153b1888a6..4f105979640 100644 --- a/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h +++ b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h @@ -25,20 +25,27 @@ constexpr char const* VPScriptName = "instance_vortex_pinnacle"; constexpr uint32 const EncounterCount = 3; -enum TotFWDataTypes +enum VPDataTypes { // Encounters BOSS_GRAND_VIZIER_ERTAN = 0, BOSS_ALTAIRUS = 1, - BOSS_ASAAD = 2 + BOSS_ASAAD = 2, + + // Shortcuts + DATA_SLIPSTREAM_LANDING_ZONE_1, + DATA_SLIPSTREAM_LANDING_ZONE_2 }; -enum TotFWCreatureIds +enum VPreatureIds { // Bosses - NPC_GRAND_VIZIER_ERTAN = 43878, - NPC_ALTAIRUS = 43873, - NPC_ASAAD = 43875 + NPC_GRAND_VIZIER_ERTAN = 43878, + NPC_ALTAIRUS = 43873, + NPC_ASAAD = 43875, + + // Shortcuts + NPC_SLIPSTREAM_LANDING_ZONE = 45504 }; template <class AI, class T> diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp index f76ef867ae1..6a61f5ed0cf 100644 --- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -111,6 +111,7 @@ void AddSC_boss_lockmaw(); void AddSC_instance_lost_city_of_the_tolvir(); // The Vortex Pinnacle void AddSC_instance_vortex_pinnacle(); +void AddSC_vortex_pinnacle(); // Wailing caverns void AddSC_wailing_caverns(); void AddSC_instance_wailing_caverns(); @@ -248,6 +249,7 @@ void AddKalimdorScripts() AddSC_instance_lost_city_of_the_tolvir(); // The Vortex Pinnacle AddSC_instance_vortex_pinnacle(); + AddSC_vortex_pinnacle(); // Wailing caverns AddSC_wailing_caverns(); AddSC_instance_wailing_caverns(); |