From d68bb5a831498358dc3ab5f9c8beaff064402620 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 28 Mar 2026 16:51:23 -0700 Subject: [PATCH] fix: spell facing used atan2(dy,dx) but canonical convention is atan2(-dy,dx) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canonical yaw convention (documented in coordinates.hpp) is atan2(-dy, dx) where X=north, Y=west. North=0, East=+PI/2. The spell facing code used atan2(dy, dx) (no negation on dy), producing a yaw ~77° off from the correct server orientation. The server rejected every cast with "unit not in front" because the sent orientation pointed in the wrong direction. Fixed in all 3 locations: charge facing, melee facing, and general pre-cast facing. --- src/game/spell_handler.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/game/spell_handler.cpp b/src/game/spell_handler.cpp index 70a3b919..65a20491 100644 --- a/src/game/spell_handler.cpp +++ b/src/game/spell_handler.cpp @@ -267,7 +267,7 @@ void SpellHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { return; } // Face the target before sending the cast packet - float yaw = std::atan2(dy, dx); + float yaw = std::atan2(-dy, dx); owner_.movementInfo.orientation = yaw; owner_.sendMovement(Opcode::MSG_MOVE_SET_FACING); if (owner_.chargeCallback_) { @@ -294,7 +294,7 @@ void SpellHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { owner_.addSystemChatMessage("Out of range."); return; } - float yaw = std::atan2(dy, dx); + float yaw = std::atan2(-dy, dx); owner_.movementInfo.orientation = yaw; owner_.sendMovement(Opcode::MSG_MOVE_SET_FACING); } @@ -311,13 +311,9 @@ void SpellHandler::castSpell(uint32_t spellId, uint64_t targetGuid) { float dy = entity->getY() - owner_.movementInfo.y; float lenSq = dx * dx + dy * dy; if (lenSq > 0.01f) { - float canonYaw = std::atan2(dy, dx); - float serverYaw = core::coords::canonicalToServerYaw(canonYaw); + // Canonical yaw convention: atan2(-dy, dx) where X=north, Y=west + float canonYaw = std::atan2(-dy, dx); owner_.movementInfo.orientation = canonYaw; - LOG_WARNING("Pre-cast facing: target=(", entity->getX(), ",", entity->getY(), - ") me=(", owner_.movementInfo.x, ",", owner_.movementInfo.y, - ") canonYaw=", canonYaw, " serverYaw=", serverYaw, - " dx=", dx, " dy=", dy); owner_.sendMovement(Opcode::MSG_MOVE_SET_FACING); owner_.sendMovement(Opcode::MSG_MOVE_HEARTBEAT); }