Files
ShaguTweaks-ClassicAPI/mods/unitframes-classportrait.lua

136 lines
5.1 KiB
Lua

local _G = ShaguTweaks.GetGlobalEnv()
local T = ShaguTweaks.T
local API = ShaguTweaks.API or {}
local addonpath
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in pairs(tocs) do
local current = string.format("ShaguTweaks%s", name)
local _, title = GetAddOnInfo(current)
if title then
addonpath = "Interface\\AddOns\\" .. current
break
end
end
local CLASS_PORTRAIT_TEXTURE = (addonpath or "Interface\\AddOns\\ShaguTweaks") .. "\\img\\UI-Classes-Circles"
local CLASS_ICON_TCOORDS = {
["WARRIOR"] = { 0, 0.25, 0, 0.25 },
["MAGE"] = { 0.25, 0.49609375, 0, 0.25 },
["ROGUE"] = { 0.49609375, 0.7421875, 0, 0.25 },
["DRUID"] = { 0.7421875, 0.98828125, 0, 0.25 },
["HUNTER"] = { 0, 0.25, 0.25, 0.5 },
["SHAMAN"] = { 0.25, 0.49609375, 0.25, 0.5 },
["PRIEST"] = { 0.49609375, 0.7421875, 0.25, 0.5 },
["WARLOCK"] = { 0.7421875, 0.98828125, 0.25, 0.5 },
["PALADIN"] = { 0, 0.25, 0.5, 0.75 },
["DEATHKNIGHT"] = { 0.25, .5, 0.5, .75 },
}
local module = ShaguTweaks:register({
title = T["Unit Frame Class Portraits"],
description = T["Replace unitframe portraits with class icons."],
expansions = { ["vanilla"] = true },
category = T["Unit Frames"],
enabled = nil,
})
local function UpdatePortraits(frame)
if not frame or not frame.unit or not frame.portrait then return end
-- detect unit class or remove for non-player units
local _, class = UnitClass(frame.unit)
class = UnitIsPlayer(frame.unit) and class or nil
-- Reapply after Blizzard's UnitFrame_Update: that function can replace the
-- portrait texture even when the new target has the same class.
if class then
local iconCoords = CLASS_ICON_TCOORDS[class]
if iconCoords then
local wanted = CLASS_PORTRAIT_TEXTURE
if frame.portrait:GetTexture() ~= wanted then frame.portrait:SetTexture(wanted) end
local l, t, l2, b, r, t2, r2, b2 = frame.portrait:GetTexCoord()
if l ~= iconCoords[1] or t ~= iconCoords[3] or l2 ~= iconCoords[1]
or b ~= iconCoords[4] or r ~= iconCoords[2] or t2 ~= iconCoords[3]
or r2 ~= iconCoords[2] or b2 ~= iconCoords[4] then
frame.portrait:SetTexCoord(unpack(iconCoords))
end
end
else
local l, t, l2, b, r, t2, r2, b2 = frame.portrait:GetTexCoord()
if l ~= 0 or t ~= 0 or l2 ~= 0 or b ~= 1 or r ~= 1 or t2 ~= 0 or r2 ~= 1 or b2 ~= 1 then
frame.portrait:SetTexCoord(0, 1, 0, 1)
end
end
end
module.enable = function(self)
-- overwrite portraits set by the game
ShaguTweaks.hooksecurefunc("UnitFrame_Update", function(frame)
UpdatePortraits(type(frame) == "table" and frame.unit and frame or this)
end)
-- handle portrait update events
local events = CreateFrame("Frame")
events:RegisterEvent("PLAYER_ENTERING_WORLD")
events:RegisterEvent("UNIT_PORTRAIT_UPDATE")
local function RefreshFrame(frame)
if not frame or not frame.unit then return end
if event == "PLAYER_ENTERING_WORLD" or frame.unit == arg1
or (arg1 and UnitIsUnit(frame.unit, arg1)) then UpdatePortraits(frame) end
end
events:SetScript("OnEvent", function()
RefreshFrame(PlayerFrame)
RefreshFrame(TargetFrame)
RefreshFrame(PartyMemberFrame1)
RefreshFrame(PartyMemberFrame2)
RefreshFrame(PartyMemberFrame3)
RefreshFrame(PartyMemberFrame4)
end)
-- Turtle/Vanilla already runs TargetofTarget_OnUpdate for the target-of-target
-- frame. Reuse that existing update path instead of adding a second poller.
-- Keep a GUID cache when ClassicAPI is available so two units with the same
-- display name are still detected as different units.
local lasttotguid = nil
if type(TargetofTarget_OnUpdate) == "function" then
local originalTargetofTargetOnUpdate = TargetofTarget_OnUpdate
-- The stock handler replaces the portrait when CURRENT_TARGETTARGET (the
-- target-of-target's name) changes; reapply the class icon in that same
-- frame. A GUID check five times a second covers same-name units and
-- clients whose handler does not track that global, instead of calling
-- UnitGUID on every frame.
local totelapsed = 0
TargetofTarget_OnUpdate = function(elapsed)
local before = CURRENT_TARGETTARGET
originalTargetofTargetOnUpdate(elapsed)
totelapsed = totelapsed + (elapsed or arg1 or 0)
if CURRENT_TARGETTARGET == before and totelapsed < .2 then return end
totelapsed = 0
local guid = API.UnitGUID and API.UnitGUID("targettarget") or UnitName("targettarget")
if guid ~= lasttotguid or CURRENT_TARGETTARGET ~= before then
lasttotguid = guid
UpdatePortraits(TargetofTargetFrame)
end
end
else
-- Compatibility fallback for clients that do not expose the stock handler.
local tot = CreateFrame("Frame", nil, TargetFrame)
tot.elapsed = 0
tot:SetScript("OnUpdate", function()
this.elapsed = this.elapsed + arg1
if this.elapsed < .2 then return end
this.elapsed = 0
local guid = API.UnitGUID and API.UnitGUID("targettarget") or UnitName("targettarget")
if guid ~= lasttotguid then
lasttotguid = guid
UpdatePortraits(TargetofTargetFrame)
end
end)
end
end