From 0d4eff65d0aae5f2476e1c19f488e4bc0e004f8a Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 14 Feb 2026 21:29:44 -0800 Subject: [PATCH] Fix vanilla spell cast and use-item packet formats for Turtle/Classic SpellCastTargets target mask is uint16 in vanilla 1.12.x, not uint32 like WotLK. The 2 extra bytes corrupted every spell packet. Also add classic CMSG_USE_ITEM builder (bag+slot+spellIndex+targets only, no spellId/itemGuid/glyphIndex/castFlags fields that WotLK added). --- include/game/packet_parsers.hpp | 6 ++++++ src/game/game_handler.cpp | 4 +++- src/game/packet_parsers_classic.cpp | 22 ++++++++++++++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/game/packet_parsers.hpp b/include/game/packet_parsers.hpp index d793d9d5..28b8c4b8 100644 --- a/include/game/packet_parsers.hpp +++ b/include/game/packet_parsers.hpp @@ -50,6 +50,11 @@ public: return CastSpellPacket::build(spellId, targetGuid, castCount); } + /** Build CMSG_USE_ITEM (WotLK default: bag + slot + castCount + spellId + itemGuid + glyphIndex + castFlags + targets) */ + virtual network::Packet buildUseItem(uint8_t bagIndex, uint8_t slotIndex, uint64_t itemGuid) { + return UseItemPacket::build(bagIndex, slotIndex, itemGuid); + } + // --- Character Enumeration --- /** Parse SMSG_CHAR_ENUM */ @@ -238,6 +243,7 @@ public: const MovementInfo& info, uint64_t playerGuid = 0) override; network::Packet buildCastSpell(uint32_t spellId, uint64_t targetGuid, uint8_t castCount) override; + network::Packet buildUseItem(uint8_t bagIndex, uint8_t slotIndex, uint64_t itemGuid) override; bool parseCastFailed(network::Packet& packet, CastFailedData& data) override; bool parseMessageChat(network::Packet& packet, MessageChatData& data) override; bool parseGameObjectQueryResponse(network::Packet& packet, GameObjectQueryResponseData& data) override; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 8489091f..8f7e06db 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -7626,7 +7626,9 @@ void GameHandler::useItemBySlot(int backpackIndex) { } if (itemGuid != 0 && state == WorldState::IN_WORLD && socket) { // WoW inventory: equipment 0-18, bags 19-22, backpack 23-38 - auto packet = UseItemPacket::build(0xFF, static_cast(23 + backpackIndex), itemGuid); + auto packet = packetParsers_ + ? packetParsers_->buildUseItem(0xFF, static_cast(23 + backpackIndex), itemGuid) + : UseItemPacket::build(0xFF, static_cast(23 + backpackIndex), itemGuid); socket->send(packet); } else if (itemGuid == 0) { LOG_WARNING("Use item failed: missing item GUID for slot ", backpackIndex); diff --git a/src/game/packet_parsers_classic.cpp b/src/game/packet_parsers_classic.cpp index 458b3fe9..d9bc745a 100644 --- a/src/game/packet_parsers_classic.cpp +++ b/src/game/packet_parsers_classic.cpp @@ -260,16 +260,16 @@ network::Packet ClassicPacketParsers::buildMovementPacket(LogicalOpcode opcode, // ============================================================================ // Classic buildCastSpell // Vanilla 1.12.x: NO castCount prefix, NO castFlags byte -// Format: uint32 spellId + uint32 targetFlags + [PackedGuid if unit target] +// Format: uint32 spellId + uint16 targetFlags + [PackedGuid if unit target] // ============================================================================ network::Packet ClassicPacketParsers::buildCastSpell(uint32_t spellId, uint64_t targetGuid, uint8_t /*castCount*/) { network::Packet packet(wireOpcode(LogicalOpcode::CMSG_CAST_SPELL)); packet.writeUInt32(spellId); - // SpellCastTargets — vanilla/CMaNGOS uses uint32 target mask (same as WotLK) + // SpellCastTargets — vanilla/CMaNGOS uses uint16 target mask (WotLK uses uint32) if (targetGuid != 0) { - packet.writeUInt32(0x02); // TARGET_FLAG_UNIT + packet.writeUInt16(0x02); // TARGET_FLAG_UNIT // Write packed GUID uint8_t mask = 0; @@ -289,12 +289,26 @@ network::Packet ClassicPacketParsers::buildCastSpell(uint32_t spellId, uint64_t packet.writeUInt8(bytes[i]); } } else { - packet.writeUInt32(0x00); // TARGET_FLAG_SELF + packet.writeUInt16(0x00); // TARGET_FLAG_SELF } return packet; } +// ============================================================================ +// Classic CMSG_USE_ITEM +// Vanilla 1.12.x: bag(u8) + slot(u8) + spellIndex(u8) + SpellCastTargets(u16) +// NO spellId, itemGuid, glyphIndex, or castFlags fields (those are WotLK) +// ============================================================================ +network::Packet ClassicPacketParsers::buildUseItem(uint8_t bagIndex, uint8_t slotIndex, uint64_t /*itemGuid*/) { + network::Packet packet(wireOpcode(LogicalOpcode::CMSG_USE_ITEM)); + packet.writeUInt8(bagIndex); + packet.writeUInt8(slotIndex); + packet.writeUInt8(0); // spell_index (which item spell to trigger, usually 0) + packet.writeUInt16(0x0000); // SpellCastTargets: TARGET_FLAG_SELF + return packet; +} + // ============================================================================ // Classic SMSG_CAST_FAILED: no castCount byte (added in TBC/WotLK) // Format: spellId(u32) + result(u8)