From d0df6eed2cf06528695c195c47ff402231f2bb76 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Mar 2026 19:52:17 -0700 Subject: [PATCH] feat: show corpse skull marker on world map when player is a ghost When the player dies and releases spirit, the world map now renders a bone-white X cross at the corpse's location (matching the existing minimap skull marker). The marker appears only when the player is a ghost with an unclaimed corpse on the same map, and shows a "Your corpse" tooltip on hover. Implemented via setCorpsePos() on WorldMap, called from renderWorldMap() using getCorpseCanonicalPos(). --- include/rendering/world_map.hpp | 11 +++++++++++ src/rendering/world_map.cpp | 27 +++++++++++++++++++++++++++ src/ui/game_screen.cpp | 11 +++++++++++ 3 files changed, 49 insertions(+) diff --git a/include/rendering/world_map.hpp b/include/rendering/world_map.hpp index cfbf5595..eedc88af 100644 --- a/include/rendering/world_map.hpp +++ b/include/rendering/world_map.hpp @@ -67,6 +67,13 @@ public: void setServerExplorationMask(const std::vector& masks, bool hasData); void setPartyDots(std::vector dots) { partyDots_ = std::move(dots); } void setTaxiNodes(std::vector nodes) { taxiNodes_ = std::move(nodes); } + /// Set the player's corpse position for overlay rendering. + /// @param hasCorpse True when the player is a ghost with an unclaimed corpse on this map. + /// @param renderPos Corpse position in render-space coordinates. + void setCorpsePos(bool hasCorpse, glm::vec3 renderPos) { + hasCorpse_ = hasCorpse; + corpseRenderPos_ = renderPos; + } bool isOpen() const { return open; } void close() { open = false; } @@ -141,6 +148,10 @@ private: std::vector taxiNodes_; int currentMapId_ = -1; ///< WoW map ID currently loaded (set in loadZonesFromDBC) + // Corpse marker (ghost state — set each frame from the UI layer) + bool hasCorpse_ = false; + glm::vec3 corpseRenderPos_ = {}; + // Exploration / fog of war std::vector serverExplorationMask; bool hasServerExplorationMask = false; diff --git a/src/rendering/world_map.cpp b/src/rendering/world_map.cpp index 2257ded9..cc278b5f 100644 --- a/src/rendering/world_map.cpp +++ b/src/rendering/world_map.cpp @@ -1096,6 +1096,33 @@ void WorldMap::renderImGuiOverlay(const glm::vec3& playerRenderPos, int screenWi } } + // Corpse marker — skull X shown when player is a ghost with unclaimed corpse + if (hasCorpse_ && currentIdx >= 0 && viewLevel != ViewLevel::WORLD) { + glm::vec2 uv = renderPosToMapUV(corpseRenderPos_, currentIdx); + if (uv.x >= 0.0f && uv.x <= 1.0f && uv.y >= 0.0f && uv.y <= 1.0f) { + float cx = imgMin.x + uv.x * displayW; + float cy = imgMin.y + uv.y * displayH; + constexpr float R = 5.0f; // cross arm half-length + constexpr float T = 1.8f; // line thickness + // Dark outline + drawList->AddLine(ImVec2(cx - R, cy - R), ImVec2(cx + R, cy + R), + IM_COL32(0, 0, 0, 220), T + 1.5f); + drawList->AddLine(ImVec2(cx + R, cy - R), ImVec2(cx - R, cy + R), + IM_COL32(0, 0, 0, 220), T + 1.5f); + // Bone-white X + drawList->AddLine(ImVec2(cx - R, cy - R), ImVec2(cx + R, cy + R), + IM_COL32(230, 220, 200, 240), T); + drawList->AddLine(ImVec2(cx + R, cy - R), ImVec2(cx - R, cy + R), + IM_COL32(230, 220, 200, 240), T); + // Tooltip on hover + ImVec2 mp = ImGui::GetMousePos(); + float dx = mp.x - cx, dy = mp.y - cy; + if (dx * dx + dy * dy < 64.0f) { + ImGui::SetTooltip("Your corpse"); + } + } + } + // Hover coordinate display — show WoW coordinates under cursor if (currentIdx >= 0 && viewLevel != ViewLevel::WORLD) { auto& io = ImGui::GetIO(); diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 73abfda6..a580fab3 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -7083,6 +7083,17 @@ void GameScreen::renderWorldMap(game::GameHandler& gameHandler) { wm->setTaxiNodes(std::move(taxiNodes)); } + // Corpse marker: show skull X on world map when ghost with unclaimed corpse + { + float corpseCanX = 0.0f, corpseCanY = 0.0f; + bool ghostWithCorpse = gameHandler.isPlayerGhost() && + gameHandler.getCorpseCanonicalPos(corpseCanX, corpseCanY); + glm::vec3 corpseRender = ghostWithCorpse + ? core::coords::canonicalToRender(glm::vec3(corpseCanX, corpseCanY, 0.0f)) + : glm::vec3{}; + wm->setCorpsePos(ghostWithCorpse, corpseRender); + } + glm::vec3 playerPos = renderer->getCharacterPosition(); float playerYaw = renderer->getCharacterYaw(); auto* window = app.getWindow();