From 022d387d954e5cf521a6dbf13d012640c79e9b18 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 13 Mar 2026 00:59:43 -0700 Subject: [PATCH] fix: correct corpse retrieval coordinate mismatch and detect corpse objects - canReclaimCorpse() and getCorpseDistance() compared canonical movementInfo (x=north=server_y, y=west=server_x) against raw server corpseX_/Y_ causing the proximity check to always report wrong distance even when standing on corpse - Fix: use corpseY_ for canonical north and corpseX_ for canonical west - Also detect OBJECT_TYPE_CORPSE update blocks owned by the player to set corpse coordinates at login-as-ghost (before SMSG_DEATH_RELEASE_LOC arrives) --- include/game/game_handler.hpp | 6 ++++-- src/game/game_handler.cpp | 29 ++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 08311cb2..e0baba9e 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1106,8 +1106,10 @@ public: /** Distance (yards) from ghost to corpse, or -1 if no corpse data. */ float getCorpseDistance() const { if (corpseMapId_ == 0 || currentMapId_ != corpseMapId_) return -1.0f; - float dx = movementInfo.x - corpseX_; - float dy = movementInfo.y - corpseY_; + // movementInfo is canonical (x=north=server_y, y=west=server_x); + // corpse coords are raw server (x=west, y=north) — swap to compare. + float dx = movementInfo.x - corpseY_; + float dy = movementInfo.y - corpseX_; float dz = movementInfo.z - corpseZ_; return std::sqrt(dx*dx + dy*dy + dz*dz); } diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 0f8a5c7f..eee30296 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -10046,6 +10046,27 @@ void GameHandler::handleUpdateObject(network::Packet& packet) { go->getX(), go->getY(), go->getZ(), go->getOrientation()); } } + // Detect player's own corpse object so we have the position even when + // SMSG_DEATH_RELEASE_LOC hasn't been received (e.g. login as ghost). + if (block.objectType == ObjectType::CORPSE && block.hasMovement) { + // CORPSE_FIELD_OWNER is at index 6 (uint64, low word at 6, high at 7) + uint16_t ownerLowIdx = 6; + auto ownerLowIt = block.fields.find(ownerLowIdx); + uint32_t ownerLow = (ownerLowIt != block.fields.end()) ? ownerLowIt->second : 0; + auto ownerHighIt = block.fields.find(ownerLowIdx + 1); + uint32_t ownerHigh = (ownerHighIt != block.fields.end()) ? ownerHighIt->second : 0; + uint64_t ownerGuid = (static_cast(ownerHigh) << 32) | ownerLow; + if (ownerGuid == playerGuid || ownerLow == static_cast(playerGuid)) { + // Server coords from movement block + corpseX_ = block.x; + corpseY_ = block.y; + corpseZ_ = block.z; + corpseMapId_ = currentMapId_; + LOG_INFO("Corpse object detected: server=(", block.x, ", ", block.y, ", ", block.z, + ") map=", corpseMapId_); + } + } + // Track online item objects (CONTAINER = bags, also tracked as items) if (block.objectType == ObjectType::ITEM || block.objectType == ObjectType::CONTAINER) { auto entryIt = block.fields.find(fieldIndex(UF::OBJECT_FIELD_ENTRY)); @@ -12192,9 +12213,11 @@ bool GameHandler::canReclaimCorpse() const { if (!releasedSpirit_ || corpseMapId_ == 0) return false; // Only if ghost is on the same map as their corpse if (currentMapId_ != corpseMapId_) return false; - // Must be within 40 yards (server also validates proximity) - float dx = movementInfo.x - corpseX_; - float dy = movementInfo.y - corpseY_; + // movementInfo.x/y are canonical (x=north=server_y, y=west=server_x). + // corpseX_/Y_ are raw server coords (x=west, y=north). + // Convert corpse to canonical before comparing. + float dx = movementInfo.x - corpseY_; // canonical north - server.y + float dy = movementInfo.y - corpseX_; // canonical west - server.x float dz = movementInfo.z - corpseZ_; return (dx*dx + dy*dy + dz*dz) <= (40.0f * 40.0f); }