diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h index 3f5c2864fa..5195158b60 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -78,6 +78,7 @@ class TC_COMMON_API EventProcessor void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true); void ModifyEventTime(BasicEvent* Event, uint64 newTime); uint64 CalculateTime(uint64 t_offset) const; + std::multimap const& GetEvents() const { return m_events; } protected: uint64 m_time; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 005a844ebd..59e4f28c59 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -12361,6 +12361,31 @@ void Unit::SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const SendMessageToSet(playSpellVisualKit.Write(), true); } +void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/) +{ + bool hasMissile = false; + for (std::pair const& itr : m_Events.GetEvents()) + { + if (Spell const* spell = Spell::ExtractSpellFromEvent(itr.second)) + { + if (spell->GetSpellInfo()->Id == spellId) + { + itr.second->ScheduleAbort(); + hasMissile = true; + } + } + } + + if (hasMissile) + { + WorldPackets::Spells::MissileCancel packet; + packet.OwnerGUID = GetGUID(); + packet.SpellID = spellId; + packet.Reverse = reverseMissile; + SendMessageToSet(packet.Write(), false); + } +} + void Unit::ApplyResilience(Unit const* victim, int32* damage) const { // player mounted on multi-passenger mount is also classified as vehicle diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index d5f7eb10cb..571dcecbee 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1340,6 +1340,7 @@ class TC_GAME_API Unit : public WorldObject void SendPlaySpellVisual(Position const& targetPosition, float o, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime = false); void SendCancelSpellVisualKit(uint32 id); void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const; + void CancelSpellMissiles(uint32 spellId, bool reverseMissile = false); void DeMorph(); diff --git a/src/server/game/Server/Packets/SpellPackets.cpp b/src/server/game/Server/Packets/SpellPackets.cpp index df65ce8d81..9efe37d956 100644 --- a/src/server/game/Server/Packets/SpellPackets.cpp +++ b/src/server/game/Server/Packets/SpellPackets.cpp @@ -967,3 +967,13 @@ WorldPacket const* WorldPackets::Spells::MountResult::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Spells::MissileCancel::Write() +{ + _worldPacket << OwnerGUID; + _worldPacket << int32(SpellID); + _worldPacket.WriteBit(Reverse); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index afef30bcb8..65f1484322 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -1009,6 +1009,18 @@ namespace WorldPackets uint32 Result = 0; }; + + class MissileCancel final : public ServerPacket + { + public: + MissileCancel() : ServerPacket(SMSG_MISSILE_CANCEL, 21) { } + + WorldPacket const* Write() override; + + ObjectGuid OwnerGUID; + bool Reverse = false; + int32 SpellID = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index f356328de4..a5de0f6c6c 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1450,7 +1450,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_COMPONENTED_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_CREATURE_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MODIFY_CHARGE_RECOVERY_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MODIFY_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MODIFY_COOLDOWN_RECOVERY_SPEED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 85ece8f024..739222a027 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -511,9 +511,11 @@ public: SpellEvent(Spell* spell); virtual ~SpellEvent(); - virtual bool Execute(uint64 e_time, uint32 p_time) override; - virtual void Abort(uint64 e_time) override; - virtual bool IsDeletable() const override; + bool Execute(uint64 e_time, uint32 p_time) override; + void Abort(uint64 e_time) override; + bool IsDeletable() const override; + Spell const* GetSpell() const { return m_Spell; } + protected: Spell* m_Spell; }; @@ -4880,6 +4882,14 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT } } +/*static*/ Spell const* Spell::ExtractSpellFromEvent(BasicEvent* event) +{ + if (SpellEvent* spellEvent = dynamic_cast(event)) + return spellEvent->GetSpell(); + + return nullptr; +} + SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) { // check death state diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 162166c750..fdec7c09a1 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -38,6 +38,7 @@ namespace WorldPackets class Aura; class AuraEffect; +class BasicEvent; class Corpse; class DynamicObject; class GameObject; @@ -598,6 +599,7 @@ class TC_GAME_API Spell void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOTarget, uint32 i, SpellEffectHandleMode mode); void HandleThreatSpells(); + static Spell const* ExtractSpellFromEvent(BasicEvent* event); SpellInfo const* const m_spellInfo; Item* m_CastItem;