From 77ce54833aec5d087317a3a331fd3487f961fc20 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 00:29:35 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20add=20quest=20kill=20objective=20indica?= =?UTF-8?q?tor=20(=E2=9A=94)=20to=20unit=20nameplates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yellow crossed-swords icon appears to the right of the unit name when the creature's entry is an incomplete kill objective in a tracked quest. Updated icon is suppressed once the kill count is satisfied. Uses unit->getEntry() (Unit subclass method) rather than the base Entity pointer, matching how questKillEntries keys are stored. --- src/ui/game_screen.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 663a031a..3bfa4b83 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -5242,6 +5242,27 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) { const uint64_t playerGuid = gameHandler.getPlayerGuid(); const uint64_t targetGuid = gameHandler.getTargetGuid(); + // Build set of creature entries that are kill objectives in active (incomplete) quests. + std::unordered_set questKillEntries; + { + const auto& questLog = gameHandler.getQuestLog(); + const auto& trackedIds = gameHandler.getTrackedQuestIds(); + for (const auto& q : questLog) { + if (q.complete || q.questId == 0) continue; + // Only highlight for tracked quests (or all if nothing tracked). + if (!trackedIds.empty() && !trackedIds.count(q.questId)) continue; + for (const auto& obj : q.killObjectives) { + if (obj.npcOrGoId > 0 && obj.required > 0) { + // Check if not already completed. + auto it = q.killCounts.find(static_cast(obj.npcOrGoId)); + if (it == q.killCounts.end() || it->second.first < it->second.second) { + questKillEntries.insert(static_cast(obj.npcOrGoId)); + } + } + } + } + } + ImDrawList* drawList = ImGui::GetBackgroundDrawList(); for (const auto& [guid, entityPtr] : gameHandler.getEntityManager().getEntities()) { @@ -5367,6 +5388,14 @@ void GameScreen::renderNameplates(game::GameHandler& gameHandler) { drawList->AddText(ImVec2(markX + 1.0f, nameY + 1.0f), IM_COL32(0,0,0,120), kNPMarks[raidMark].sym); drawList->AddText(ImVec2(markX, nameY), kNPMarks[raidMark].col, kNPMarks[raidMark].sym); } + + // Quest kill objective indicator: small yellow sword icon to the right of the name + if (!isPlayer && questKillEntries.count(unit->getEntry())) { + const char* objSym = "\xe2\x9a\x94"; // ⚔ crossed swords (UTF-8) + float objX = nameX + textSize.x + 4.0f; + drawList->AddText(ImVec2(objX + 1.0f, nameY + 1.0f), IM_COL32(0, 0, 0, A(160)), objSym); + drawList->AddText(ImVec2(objX, nameY), IM_COL32(255, 220, 0, A(230)), objSym); + } } // Click to target: detect left-click inside the combined nameplate region