Files
Questie-X/Modules/QuestieNameplate.lua
T

306 lines
9.5 KiB
Lua

---@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<string, 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