From d2c36a4a9532da473d907946130027dfc3784350 Mon Sep 17 00:00:00 2001 From: Xurkon Date: Wed, 10 Jun 2026 21:46:18 -0500 Subject: [PATCH] fix(learner): kills never recorded coords (credited used before assignment) The kill handler's position capture ran inside 'if credited then', but credited was read before its 'local credited = ...' assignment a few lines below, so it was always nil and px,py were never captured -- every killed NPC stayed spawnSource='fallback' with no [7] and drew no learner pins regardless of kill count. Move the credited computation above the capture and nil-guard a 0,0 position. GetPlayerCoords now uses the robust GetCurrentPlayerPosition (Sunstrider-corrected), returning nil when invalid so no 0,0 pins are recorded. Reverts the earlier HBD GetPlayerCoords approach which treated the wrong symptom and caused spurious pins. --- CHANGELOG.md | 2 +- Modules/QuestieLearner.lua | 44 ++++++++++++++++---------------------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 249b20d..bc6c1b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,7 @@ ### Bug Fixes - **[Map - Quest-Type Filters Now Truly Apply To The Minimap]** (#11) Filtered quest types (e.g. dungeon quests) could still show on the minimap while correctly hidden on the world map. The previous fix made the minimap `FadeLogic` re-check `ShouldBeHidden` only when deciding whether to *re-show* an already-hidden icon — so an icon that was already visible (or that HBD's pin renderer showed on coming into range) was never hidden. `FadeLogic` now proactively calls `ShouldBeHidden` for every in-range minimap icon and `FakeHide`s it when filtered, in both minimap fade paths (quest icons and townsfolk/manual icons). The same path also picked up the #17 minimap-radius cutoff gating it was missing. -- **[Learner - Capture Spawn Coordinates Reliably (Fixes Disappearing Pins)]** The learner's `GetPlayerCoords` used the raw `GetPlayerMapPosition("player")`, which returns `0,0` whenever the world map isn't set to the player's current zone (the usual case — the map is closed or showing another zone) and mis-reports on Ascension subzones like Sunstrider Isle. So kill/mouseover learn events captured no position: NPCs were saved with `spawnSource="fallback"` and no `[7]` spawns, and in learner-only mode their pins never persisted (showing only briefly after a live kill, then disappearing on the next redraw/reload). It now reads position from `HBD:GetPlayerZonePosition()` — the robust `SetMapToCurrentZone()`/Sunstrider-corrected path, cached for cheap per-kill calls — falling back to the old API only if HBD is unavailable. Newly encountered mobs now record real coordinates so their learner pins persist. +- **[Learner - Kills Never Recorded Spawn Coordinates]** The combat-log kill handler computed the player's spawn position inside `if credited then ... end`, but `credited` was read **before** it was assigned (the `local credited = ...` came several lines later), so it was always `nil` — the position-capture block never ran. Every killed NPC was saved with `spawnSource="fallback"` and no `[7]` spawns regardless of kill count, so in learner-only mode their pins never appeared (and re-killing didn't help). Moved the `credited` computation above the position capture, and guard against a `0,0` position being stored. The learner's `GetPlayerCoords` (used by quest-giver/object learning) also now uses the robust `QuestieCompat.GetCurrentPlayerPosition()` (handles `SetMapToCurrentZone` and the Sunstrider parent/child coordinate correction) instead of the raw `GetPlayerMapPosition`, returning `nil` when no valid position exists so no `0,0` pins are recorded. Newly killed mobs now record real coordinates and their learner pins persist. - **[Map - Minimap Icon Pixel Snapping At Fractional Scales]** (#6) Minimap quest icons are now snapped to the physical pixel grid when positioned. At fractional UI scales (e.g. a 0.71 game scale combined with Windows display scaling) the raw fractional offset placed icons between physical pixels, making them render blurry and visibly offset from the engine-drawn native quest blips. Rounding the pin offset to a whole physical pixel (via the minimap's effective scale) keeps Questie's icons on the same grid as the native markers, improving alignment at non-integer scales. - **[Map - Hide Callboard Quests: Robust Board Detection]** (#10) The "hide repeatable quests below level 60" option only hid quests flagged repeatable in the DB, but Ascension's Call Board / Contract Board bounties (e.g. NPC 24 "Outlaw's Contract Board") aren't reliably flagged repeatable, so their `!` markers still showed. Added `QuestieDB.IsBoardQuest(questId)` which detects these by their starter NPC/object name containing "board" (cached per quest), and the hide-below-60 option now hides a quest when it is repeatable **or** a board quest — closing the gap in both the available-quest draw path and the icon visibility check. - **[Tooltip - ElvUI Style No Longer On By Default]** (#16) The "ElvUI tooltip style" option shipped enabled by default, so Questie restyled every default WoW tooltip — stripping the border — for users who never asked for it and don't run ElvUI. It is now opt-in (default off), and a one-time migration resets it off for existing installs so their default tooltips return. Users who want the flat style can re-enable it in the General tab. diff --git a/Modules/QuestieLearner.lua b/Modules/QuestieLearner.lua index 1779a3b..45aad38 100644 --- a/Modules/QuestieLearner.lua +++ b/Modules/QuestieLearner.lua @@ -13,8 +13,6 @@ local QuestLogCache = QuestieLoader:ImportModule("QuestLogCache") local l10n = QuestieLoader:ImportModule("l10n") ---@type ZoneDB local ZoneDB = QuestieLoader:ImportModule("ZoneDB") ----@type HBD -local HBD = (QuestieCompat and QuestieCompat.HBD) or (LibStub and LibStub("HereBeDragonsQuestie-2.0", true)) local _Learner = QuestieLearner.private or {} @@ -289,25 +287,14 @@ local function GetZoneId() end local function GetPlayerCoords() - -- Prefer HBD's cached zone position. The raw GetPlayerMapPosition("player") returns 0,0 - -- whenever the world map isn't set to the player's current zone (the common case — the map - -- is usually closed or showing another zone), and it also mis-reports on Ascension subzones - -- like Sunstrider Isle. That made kill/learn events fall back with NO coordinates, so learned - -- NPCs were saved as spawnSource="fallback" with no [7] spawns and their pins never persisted. - -- HBD:GetPlayerZonePosition() goes through QuestieCompat.GetCurrentPlayerPosition(), which - -- runs SetMapToCurrentZone() and corrects the Sunstrider parent/child coordinate-space - -- mismatch, and it caches the result so it is cheap to call on every kill. - if HBD and HBD.GetPlayerZonePosition then - local zx, zy = HBD:GetPlayerZonePosition() - if zx and zy and zx > 0 and zy > 0 then - -- HBD returns 0–1; store in 0–100 scale, 2-decimal precision. - return floor(zx * 10000) / 100, floor(zy * 10000) / 100 - end - end - - local x, y = GetPlayerMapPosition("player") + -- Use the robust position helper (handles SetMapToCurrentZone and the Sunstrider + -- parent/child coordinate-space correction) rather than the raw GetPlayerMapPosition, + -- which returns 0,0 whenever the world map isn't set to the player's zone. Returns nil + -- when no valid position is available so callers that record the player's location as a + -- spawn (mouseover quest-givers, object use) simply skip rather than logging a 0,0 pin. + local _mapId, x, y = QuestieCompat.GetCurrentPlayerPosition() if x and y and x > 0 and y > 0 then - -- Store in 0–100 scale, 2-decimal precision + -- Native APIs return 0–1; store in 0–100 scale, 2-decimal precision. return floor(x * 10000) / 100, floor(y * 10000) / 100 end return nil, nil @@ -4203,6 +4190,15 @@ function QuestieLearner:OnCombatLogEvent(timestamp, eventType, srcGUID, srcName, if not npcId or npcId <= 0 then return end + -- Determine whether this kill is "credited" to us (our own/party kill we engaged) + -- BEFORE using it to decide whether to record our position. This MUST come first: + -- previously `credited` was read while still nil (defined further below), so the + -- position-capture block never ran and kills never recorded any spawn coordinates — + -- every killed NPC stayed spawnSource="fallback" with no [7] and drew no learner pins. + local engagedTs = _Learner.playerEngaged and _Learner.playerEngaged[dstGUID] + local credited = (eventType == "PARTY_KILL") + or (engagedTs ~= nil and (now - engagedTs) <= 60) + -- Only record YOUR position for the spawn. GetCurrentPlayerPosition() -- returns the local player's coords, not the killer's — so for -- party/raid kills where someone else landed the killing blow we @@ -4213,16 +4209,12 @@ function QuestieLearner:OnCombatLogEvent(timestamp, eventType, srcGUID, srcName, if px and py and px > 0 and py > 0 then px = floor(px * 10000) / 100 py = floor(py * 10000) / 100 + else + px, py = nil, nil end end local zoneId = GetZoneId() local zoneText = GetRealZoneText and GetRealZoneText() or "" - -- Keep the credited flag for quest-progress correlation, but do not use it - -- to suppress learning. The learner should still harvest kill data from - -- nearby players so static import coverage stays as complete as possible. - local engagedTs = _Learner.playerEngaged and _Learner.playerEngaged[dstGUID] - local credited = (eventType == "PARTY_KILL") - or (engagedTs ~= nil and (now - engagedTs) <= 60) _Learner.recentKills[dstGUID] = { npcId = npcId, name = name or "",