---@class QuestieNameplate local QuestieNameplate = QuestieLoader:CreateModule("QuestieNameplate") local _QuestieNameplate = QuestieNameplate.private ------------------------- --Import modules. ------------------------- ---@type QuestieTooltips local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips") --- COMPATIBILITY --- local UnitGUID = QuestieCompat.UnitGUID local activeGUIDs = {} local npFrames = {} local npUnusedFrames = {} local npFramesCount = 0 local activeTargetFrame -- Not used function QuestieNameplate:Initialize() -- Nothing to initialize end ---@param token string function QuestieNameplate:NameplateCreated(token) Questie:Debug(Questie.DEBUG_SPAM, "[QuestieNameplate:NameplateCreated]") -- if nameplates are disabled, don't create new nameplates. if (not Questie.db.profile.nameplateEnabled) then return end -- to avoid memory issues if npFramesCount >= 300 then return end local unitGUID = UnitGUID(token) local unitName, _ = UnitName(token) if (not unitGUID) or (not unitName) then return end local unitType, _, _, _, _, npcId, _ = strsplit("-", unitGUID) if unitType ~= "Creature" and unitType ~= "Vehicle" then -- We only draw name plates on NPCs/creatures and Vehicles (oddness with Chillmaw being a Vehicle?!?!) and skip players, pets, etc return end local icon = _QuestieNameplate.GetValidIcon(QuestieTooltips.lookupByKey["m_" .. npcId]) if icon then activeGUIDs[unitGUID] = token local f = _QuestieNameplate.GetFrame(unitGUID) f.Icon:SetTexture(icon) f.lastIcon = icon -- this is used to prevent updating the texture when it's already what it needs to be f:Show() end end ---@param token string function QuestieNameplate:NameplateDestroyed(token) Questie:Debug(Questie.DEBUG_SPAM, "[QuestieNameplate:NameplateDestroyed]") if (not Questie.db.profile.nameplateEnabled) then return end local unitGUID = UnitGUID(token) if unitGUID and activeGUIDs[unitGUID] then activeGUIDs[unitGUID] = nil _QuestieNameplate.RemoveFrame(unitGUID) end end function QuestieNameplate:UpdateNameplate() Questie:Debug(Questie.DEBUG_SPAM, "[QuestieNameplate:UpdateNameplate]") for guid, token in pairs(activeGUIDs) do local unitName, _ = UnitName(token) local _, _, _, _, _, npcId, _ = strsplit("-", guid) if (not unitName) or (not npcId) then return end local icon = _QuestieNameplate.GetValidIcon(QuestieTooltips.lookupByKey["m_" .. npcId]) if icon then local frame = _QuestieNameplate.GetFrame(guid) -- check if the texture needs to be changed if frame.lastIcon ~= icon then frame.lastIcon = icon frame.Icon:SetTexture(icon) end else -- tooltip removed but we still have the frame active, remove it activeGUIDs[guid] = nil _QuestieNameplate.RemoveFrame(guid) end end end function QuestieNameplate:RedrawIcons() for _, frame in pairs(npFrames) do local iconScale = Questie.db.profile.nameplateScale frame:SetPoint("LEFT", Questie.db.profile.nameplateX, Questie.db.profile.nameplateY) frame:SetWidth(16 * iconScale) frame:SetHeight(16 * iconScale) end end function QuestieNameplate:HideCurrentFrames() for guid, _ in pairs(activeGUIDs) do activeGUIDs[guid] = nil _QuestieNameplate.RemoveFrame(guid) end end function QuestieNameplate:DrawTargetFrame() Questie:Debug(Questie.DEBUG_SPAM, "[QuestieNameplate:DrawTargetFrame]") if (not Questie.db.profile.nameplateTargetFrameEnabled) then return end -- always remove the previous frame if it exists if activeTargetFrame ~= nil then activeTargetFrame.Icon:SetTexture(nil) activeTargetFrame:Hide() end local unitGUID = UnitGUID("target") local unitName = UnitName("target") if (not unitName) or (not unitGUID) then -- We need the GUID and name, this should not happen return end local unitType, _, _, _, _, npcId, _ = strsplit("-", unitGUID) if unitType ~= "Creature" and unitType ~= "Vehicle" then -- We only draw name plates on NPCs/creatures and Vehicles (oddness with Chillmaw being a Vehicle?!?!) and skip players, pets, etc return end local icon = _QuestieNameplate.GetValidIcon(QuestieTooltips.lookupByKey["m_" .. npcId]) if (not icon) then return end if not activeTargetFrame then activeTargetFrame = _QuestieNameplate.GetTargetFrameIconFrame() end activeTargetFrame.Icon:SetTexture(icon) activeTargetFrame:Show() end function QuestieNameplate:HideCurrentTargetFrame() if (not activeTargetFrame) then return end activeTargetFrame.Icon:SetTexture(nil) activeTargetFrame:Hide() activeTargetFrame = nil end function QuestieNameplate:RedrawFrameIcon() if (not Questie.db.profile.nameplateTargetFrameEnabled) or (not activeTargetFrame) then return end local iconScale = Questie.db.profile.nameplateTargetFrameScale activeTargetFrame:SetWidth(16 * iconScale) activeTargetFrame:SetHeight(16 * iconScale) activeTargetFrame:SetPoint("RIGHT", Questie.db.profile.nameplateTargetFrameX, Questie.db.profile.nameplateTargetFrameY) end ---@param guid string function _QuestieNameplate.GetFrame(guid) if npFrames[guid] then return npFrames[guid] end local parent = QuestieCompat.Is335 and guid or C_NamePlate.GetNamePlateForUnit(activeGUIDs[guid]) local frame = tremove(npUnusedFrames) if (not frame) then frame = CreateFrame("Frame") npFramesCount = npFramesCount + 1 end local iconScale = Questie.db.profile.nameplateScale frame:SetFrameStrata("LOW") frame:SetFrameLevel(10) frame:SetWidth(16 * iconScale) frame:SetHeight(16 * iconScale) frame:EnableMouse(false) frame:SetParent(parent) frame:SetPoint("LEFT", Questie.db.profile.nameplateX, Questie.db.profile.nameplateY) frame.Icon = frame.Icon or frame:CreateTexture(nil, "ARTWORK") frame.Icon:ClearAllPoints() frame.Icon:SetAllPoints(frame) npFrames[guid] = frame return frame end function _QuestieNameplate.GetTargetFrameIconFrame() local frame = CreateFrame("Frame") local iconScale = Questie.db.profile.nameplateTargetFrameScale local strata = "MEDIUM" local targetFrame = TargetFrame -- Default Blizzard target frame if ElvUF_Target then targetFrame = ElvUF_Target strata = "LOW" elseif PitBull4_Frames_Target then targetFrame = PitBull4_Frames_Target elseif AzeriteUnitFrameTarget then targetFrame = AzeriteUnitFrameTarget strata = "LOW" elseif GwTargetUnitFrame then targetFrame = GwTargetUnitFrame strata = "LOW" elseif SUFUnittarget then targetFrame = SUFUnittarget frame:SetFrameLevel(SUFUnittarget:GetFrameLevel() + 1) end frame:SetParent(targetFrame) frame:SetFrameStrata(strata) frame:SetFrameLevel(11) frame:SetWidth(16 * iconScale) frame:SetHeight(16 * iconScale) frame:EnableMouse(false) frame:SetPoint("RIGHT", Questie.db.profile.nameplateTargetFrameX, Questie.db.profile.nameplateTargetFrameY) frame.Icon = frame:CreateTexture(nil, "ARTWORK") frame.Icon:ClearAllPoints() frame.Icon:SetAllPoints(frame) return frame end ---@param guid string function _QuestieNameplate.RemoveFrame(guid) if (not npFrames[guid]) then return end table.insert(npUnusedFrames, npFrames[guid]) npFrames[guid].Icon:SetTexture(nil) -- fix for overlapping icons npFrames[guid]:Hide() npFrames[guid] = nil end ---@param tooltips table function _QuestieNameplate.GetValidIcon(tooltips) -- helper function to get the first valid (incomplete) icon from the specified tooltip, or nil if there is none if (not tooltips) then return end for _, tooltip in pairs(tooltips) do if tooltip.objective and tooltip.objective.Update then tooltip.objective:Update() -- get latest qlog data if its outdated if (not tooltip.objective.Completed) and tooltip.objective.Icon then -- If the tooltip icon is Questie.ICON_TYPE_OBJECT we use Questie.ICON_TYPE_LOOT because NPCs should never show -- a cogwheel icon. local iconType = tooltip.objective.Icon if iconType == Questie.ICON_TYPE_OBJECT or iconType == Questie.ICON_TYPE_LOOT then return Questie.icons["loot"] elseif iconType == Questie.ICON_TYPE_SLAY then return Questie.icons["slay"] elseif iconType == Questie.ICON_TYPE_EVENT then return Questie.icons["event"] elseif iconType == Questie.ICON_TYPE_TALK then return Questie.icons["talk"] --? icon types below here are never reached or just not used on nameplates ? elseif iconType == Questie.ICON_TYPE_AVAILABLE or iconType == Questie.ICON_TYPE_AVAILABLE_GRAY then return Questie.icons["available"] elseif iconType == Questie.ICON_TYPE_REPEATABLE then return Questie.icons["repeatable"] elseif iconType == Questie.ICON_TYPE_COMPLETE then return Questie.icons["complete"] end end end end end