From dd7d74cb933627b0669d6a51d02ebab63ab13ab6 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 03:54:33 -0700 Subject: [PATCH] fix: correct SMSG_SPELL_FAILURE Classic format and result enum shift Classic 1.12 SMSG_SPELL_FAILURE omits the castCount byte that TBC/WotLK include (format: uint64 GUID + uint32 spellId + uint8 failReason). The previous code read a castCount for all expansions, misaligning spellId and failReason for Classic by one byte. Also apply the same +1 enum shift used in parseCastFailed/parseCastResult: Classic result 0=AFFECTING_COMBAT maps to WotLK 1=AFFECTING_COMBAT, so Classic failReason=0 now correctly shows an error instead of being silently swallowed. --- src/game/game_handler.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index e9452785..bce39d4a 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -2747,16 +2747,21 @@ void GameHandler::handlePacket(network::Packet& packet) { break; case Opcode::SMSG_SPELL_FAILURE: { // WotLK: packed_guid + uint8 castCount + uint32 spellId + uint8 failReason - // TBC/Classic: full uint64 + uint8 castCount + uint32 spellId + uint8 failReason - const bool tbcOrClassic = isClassicLikeExpansion() || isActiveExpansion("tbc"); - uint64_t failGuid = tbcOrClassic + // TBC: full uint64 + uint8 castCount + uint32 spellId + uint8 failReason + // Classic: full uint64 + uint32 spellId + uint8 failReason (NO castCount) + const bool isClassic = isClassicLikeExpansion(); + const bool isTbc = isActiveExpansion("tbc"); + uint64_t failGuid = (isClassic || isTbc) ? (packet.getSize() - packet.getReadPos() >= 8 ? packet.readUInt64() : 0) : UpdateObjectParser::readPackedGuid(packet); - // Read castCount + spellId + failReason - if (packet.getSize() - packet.getReadPos() >= 6) { - /*uint8_t castCount =*/ packet.readUInt8(); + // Classic omits the castCount byte; TBC and WotLK include it + const size_t remainingFields = isClassic ? 5u : 6u; // spellId(4)+reason(1) [+castCount(1)] + if (packet.getSize() - packet.getReadPos() >= remainingFields) { + if (!isClassic) /*uint8_t castCount =*/ packet.readUInt8(); /*uint32_t spellId =*/ packet.readUInt32(); - uint8_t failReason = packet.readUInt8(); + uint8_t rawFailReason = packet.readUInt8(); + // Classic result enum starts at 0=AFFECTING_COMBAT; shift +1 for WotLK table + uint8_t failReason = isClassic ? static_cast(rawFailReason + 1) : rawFailReason; if (failGuid == playerGuid && failReason != 0) { // Show interruption/failure reason in chat for player int pt = -1;