mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-23 12:30:50 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60f953178f | ||
|
|
1dc10964a2 | ||
|
|
0fc08e77c0 | ||
|
|
7f3795b45b | ||
|
|
8eee766652 | ||
|
|
2b5288a688 | ||
|
|
daba4e202e | ||
|
|
98c7751416 | ||
|
|
8796fab6d8 | ||
|
|
7ca0e40d8b | ||
|
|
2f93b246a1 | ||
|
|
c647698f8f | ||
|
|
48026008b6 | ||
|
|
c1d96bae58 | ||
|
|
1d44c5ec6f | ||
|
|
8f88dfd852 | ||
|
|
a57214aeb0 | ||
|
|
9bde843e33 | ||
|
|
ad13e6ace3 |
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"runtime": {
|
||||
"version": "Lua 5.1"
|
||||
},
|
||||
"diagnostics": {
|
||||
"disable": ["deprecated"],
|
||||
"globals": [
|
||||
"this",
|
||||
"event",
|
||||
"arg",
|
||||
"arg1",
|
||||
"arg2",
|
||||
"arg3",
|
||||
"arg4",
|
||||
"arg5",
|
||||
"arg6",
|
||||
"arg7",
|
||||
"arg8",
|
||||
"arg9"
|
||||
]
|
||||
}
|
||||
}
|
||||
+66
-53
@@ -1638,39 +1638,40 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
for i=1, unit.config.bufflimit do
|
||||
if not unit.buffs[i] then break end
|
||||
|
||||
local aura = C_UnitAuras.GetBuffDataByIndex(unitstr, i)
|
||||
-- positional UnitBuff allocates nothing (vs a table per icon per refresh)
|
||||
local name, icon, count, _, duration, expirationTime, _, _, _, spellId = C_UnitAuras.UnitBuff(unitstr, i)
|
||||
|
||||
if aura then
|
||||
unit.buffs[i].texture:SetTexture(aura.icon)
|
||||
if name then
|
||||
unit.buffs[i].texture:SetTexture(icon)
|
||||
unit.buffs[i]:Show()
|
||||
|
||||
if aura.applications > 1 then
|
||||
unit.buffs[i].stacks:SetText(aura.applications)
|
||||
if count > 1 then
|
||||
unit.buffs[i].stacks:SetText(count)
|
||||
else
|
||||
unit.buffs[i].stacks:SetText("")
|
||||
end
|
||||
|
||||
if aura.expirationTime > 0 then
|
||||
if expirationTime > 0 then
|
||||
-- pfUI's cooldown text falls into a 2^32 wraparound branch when start > GetTime(),
|
||||
-- which happens for talent-extended buffs where the real duration exceeds aura.duration
|
||||
-- (the Spell.dbc base). Anchor start to now in that case to keep the remaining math sane.
|
||||
-- which happens for talent-extended buffs where the real duration exceeds the
|
||||
-- Spell.dbc base. Anchor start to now in that case to keep the remaining math sane.
|
||||
local now = GetTime()
|
||||
local start = aura.expirationTime - aura.duration
|
||||
local duration = aura.duration
|
||||
if start > now or duration <= 0 then
|
||||
start, duration = now, aura.expirationTime - now
|
||||
local start = expirationTime - duration
|
||||
local dur = duration
|
||||
if start > now or dur <= 0 then
|
||||
start, dur = now, expirationTime - now
|
||||
end
|
||||
if duration > 0 then
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, start, duration, 1)
|
||||
if dur > 0 then
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, start, dur, 1)
|
||||
else
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
||||
end
|
||||
elseif aura.duration > 0 then
|
||||
elseif duration > 0 then
|
||||
local guid = UnitGUID(unitstr)
|
||||
local guidStarts = guid and pfUI.uf.aura_starts[guid]
|
||||
local start = guidStarts and guidStarts[aura.spellId]
|
||||
local start = guidStarts and guidStarts[spellId]
|
||||
if start then
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, start, aura.duration, 1)
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, start, duration, 1)
|
||||
else
|
||||
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
||||
end
|
||||
@@ -1741,10 +1742,11 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
-- selfdebuff narrows to player-cast harmful auras via the PLAYER filter.
|
||||
-- Player-frame debuffs aren't gated on it (it'd hide most party-applied
|
||||
-- effects on you).
|
||||
local filter = (unit.label ~= "player" and selfdebuff == "1") and "HARMFUL|PLAYER" or "HARMFUL"
|
||||
local aura = C_UnitAuras.GetAuraDataByIndex(unitstr, i, filter)
|
||||
if aura then
|
||||
texture, stacks, dtype = aura.icon, aura.applications, aura.dispelName
|
||||
-- positional UnitDebuff allocates nothing; PLAYER predicate honored for selfdebuff
|
||||
local filter = (unit.label ~= "player" and selfdebuff == "1") and "PLAYER" or nil
|
||||
local name, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitDebuff(unitstr, i, filter)
|
||||
if name then
|
||||
texture, stacks, dtype = icon, count, dispelType
|
||||
else
|
||||
texture, stacks, dtype = nil, 0, nil
|
||||
end
|
||||
@@ -1757,18 +1759,18 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
if texture then
|
||||
unit.debuffs[i]:Show()
|
||||
|
||||
if aura and aura.expirationTime > 0 then
|
||||
if expirationTime > 0 then
|
||||
-- Cap start to now so talent-extended debuffs (expirationTime past
|
||||
-- the dbc base duration) don't push start into the future and trip
|
||||
-- CooldownFrame_SetTimer's 2^32-wraparound branch.
|
||||
local now = GetTime()
|
||||
local start = aura.expirationTime - aura.duration
|
||||
local duration = aura.duration
|
||||
if start > now or duration <= 0 then
|
||||
start, duration = now, aura.expirationTime - now
|
||||
local start = expirationTime - duration
|
||||
local dur = duration
|
||||
if start > now or dur <= 0 then
|
||||
start, dur = now, expirationTime - now
|
||||
end
|
||||
if duration > 0 then
|
||||
CooldownFrame_SetTimer(unit.debuffs[i].cd, start, duration, 1)
|
||||
if dur > 0 then
|
||||
CooldownFrame_SetTimer(unit.debuffs[i].cd, start, dur, 1)
|
||||
else
|
||||
CooldownFrame_SetTimer(unit.debuffs[i].cd, 0, 0, 0)
|
||||
end
|
||||
@@ -1826,6 +1828,17 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
end
|
||||
end
|
||||
|
||||
-- Scan the 16 harmful slots once into a reusable set, instead of
|
||||
-- re-scanning all 16 for every dispellable type below. Reused across
|
||||
-- frames (populated and consumed within this single RefreshUnit call).
|
||||
local present = pfUI.uf.dispelPresent or {}
|
||||
pfUI.uf.dispelPresent = present
|
||||
for k in pairs(present) do present[k] = nil end
|
||||
for i=1,16 do
|
||||
local name, _, _, dispelType = C_UnitAuras.UnitDebuff(unitstr, i)
|
||||
if name and dispelType and dispelType ~= "" then present[dispelType] = true end
|
||||
end
|
||||
|
||||
for _, debuff in pairs(unit.dispellable) do
|
||||
indicator[debuff] = indicator[debuff] or CreateFrame("Frame", nil, indicator)
|
||||
indicator[debuff]:SetParent(indicator)
|
||||
@@ -1865,15 +1878,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
indicator[debuff].disp = indicator.disp
|
||||
end
|
||||
|
||||
indicator[debuff].visible = nil
|
||||
|
||||
for i=1,16 do
|
||||
local a = C_UnitAuras.GetDebuffDataByIndex(unitstr, i)
|
||||
local dtype = a and a.dispelName
|
||||
if dtype == debuff then
|
||||
indicator[debuff].visible = true
|
||||
end
|
||||
end
|
||||
indicator[debuff].visible = present[debuff]
|
||||
|
||||
if indicator[debuff].visible then
|
||||
indicator[debuff]:Show()
|
||||
@@ -1920,50 +1925,58 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
|
||||
local pos = 1
|
||||
if table.getn(unit.indicators) > 0 then
|
||||
for _, aura in ipairs(C_UnitAuras.GetUnitAuras(unitstr, "HELPFUL")) do
|
||||
local texLower = string.lower(aura.icon)
|
||||
local timeleft = aura.expirationTime > 0 and (aura.expirationTime - GetTime()) or nil
|
||||
local i = 1
|
||||
while true do
|
||||
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitBuff(unitstr, i)
|
||||
if not name then break end
|
||||
local texLower = string.lower(icon)
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
|
||||
for _, filter in pairs(unit.indicators) do
|
||||
if filter == texLower then
|
||||
local hot = HOT_INDICATORS[texLower]
|
||||
if hot and string.lower(aura.name) ~= hot.name then
|
||||
if hot and string.lower(name) ~= hot.name then
|
||||
break -- texture matches but name disambiguates (e.g. shared icon)
|
||||
end
|
||||
if hot then
|
||||
local start, duration, prediction = libpredict:GetHotDuration(unitstr, hot.predict)
|
||||
pfUI.uf:AddIcon(unit, pos, aura.icon, timeleft or prediction, aura.applications, tonumber(start), tonumber(duration))
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft or prediction, count, tonumber(start), tonumber(duration))
|
||||
else
|
||||
pfUI.uf:AddIcon(unit, pos, aura.icon, timeleft, aura.applications)
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
end
|
||||
pos = pos + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
if table.getn(unit.indicator_custom) > 0 then
|
||||
for _, aura in ipairs(C_UnitAuras.GetUnitAuras(unitstr, "HELPFUL")) do
|
||||
local timeleft = aura.expirationTime > 0 and (aura.expirationTime - GetTime()) or nil
|
||||
local lowerName = string.lower(aura.name)
|
||||
local ai = 1
|
||||
while true do
|
||||
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitBuff(unitstr, ai)
|
||||
if not name then break end
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
local lowerName = string.lower(name)
|
||||
for _, filter in pairs(unit.indicator_custom) do
|
||||
if filter == lowerName then
|
||||
pfUI.uf:AddIcon(unit, pos, aura.icon, timeleft, aura.applications)
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
pos = pos + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
ai = ai + 1
|
||||
end
|
||||
|
||||
local debuffFilter = unit.config.selfdebuff == "1" and "HARMFUL|PLAYER" or "HARMFUL"
|
||||
local debuffFilter = unit.config.selfdebuff == "1" and "PLAYER" or nil
|
||||
for i=1,16 do -- scan for custom debuffs
|
||||
local aura = C_UnitAuras.GetAuraDataByIndex(unitstr, i, debuffFilter)
|
||||
if aura then
|
||||
local timeleft = aura.expirationTime > 0 and (aura.expirationTime - GetTime()) or nil
|
||||
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitDebuff(unitstr, i, debuffFilter)
|
||||
if name then
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
for _, filter in pairs(unit.indicator_custom) do
|
||||
if filter == string.lower(aura.name) then
|
||||
pfUI.uf:AddIcon(unit, pos, aura.icon, timeleft, aura.applications)
|
||||
if filter == string.lower(name) then
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
pos = pos + 1
|
||||
break
|
||||
end
|
||||
|
||||
@@ -168,6 +168,9 @@ pfUI.libdebuff_spell_start_self_hooks["libpredict"] = function(spellId, casterGu
|
||||
return
|
||||
end
|
||||
|
||||
spell_queue[1] = spellName
|
||||
spell_queue[2] = spellName .. (C_Spell.GetSpellSubtext(spellId) or "")
|
||||
|
||||
if spell_queue[1] == spellName and cache[spell_queue[2]] then
|
||||
local amount = cache[spell_queue[2]][1]
|
||||
local casttime = castTime
|
||||
|
||||
+7
-7
@@ -23,7 +23,7 @@ pfUI:RegisterModule("buff", function ()
|
||||
CreateBackdropShadow(buff)
|
||||
end
|
||||
|
||||
local aura = C_UnitAuras.GetAuraDataByIndex("player", buff.id, buff.btype)
|
||||
local name, icon, count, dispelType, _, expirationTime, _, _, _, spellId = C_UnitAuras.UnitAura("player", buff.id, buff.btype)
|
||||
|
||||
--detect weapon buffs
|
||||
if buff.btype == "HELPFUL" and ((C.buffs.separateweapons == "0" and buff.gid <= pfUI.buff.wepbuffs.count) or (pfUI.buff.wepbuffs.count > 0 and buff.weapon ~= nil)) then
|
||||
@@ -55,16 +55,16 @@ pfUI:RegisterModule("buff", function ()
|
||||
buff.texture:SetTexture(GetInventoryItemTexture("player", 17))
|
||||
buff.backdrop:SetBackdropBorderColor(GetItemQualityColor(GetInventoryItemQuality("player", 17) or 1))
|
||||
end
|
||||
elseif aura and (( buff.btype == "HARMFUL" and C.buffs.debuffs == "1" ) or ( buff.btype == "HELPFUL" and C.buffs.buffs == "1" )) then
|
||||
elseif name and (( buff.btype == "HARMFUL" and C.buffs.debuffs == "1" ) or ( buff.btype == "HELPFUL" and C.buffs.buffs == "1" )) then
|
||||
-- Set Buff Texture and Border
|
||||
buff.mode = buff.btype
|
||||
buff.expirationTime = aura.expirationTime
|
||||
buff.stackCount = aura.applications
|
||||
buff.spellId = aura.spellId
|
||||
buff.texture:SetTexture(aura.icon)
|
||||
buff.expirationTime = expirationTime
|
||||
buff.stackCount = count
|
||||
buff.spellId = spellId
|
||||
buff.texture:SetTexture(icon)
|
||||
|
||||
if buff.btype == "HARMFUL" then
|
||||
local dispelColor = C_UnitAuras.GetAuraDispelTypeColor(aura.dispelName)
|
||||
local dispelColor = C_UnitAuras.GetAuraDispelTypeColor(dispelType)
|
||||
buff.backdrop:SetBackdropBorderColor(dispelColor:GetRGBA())
|
||||
else
|
||||
buff.backdrop:SetBackdropBorderColor(br,bg,bb,ba)
|
||||
|
||||
+10
-11
@@ -75,10 +75,10 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
|
||||
local function GetBuffData(unit, id, type, selfdebuff)
|
||||
local filter = (selfdebuff and type == "HARMFUL") and "HARMFUL|PLAYER" or type
|
||||
local aura = C_UnitAuras.GetAuraDataByIndex(unit, id, filter)
|
||||
if not aura then return end
|
||||
local remaining = aura.expirationTime > 0 and (aura.expirationTime - GetTime()) or 0
|
||||
return remaining, aura.icon, aura.name, aura.applications
|
||||
local name, icon, count, dispelType, _, expirationTime = C_UnitAuras.UnitAura(unit, id, filter)
|
||||
if not name then return end
|
||||
local remaining = expirationTime > 0 and (expirationTime - GetTime()) or 0
|
||||
return remaining, icon, name, count, dispelType
|
||||
end
|
||||
|
||||
local function StatusBarOnClick()
|
||||
@@ -236,7 +236,7 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
local selfdebuff = frame.config.selfdebuff == "1"
|
||||
|
||||
for i=1,32 do
|
||||
local timeleft, texture, name, stacks = GetBuffData(frame.unit, i, frame.type, selfdebuff)
|
||||
local timeleft, texture, name, stacks, dtype = GetBuffData(frame.unit, i, frame.type, selfdebuff)
|
||||
timeleft = timeleft or 0
|
||||
|
||||
if texture and name and name ~= "" and BuffIsVisible(frame.config, name) then
|
||||
@@ -245,12 +245,14 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
frame.buffs[i][3] = name
|
||||
frame.buffs[i][4] = texture
|
||||
frame.buffs[i][5] = stacks
|
||||
frame.buffs[i][6] = dtype
|
||||
else
|
||||
frame.buffs[i][1] = 0
|
||||
frame.buffs[i][2] = nil
|
||||
frame.buffs[i][3] = nil
|
||||
frame.buffs[i][4] = nil
|
||||
frame.buffs[i][5] = 0
|
||||
frame.buffs[i][6] = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -294,12 +296,9 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
-- calculate dynamic auto color
|
||||
local r, g, b
|
||||
if frame.type == "HARMFUL" then
|
||||
r, g, b = 1, .2, .2
|
||||
local a = C_UnitAuras.GetDebuffDataByIndex(frame.unit, data[2])
|
||||
local dtype = a and a.dispelName
|
||||
if dtype and DebuffTypeColor[dtype] then
|
||||
r,g,b = DebuffTypeColor[dtype].r,DebuffTypeColor[dtype].g,DebuffTypeColor[dtype].b
|
||||
end
|
||||
-- official Blizzard dispel-type colors (matches unitframes/buff);
|
||||
-- nil/unknown type falls back to the DEBUFF_TYPE_NONE colour
|
||||
r, g, b = C_UnitAuras.GetAuraDispelTypeColor(data[6] or ""):GetRGBA()
|
||||
else
|
||||
r,g,b = str2rgb(data[3])
|
||||
end
|
||||
|
||||
+58
-3
@@ -296,6 +296,54 @@ pfUI:RegisterModule("chat", function ()
|
||||
end
|
||||
end
|
||||
|
||||
-- [ Chat Background Alpha ]
|
||||
-- Blizzard's per-window transparency slider drives FCF_SetWindowAlpha, which only
|
||||
-- touches the ChatFrame*Background textures that pfUI hides on docked frames. Mirror
|
||||
-- the window's stored alpha onto the visible pfUI backdrop so the native slider
|
||||
-- controls it directly. The slider is authoritative for the panel's alpha.
|
||||
local function ApplyChatBackgroundAlpha(panel, frame)
|
||||
if not (panel and panel.backdrop and frame) then return end
|
||||
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
|
||||
alpha = tonumber(alpha)
|
||||
if not alpha then return end
|
||||
local r, g, b = panel.backdrop:GetBackdropColor()
|
||||
panel.backdrop:SetBackdropColor(r, g, b, alpha)
|
||||
end
|
||||
|
||||
function pfUI.chat:RefreshBackgroundAlpha()
|
||||
-- left panel follows the currently selected docked tab
|
||||
local selected = SELECTED_CHAT_FRAME
|
||||
if not (selected and selected:GetParent() == pfUI.chat.left) then
|
||||
selected = ChatFrame1
|
||||
end
|
||||
ApplyChatBackgroundAlpha(pfUI.chat.left, selected)
|
||||
|
||||
if C.chat.right.enable == "1" then
|
||||
ApplyChatBackgroundAlpha(pfUI.chat.right, ChatFrame3)
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.chat:MigrateBackgroundAlpha()
|
||||
-- Runs once per character. The previous SetupPositions default stored a hard 0 window
|
||||
-- alpha, which now renders the pfUI backdrop fully transparent. Restore the historical
|
||||
-- 0.8 look for any pfUI-managed window still sitting at 0. Only existing installs that
|
||||
-- already ran chat setup carry that legacy 0; fresh installs get 0.8 from SetupPositions.
|
||||
if pfUI_init.chatbgalpha then return end
|
||||
if not pfUI_init["chat_position"] then return end
|
||||
pfUI_init.chatbgalpha = true
|
||||
|
||||
local frames = { ChatFrame1, ChatFrame2 }
|
||||
if C.chat.right.enable == "1" then table.insert(frames, ChatFrame3) end
|
||||
|
||||
for _, frame in ipairs(frames) do
|
||||
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
|
||||
alpha = tonumber(alpha)
|
||||
if alpha and alpha <= 0 then
|
||||
FCF_SetWindowAlpha(frame, 0.8)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.chat:RefreshChat()
|
||||
local panelheight = C.global.font_size*1.5 + default_border*2 + 2
|
||||
|
||||
@@ -447,9 +495,13 @@ pfUI:RegisterModule("chat", function ()
|
||||
for index, value in pairs(DOCKED_CHAT_FRAMES) do
|
||||
FCF_UpdateButtonSide(value)
|
||||
end
|
||||
|
||||
pfUI.chat:RefreshBackgroundAlpha()
|
||||
end
|
||||
|
||||
hooksecurefunc("FCF_SaveDock", pfUI.chat.RefreshChat)
|
||||
hooksecurefunc("FCF_SetWindowAlpha", function() pfUI.chat:RefreshBackgroundAlpha() end)
|
||||
hooksecurefunc("FCF_SelectDockFrame", function() pfUI.chat:RefreshBackgroundAlpha() end)
|
||||
|
||||
if C.chat.global.tabmouse == "1" then
|
||||
pfUI.chat.mouseovertab = CreateFrame("Frame")
|
||||
@@ -500,7 +552,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame1, 1)
|
||||
FCF_SetWindowName(ChatFrame1, GENERAL)
|
||||
FCF_SetWindowColor(ChatFrame1, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame1, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame1, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame1, 12)
|
||||
ChatFrame1:SetUserPlaced(1)
|
||||
|
||||
@@ -508,7 +560,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame2, 1)
|
||||
FCF_SetWindowName(ChatFrame2, COMBAT_LOG)
|
||||
FCF_SetWindowColor(ChatFrame2, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame2, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame2, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame2, 12)
|
||||
ChatFrame2:SetUserPlaced(1)
|
||||
|
||||
@@ -518,7 +570,7 @@ pfUI:RegisterModule("chat", function ()
|
||||
FCF_SetLocked(ChatFrame3, 1)
|
||||
FCF_SetWindowName(ChatFrame3, T["Loot & Spam"])
|
||||
FCF_SetWindowColor(ChatFrame3, 0, 0, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame3, 0)
|
||||
FCF_SetWindowAlpha(ChatFrame3, 0.8)
|
||||
FCF_SetChatWindowFontSize(ChatFrame3, 12)
|
||||
FCF_UnDockFrame(ChatFrame3)
|
||||
FCF_SetTabPosition(ChatFrame3, 0)
|
||||
@@ -566,6 +618,9 @@ pfUI:RegisterModule("chat", function ()
|
||||
end
|
||||
|
||||
pfUI.chat:SetScript("OnEvent", function()
|
||||
-- restore legacy chat windows stuck at 0 alpha before anything reads it
|
||||
pfUI.chat:MigrateBackgroundAlpha()
|
||||
|
||||
-- set the default chat
|
||||
FCF_SelectDockFrame(SELECTED_CHAT_FRAME)
|
||||
|
||||
|
||||
+32
-20
@@ -1039,13 +1039,29 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
local mouseover = plate.cachedGuid and plate.cachedGuid == frameState.mouseoverGuid or nil
|
||||
local unitstr = target and "target" or mouseover and "mouseover" or plate.cachedGuid or nil
|
||||
|
||||
-- target event sometimes fires too quickly, where nameplate identifiers are not
|
||||
-- yet updated. So while being inside this event, we cannot trust the unitstr.
|
||||
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
|
||||
|
||||
-- remove unitstr when it doesn't resolve to this plate's unit (stale istarget,
|
||||
-- stale mouseover guid or a despawned unit). Must run before the cache fills
|
||||
-- below -- an unrelated unitstr would poison cache.player/minion with the
|
||||
-- *other* unit's answer, and the nil-gate would then never recompute it.
|
||||
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
|
||||
|
||||
-- resolve player vs npc from plate's own unit so libunitscan can't return
|
||||
-- a player record for an NPC sharing the same name (e.g. Chromie). Stored
|
||||
-- as true/false/nil so it doubles as the GetUnitInfo hint.
|
||||
if plate.cache.player == nil and unitstr then
|
||||
plate.cache.player = UnitIsPlayer(unitstr) and true or false
|
||||
end
|
||||
local class, ulevel, elite, player, guild = GetUnitInfo(name, true, plate.cache.player)
|
||||
if plate.cache.minion == nil and unitstr then
|
||||
plate.cache.minion = UnitIsMinion(unitstr) and true or false
|
||||
end
|
||||
local class, ulevel, elite, player, guild
|
||||
if not plate.cache.minion then
|
||||
class, ulevel, elite, player, guild = GetUnitInfo(name, true, plate.cache.player)
|
||||
end
|
||||
if plate.cache.player ~= nil then player = plate.cache.player or nil end
|
||||
|
||||
-- Use database level ONLY if current level is ?? (fixes ?? after reload, but doesn't override visible levels)
|
||||
@@ -1065,18 +1081,11 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
if player and unittype == "ENEMY_NPC" then unittype = "ENEMY_PLAYER" end
|
||||
if player and unittype == "FRIENDLY_NPC" then unittype = "FRIENDLY_PLAYER" end
|
||||
elite = plate.original.levelicon:IsShown() and not player and "boss" or elite
|
||||
if not class then plate.wait_for_scan = true end
|
||||
if not class and not plate.cache.minion then plate.wait_for_scan = true end
|
||||
|
||||
-- skip data updates on invisible frames
|
||||
if not visible then return end
|
||||
|
||||
-- target event sometimes fires too quickly, where nameplate identifiers are not
|
||||
-- yet updated. So while being inside this event, we cannot trust the unitstr.
|
||||
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
|
||||
|
||||
-- remove unitstr on unit name mismatch
|
||||
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
|
||||
|
||||
-- always make sure to keep plate visible
|
||||
plate:Show()
|
||||
|
||||
@@ -1313,19 +1322,22 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
for i = 1, 16 do debuffDisplayBuf[i].effect = nil end
|
||||
if unitstr then
|
||||
local filter = cfg.owndebuffs and "HARMFUL|PLAYER" or "HARMFUL"
|
||||
local auras = C_UnitAuras.GetUnitAuras(unitstr, filter)
|
||||
local now = GetTime()
|
||||
for _, aura in ipairs(auras) do
|
||||
if debuffCount >= 16 then break end
|
||||
-- positional UnitAura writes straight into the reusable buffer, so the
|
||||
-- per-plate scan allocates nothing (no per-aura table, no result array)
|
||||
local i = 1
|
||||
while debuffCount < 16 do
|
||||
local aname, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAura(unitstr, i, filter)
|
||||
if not aname then break end
|
||||
debuffCount = debuffCount + 1
|
||||
local timeleft = (aura.expirationTime and aura.expirationTime > 0) and (aura.expirationTime - now) or nil
|
||||
local b = debuffDisplayBuf[debuffCount]
|
||||
b.effect = aura.name
|
||||
b.texture = aura.icon
|
||||
b.stacks = aura.applications
|
||||
b.dtype = aura.dispelName
|
||||
b.duration = aura.duration
|
||||
b.timeleft = timeleft
|
||||
b.effect = aname
|
||||
b.texture = icon
|
||||
b.stacks = count
|
||||
b.dtype = dispelType
|
||||
b.duration = duration
|
||||
b.timeleft = (expirationTime and expirationTime > 0) and (expirationTime - now) or nil
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
for i = 1, 16 do
|
||||
@@ -1548,7 +1560,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
-- otherwise an NPC sharing a name with a known player flips wait_for_scan
|
||||
-- off here, then OnDataChanged re-sets it, every frame until the mob scan
|
||||
-- lands.
|
||||
if nameplate.wait_for_scan and GetUnitInfo(name, true, nameplate.cache.player) then
|
||||
if nameplate.wait_for_scan and not nameplate.cache.minion and GetUnitInfo(name, true, nameplate.cache.player) then
|
||||
nameplate.wait_for_scan = nil
|
||||
update = true
|
||||
end
|
||||
|
||||
+23
-90
@@ -3,56 +3,15 @@ pfUI:RegisterModule("tracking", function ()
|
||||
MINIMAP_TRACKING_FRAME:UnregisterAllEvents()
|
||||
MINIMAP_TRACKING_FRAME:Hide()
|
||||
|
||||
local function HasEntries(tbl)
|
||||
for _ in pairs(tbl) do
|
||||
return true
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local rawborder, border = GetBorderSize()
|
||||
local size = tonumber(C.appearance.minimap.tracking_size)
|
||||
local pulse = C.appearance.minimap.tracking_pulse == "1"
|
||||
|
||||
-- Tracking spells identified by SpellID + expected icon path.
|
||||
-- SpellID is the primary identifier (stable, locale-independent).
|
||||
-- Icon path is used as secondary confirmation when scanning the spellbook.
|
||||
local knownTrackingSpells = {
|
||||
any = {
|
||||
{ id = 2481, icon = "Racial_Dwarf_FindTreasure" }, -- Find Treasure
|
||||
{ id = 2580, icon = "Spell_Nature_Earthquake" }, -- Find Minerals
|
||||
{ id = 2383, icon = "INV_Misc_Flower_02" }, -- Find Herbs (Rank 1)
|
||||
{ id = 8387, icon = "INV_Misc_Flower_02" }, -- Find Herbs (Rank 2)
|
||||
{ id = 52917, icon = "INV_TradeSkillItem_03" }, -- Find Trees (TurtleWow)
|
||||
},
|
||||
HUNTER = {
|
||||
{ id = 1494, icon = "Ability_Tracking" }, -- Track Beasts
|
||||
{ id = 19883, icon = "Spell_Holy_PrayerOfHealing" }, -- Track Humanoids
|
||||
{ id = 19884, icon = "Spell_Shadow_DarkSummoning" }, -- Track Undead
|
||||
{ id = 19885, icon = "Ability_Stealth" }, -- Track Hidden
|
||||
{ id = 19880, icon = "Spell_Frost_SummonWaterElemental" }, -- Track Elementals
|
||||
{ id = 19878, icon = "Spell_Shadow_SummonFelHunter" }, -- Track Demons
|
||||
{ id = 19882, icon = "Ability_Racial_Avatar" }, -- Track Giants
|
||||
{ id = 19879, icon = "INV_Misc_Head_Dragon_01" }, -- Track Dragonkin
|
||||
},
|
||||
PALADIN = {
|
||||
{ id = 5502, icon = "Spell_Holy_SenseUndead" }, -- Sense Undead
|
||||
},
|
||||
WARLOCK = {
|
||||
{ id = 5500, icon = "Spell_Shadow_Metamorphosis" }, -- Sense Demons
|
||||
},
|
||||
DRUID = {
|
||||
{ id = 5225, icon = "Ability_Tracking" }, -- Track Humanoids (Cat Form only)
|
||||
},
|
||||
}
|
||||
|
||||
-- Build a flat lookup: spellId -> entry, for fast spellbook matching
|
||||
local spellIdLookup = {}
|
||||
for _, entries in pairs(knownTrackingSpells) do
|
||||
for _, entry in ipairs(entries) do
|
||||
spellIdLookup[entry.id] = entry
|
||||
end
|
||||
end
|
||||
-- Tracking spells come from ClassicAPI's native GetNumTrackingTypes /
|
||||
-- GetTrackingInfo (see the DLL's docs/API.md "Tracking"). The DLL
|
||||
-- enumerates them straight from the spellbook by tracking-aura effect,
|
||||
-- so there is no spell table to maintain here and server-custom trackers
|
||||
-- (e.g. Turtle's Find Trees) are picked up automatically.
|
||||
|
||||
local state = {
|
||||
texture = nil,
|
||||
@@ -128,50 +87,24 @@ pfUI:RegisterModule("tracking", function ()
|
||||
end)
|
||||
|
||||
function pfUI.tracking:RefreshSpells()
|
||||
local playerClass = UnitClassBase("player")
|
||||
local isCatForm = pfUI.tracking:PlayerIsDruidInCatForm(playerClass)
|
||||
state.spells = {}
|
||||
if not GetNumTrackingTypes then return end
|
||||
|
||||
-- Build set of valid SpellIDs for this class
|
||||
local validIds = {}
|
||||
for _, entry in ipairs(knownTrackingSpells.any) do
|
||||
validIds[entry.id] = true
|
||||
end
|
||||
if knownTrackingSpells[playerClass] then
|
||||
for _, entry in ipairs(knownTrackingSpells[playerClass]) do
|
||||
validIds[entry.id] = true
|
||||
end
|
||||
end
|
||||
-- Druid Track Humanoids (5225) only casts in Cat Form. Hide it out of
|
||||
-- form so the menu never offers a tracker that would fail to cast.
|
||||
local isCatForm = pfUI.tracking:PlayerIsDruidInCatForm(UnitClassBase("player"))
|
||||
|
||||
-- Druids only get Track Humanoids in Cat Form
|
||||
if playerClass == "DRUID" and not isCatForm then
|
||||
validIds[5225] = nil
|
||||
end
|
||||
|
||||
-- Scan spellbook: match by icon path, confirm SpellID is valid for this class
|
||||
for tabIndex = 1, GetNumSpellTabs() do
|
||||
local _, _, offset, numSpells = GetSpellTabInfo(tabIndex)
|
||||
for spellIndex = offset + 1, offset + numSpells do
|
||||
local spellTexture = GetSpellTexture(spellIndex, BOOKTYPE_SPELL)
|
||||
local spellName = GetSpellName(spellIndex, BOOKTYPE_SPELL)
|
||||
|
||||
if pfUI.tracking.invalidSpells[spellName] then
|
||||
spellTexture = nil
|
||||
end
|
||||
|
||||
if spellTexture then
|
||||
local lowerTexture = string.lower(spellTexture)
|
||||
for spellId, entry in pairs(spellIdLookup) do
|
||||
if validIds[spellId] and not state.spells[spellId]
|
||||
and strfind(lowerTexture, string.lower(entry.icon)) then
|
||||
state.spells[spellId] = {
|
||||
index = spellIndex,
|
||||
name = spellName,
|
||||
texture = spellTexture,
|
||||
spellId = spellId,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
for i = 1, GetNumTrackingTypes() do
|
||||
local name, texture, _, _, spellId = GetTrackingInfo(i)
|
||||
local castable = not (spellId == 5225 and not isCatForm)
|
||||
if name and texture and castable
|
||||
and not pfUI.tracking.invalidSpells[name] then
|
||||
state.spells[i] = {
|
||||
index = i, -- tracking index, passed to SetTracking()
|
||||
name = name,
|
||||
texture = texture,
|
||||
spellId = spellId,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -187,7 +120,7 @@ pfUI:RegisterModule("tracking", function ()
|
||||
elseif not texture then
|
||||
state.texture = nil
|
||||
|
||||
if pulse and HasEntries(state.spells) then
|
||||
if pulse and next(state.spells) ~= nil then
|
||||
pfUI.tracking.pulse = true
|
||||
pfUI.tracking.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
pfUI.tracking.icon:SetVertexColor(1,1,1,1)
|
||||
@@ -217,7 +150,7 @@ pfUI:RegisterModule("tracking", function ()
|
||||
checked = spell.texture == state.texture,
|
||||
arg1 = spell,
|
||||
func = function (arg1)
|
||||
CastSpell(arg1.index, BOOKTYPE_SPELL)
|
||||
SetTracking(arg1.index)
|
||||
CloseDropDownMenus()
|
||||
end
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ do
|
||||
-- ClassicAPI dependency check.
|
||||
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
||||
-- API surface that ClassicAPI polyfills, so presence is required.
|
||||
local PFUI_CLASSIC_API_MIN = 11100 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_MIN = 11204 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||
@@ -86,14 +86,13 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- initialize saved variables
|
||||
pfUI_playerDB = {}
|
||||
pfUI_config = {}
|
||||
pfUI_init = {}
|
||||
pfUI_profiles = {}
|
||||
pfUI_addon_profiles = {}
|
||||
pfUI_cache = {}
|
||||
pfUI_throttle = {}
|
||||
pfUI_playerDB = pfUI_playerDB or {}
|
||||
pfUI_config = pfUI_config or {}
|
||||
pfUI_init = pfUI_init or {}
|
||||
pfUI_profiles = pfUI_profiles or {}
|
||||
pfUI_addon_profiles = pfUI_addon_profiles or {}
|
||||
pfUI_cache = pfUI_cache or {}
|
||||
pfUI_throttle = pfUI_throttle or {}
|
||||
|
||||
-- localization
|
||||
pfUI_locale = {}
|
||||
@@ -577,4 +576,4 @@ function pfUI.SetupCVars()
|
||||
COMBAT_TEXT_SHOW_HONOR_GAINED = "1"
|
||||
end
|
||||
UIParentLoadAddOn("Blizzard_CombatText")
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user