聊天重做前缓存
This commit is contained in:
337
Units/Party.lua
337
Units/Party.lua
@@ -9,6 +9,9 @@ local PARTY_HORIZONTAL_GAP = 8
|
||||
local PARTY_UNIT_LOOKUP = { party1 = true, party2 = true, party3 = true, party4 = true }
|
||||
local PARTYPET_UNIT_LOOKUP = { partypet1 = true, partypet2 = true, partypet3 = true, partypet4 = true }
|
||||
|
||||
-- Pre-allocated table reused every UpdateAuras call
|
||||
local _partyDebuffColor = { r = 0, g = 0, b = 0 }
|
||||
|
||||
local function GetIncomingHeals(unit)
|
||||
return SFrames:GetIncomingHeals(unit)
|
||||
end
|
||||
@@ -36,6 +39,12 @@ local function Clamp(value, minValue, maxValue)
|
||||
return value
|
||||
end
|
||||
|
||||
local function SetTextureIfPresent(region, texturePath)
|
||||
if region and region.SetTexture and texturePath then
|
||||
region:SetTexture(texturePath)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Party:GetMetrics()
|
||||
local db = SFramesDB or {}
|
||||
|
||||
@@ -57,6 +66,34 @@ function SFrames.Party:GetMetrics()
|
||||
local powerHeight = tonumber(db.partyPowerHeight) or (height - healthHeight - 3)
|
||||
powerHeight = Clamp(math.floor(powerHeight + 0.5), 6, height - 6)
|
||||
|
||||
local gradientStyle = SFrames:IsGradientStyle()
|
||||
local availablePowerWidth = width - portraitWidth - 5
|
||||
if availablePowerWidth < 40 then
|
||||
availablePowerWidth = 40
|
||||
end
|
||||
|
||||
local rawPowerWidth = tonumber(db.partyPowerWidth)
|
||||
local legacyFullWidth = tonumber(db.partyFrameWidth) or width
|
||||
local legacyPowerWidth = width - portraitWidth - 3
|
||||
local defaultPowerWidth = gradientStyle and width or availablePowerWidth
|
||||
local maxPowerWidth = gradientStyle and width or availablePowerWidth
|
||||
local powerWidth
|
||||
if gradientStyle then
|
||||
-- 渐变风格:能量条始终与血条等宽(全宽)
|
||||
powerWidth = width
|
||||
elseif not rawPowerWidth
|
||||
or math.abs(rawPowerWidth - legacyFullWidth) < 0.5
|
||||
or math.abs(rawPowerWidth - legacyPowerWidth) < 0.5
|
||||
or math.abs(rawPowerWidth - availablePowerWidth) < 0.5 then
|
||||
powerWidth = defaultPowerWidth
|
||||
else
|
||||
powerWidth = rawPowerWidth
|
||||
end
|
||||
powerWidth = Clamp(math.floor(powerWidth + 0.5), 40, maxPowerWidth)
|
||||
|
||||
local powerOffsetX = Clamp(math.floor((tonumber(db.partyPowerOffsetX) or 0) + 0.5), -120, 120)
|
||||
local powerOffsetY = Clamp(math.floor((tonumber(db.partyPowerOffsetY) or 0) + 0.5), -80, 80)
|
||||
|
||||
if healthHeight + powerHeight + 3 > height then
|
||||
powerHeight = height - healthHeight - 3
|
||||
if powerHeight < 6 then
|
||||
@@ -81,16 +118,30 @@ function SFrames.Party:GetMetrics()
|
||||
local valueFont = tonumber(db.partyValueFontSize) or 10
|
||||
valueFont = Clamp(math.floor(valueFont + 0.5), 8, 18)
|
||||
|
||||
local healthFont = tonumber(db.partyHealthFontSize) or valueFont
|
||||
healthFont = Clamp(math.floor(healthFont + 0.5), 8, 18)
|
||||
|
||||
local powerFont = tonumber(db.partyPowerFontSize) or valueFont
|
||||
powerFont = Clamp(math.floor(powerFont + 0.5), 8, 18)
|
||||
|
||||
return {
|
||||
width = width,
|
||||
height = height,
|
||||
portraitWidth = portraitWidth,
|
||||
healthHeight = healthHeight,
|
||||
powerHeight = powerHeight,
|
||||
powerWidth = powerWidth,
|
||||
powerOffsetX = powerOffsetX,
|
||||
powerOffsetY = powerOffsetY,
|
||||
powerOnTop = db.partyPowerOnTop == true,
|
||||
horizontalGap = hgap,
|
||||
verticalGap = vgap,
|
||||
nameFont = nameFont,
|
||||
valueFont = valueFont,
|
||||
healthFont = healthFont,
|
||||
powerFont = powerFont,
|
||||
healthTexture = SFrames:ResolveBarTexture("partyHealthTexture", "barTexture"),
|
||||
powerTexture = SFrames:ResolveBarTexture("partyPowerTexture", "barTexture"),
|
||||
}
|
||||
end
|
||||
|
||||
@@ -142,8 +193,8 @@ function SFrames.Party:ApplyFrameStyle(frame, metrics)
|
||||
|
||||
if frame.power then
|
||||
frame.power:ClearAllPoints()
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", 0, -1)
|
||||
frame.power:SetPoint("TOPRIGHT", frame.health, "BOTTOMRIGHT", 0, 0)
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", metrics.powerOffsetX, -1 + metrics.powerOffsetY)
|
||||
frame.power:SetWidth(metrics.powerWidth)
|
||||
frame.power:SetHeight(metrics.powerHeight)
|
||||
end
|
||||
|
||||
@@ -153,14 +204,114 @@ function SFrames.Party:ApplyFrameStyle(frame, metrics)
|
||||
frame.powerBGFrame:SetPoint("BOTTOMRIGHT", frame.power, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
|
||||
local outline = (SFrames and SFrames.Media and SFrames.Media.fontOutline) or "OUTLINE"
|
||||
local fontPath = SFrames:GetFont()
|
||||
SFrames:ApplyStatusBarTexture(frame.health, "partyHealthTexture", "barTexture")
|
||||
SFrames:ApplyStatusBarTexture(frame.power, "partyPowerTexture", "barTexture")
|
||||
if frame.health and frame.power then
|
||||
local healthLevel = frame:GetFrameLevel() + 2
|
||||
local powerLevel = metrics.powerOnTop and (healthLevel + 1) or (healthLevel - 1)
|
||||
frame.health:SetFrameLevel(healthLevel)
|
||||
frame.power:SetFrameLevel(powerLevel)
|
||||
end
|
||||
SFrames:ApplyConfiguredUnitBackdrop(frame, "party")
|
||||
if frame.pbg then SFrames:ApplyConfiguredUnitBackdrop(frame.pbg, "party", true) end
|
||||
if frame.healthBGFrame then SFrames:ApplyConfiguredUnitBackdrop(frame.healthBGFrame, "party") end
|
||||
if frame.powerBGFrame then SFrames:ApplyConfiguredUnitBackdrop(frame.powerBGFrame, "party") end
|
||||
SetTextureIfPresent(frame.health and frame.health.bg, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredMine, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredOther, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredOver, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.power and frame.power.bg, metrics.powerTexture)
|
||||
|
||||
-- Gradient style preset
|
||||
if SFrames:IsGradientStyle() then
|
||||
-- Hide portrait & its backdrop
|
||||
if frame.portrait then frame.portrait:Hide() end
|
||||
if frame.pbg then SFrames:ClearBackdrop(frame.pbg); frame.pbg:Hide() end
|
||||
-- Strip backdrops
|
||||
SFrames:ClearBackdrop(frame)
|
||||
SFrames:ClearBackdrop(frame.healthBGFrame)
|
||||
SFrames:ClearBackdrop(frame.powerBGFrame)
|
||||
-- Health bar full width
|
||||
if frame.health then
|
||||
frame.health:ClearAllPoints()
|
||||
frame.health:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
|
||||
frame.health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
|
||||
frame.health:SetHeight(metrics.healthHeight)
|
||||
end
|
||||
-- Power bar full width
|
||||
if frame.power then
|
||||
frame.power:ClearAllPoints()
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", metrics.powerOffsetX, -2 + metrics.powerOffsetY)
|
||||
frame.power:SetWidth(metrics.powerWidth)
|
||||
frame.power:SetHeight(metrics.powerHeight)
|
||||
end
|
||||
-- Apply gradient overlays
|
||||
SFrames:ApplyGradientStyle(frame.health)
|
||||
SFrames:ApplyGradientStyle(frame.power)
|
||||
-- Flush BG frames
|
||||
if frame.healthBGFrame then
|
||||
frame.healthBGFrame:ClearAllPoints()
|
||||
frame.healthBGFrame:SetPoint("TOPLEFT", frame.health, "TOPLEFT", 0, 0)
|
||||
frame.healthBGFrame:SetPoint("BOTTOMRIGHT", frame.health, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
if frame.powerBGFrame then
|
||||
frame.powerBGFrame:ClearAllPoints()
|
||||
frame.powerBGFrame:SetPoint("TOPLEFT", frame.power, "TOPLEFT", 0, 0)
|
||||
frame.powerBGFrame:SetPoint("BOTTOMRIGHT", frame.power, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
-- Hide bar backgrounds (transparent)
|
||||
if frame.healthBGFrame then frame.healthBGFrame:Hide() end
|
||||
if frame.powerBGFrame then frame.powerBGFrame:Hide() end
|
||||
if frame.health and frame.health.bg then frame.health.bg:Hide() end
|
||||
if frame.power and frame.power.bg then frame.power.bg:Hide() end
|
||||
else
|
||||
SFrames:RemoveGradientStyle(frame.health)
|
||||
SFrames:RemoveGradientStyle(frame.power)
|
||||
-- Restore bar backgrounds
|
||||
if frame.healthBGFrame then frame.healthBGFrame:Show() end
|
||||
if frame.powerBGFrame then frame.powerBGFrame:Show() end
|
||||
if frame.health and frame.health.bg then frame.health.bg:Show() end
|
||||
if frame.power and frame.power.bg then frame.power.bg:Show() end
|
||||
|
||||
local use3D = not (SFramesDB and SFramesDB.partyPortrait3D == false)
|
||||
if use3D then
|
||||
if frame.portrait then frame.portrait:Show() end
|
||||
if frame.pbg then frame.pbg:Show() end
|
||||
else
|
||||
-- Hide portrait area and extend health/power bars to full width
|
||||
if frame.portrait then frame.portrait:Hide() end
|
||||
if frame.pbg then frame.pbg:Hide() end
|
||||
local fullWidth = metrics.width - 2
|
||||
if frame.health then
|
||||
frame.health:ClearAllPoints()
|
||||
frame.health:SetPoint("TOPLEFT", frame, "TOPLEFT", 1, -1)
|
||||
frame.health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -1, -1)
|
||||
frame.health:SetHeight(metrics.healthHeight)
|
||||
end
|
||||
if frame.healthBGFrame then
|
||||
frame.healthBGFrame:ClearAllPoints()
|
||||
frame.healthBGFrame:SetPoint("TOPLEFT", frame.health, "TOPLEFT", -1, 1)
|
||||
frame.healthBGFrame:SetPoint("BOTTOMRIGHT", frame.health, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
if frame.power then
|
||||
frame.power:SetWidth(fullWidth)
|
||||
end
|
||||
if frame.powerBGFrame then
|
||||
frame.powerBGFrame:ClearAllPoints()
|
||||
frame.powerBGFrame:SetPoint("TOPLEFT", frame.power, "TOPLEFT", -1, 1)
|
||||
frame.powerBGFrame:SetPoint("BOTTOMRIGHT", frame.power, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if frame.nameText then
|
||||
frame.nameText:SetFont(fontPath, metrics.nameFont, outline)
|
||||
SFrames:ApplyFontString(frame.nameText, metrics.nameFont, "partyNameFontKey", "fontKey")
|
||||
end
|
||||
if frame.healthText then
|
||||
frame.healthText:SetFont(fontPath, metrics.valueFont, outline)
|
||||
SFrames:ApplyFontString(frame.healthText, metrics.healthFont, "partyHealthFontKey", "fontKey")
|
||||
end
|
||||
if frame.powerText then
|
||||
SFrames:ApplyFontString(frame.powerText, metrics.powerFont, "partyPowerFontKey", "fontKey")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -250,12 +401,13 @@ function SFrames.Party:ApplyLayout()
|
||||
end
|
||||
end
|
||||
|
||||
local auraRowHeight = 24 -- 20px icon + 2px gap above + 2px padding
|
||||
if mode == "horizontal" then
|
||||
self.parent:SetWidth((metrics.width * 4) + (metrics.horizontalGap * 3))
|
||||
self.parent:SetHeight(metrics.height)
|
||||
self.parent:SetHeight(metrics.height + auraRowHeight)
|
||||
else
|
||||
self.parent:SetWidth(metrics.width)
|
||||
self.parent:SetHeight(metrics.height + ((metrics.height + metrics.verticalGap) * 3))
|
||||
self.parent:SetHeight(metrics.height + ((metrics.height + metrics.verticalGap) * 3) + auraRowHeight)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -432,11 +584,16 @@ function SFrames.Party:Initialize()
|
||||
|
||||
f.healthText = SFrames:CreateFontString(f.health, 10, "RIGHT")
|
||||
f.healthText:SetPoint("RIGHT", f.health, "RIGHT", -4, 0)
|
||||
|
||||
f.powerText = SFrames:CreateFontString(f.power, 9, "RIGHT")
|
||||
f.powerText:SetPoint("RIGHT", f.power, "RIGHT", -4, 0)
|
||||
|
||||
f.nameText:SetShadowColor(0, 0, 0, 1)
|
||||
f.nameText:SetShadowOffset(1, -1)
|
||||
f.healthText:SetShadowColor(0, 0, 0, 1)
|
||||
f.healthText:SetShadowOffset(1, -1)
|
||||
f.powerText:SetShadowColor(0, 0, 0, 1)
|
||||
f.powerText:SetShadowOffset(1, -1)
|
||||
|
||||
-- Leader / Master Looter overlay (high frame level so icons aren't hidden by portrait)
|
||||
local roleOvr = CreateFrame("Frame", nil, f)
|
||||
@@ -621,74 +778,79 @@ end
|
||||
|
||||
function SFrames.Party:CreateAuras(index)
|
||||
local f = self.frames[index].frame
|
||||
-- Use self.parent (plain Frame) as parent for aura buttons so they are
|
||||
-- never clipped by the party Button frame's boundaries.
|
||||
local auraParent = self.parent
|
||||
f.buffs = {}
|
||||
f.debuffs = {}
|
||||
local size = 20
|
||||
local spacing = 2
|
||||
|
||||
|
||||
-- Party Buffs
|
||||
for i = 1, 4 do
|
||||
local b = CreateFrame("Button", "SFramesParty"..index.."Buff"..i, f)
|
||||
local b = CreateFrame("Button", "SFramesParty"..index.."Buff"..i, auraParent)
|
||||
b:SetWidth(size)
|
||||
b:SetHeight(size)
|
||||
b:SetFrameLevel((f:GetFrameLevel() or 0) + 3)
|
||||
SFrames:CreateUnitBackdrop(b)
|
||||
|
||||
|
||||
b.icon = b:CreateTexture(nil, "ARTWORK")
|
||||
b.icon:SetAllPoints()
|
||||
b.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
|
||||
|
||||
|
||||
b.cdText = SFrames:CreateFontString(b, 9, "CENTER")
|
||||
b.cdText:SetPoint("BOTTOM", b, "BOTTOM", 0, 1)
|
||||
b.cdText:SetTextColor(1, 0.82, 0)
|
||||
b.cdText:SetShadowColor(0, 0, 0, 1)
|
||||
b.cdText:SetShadowOffset(1, -1)
|
||||
|
||||
|
||||
b:SetScript("OnEnter", function()
|
||||
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
||||
GameTooltip:SetUnitBuff(f.unit, this:GetID())
|
||||
end)
|
||||
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||||
|
||||
-- Anchored BELOW the frame on the left side
|
||||
|
||||
-- Anchored BELOW the party frame on the left side
|
||||
if i == 1 then
|
||||
b:SetPoint("TOPLEFT", f, "BOTTOMLEFT", 0, -2)
|
||||
else
|
||||
b:SetPoint("LEFT", f.buffs[i-1], "RIGHT", spacing, 0)
|
||||
end
|
||||
|
||||
|
||||
b:Hide()
|
||||
f.buffs[i] = b
|
||||
end
|
||||
|
||||
|
||||
-- Debuffs (Starting right after Buffs to remain linear)
|
||||
for i = 1, 4 do
|
||||
local b = CreateFrame("Button", "SFramesParty"..index.."Debuff"..i, f)
|
||||
local b = CreateFrame("Button", "SFramesParty"..index.."Debuff"..i, auraParent)
|
||||
b:SetWidth(size)
|
||||
b:SetHeight(size)
|
||||
b:SetFrameLevel((f:GetFrameLevel() or 0) + 3)
|
||||
SFrames:CreateUnitBackdrop(b)
|
||||
|
||||
|
||||
b.icon = b:CreateTexture(nil, "ARTWORK")
|
||||
b.icon:SetAllPoints()
|
||||
b.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
|
||||
|
||||
|
||||
b.cdText = SFrames:CreateFontString(b, 9, "CENTER")
|
||||
b.cdText:SetPoint("BOTTOM", b, "BOTTOM", 0, 1)
|
||||
b.cdText:SetTextColor(1, 0.82, 0)
|
||||
b.cdText:SetShadowColor(0, 0, 0, 1)
|
||||
b.cdText:SetShadowOffset(1, -1)
|
||||
|
||||
|
||||
b:SetScript("OnEnter", function()
|
||||
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
||||
GameTooltip:SetUnitDebuff(f.unit, this:GetID())
|
||||
end)
|
||||
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||||
|
||||
|
||||
if i == 1 then
|
||||
b:SetPoint("LEFT", f.buffs[4], "RIGHT", spacing * 4, 0)
|
||||
else
|
||||
b:SetPoint("LEFT", f.debuffs[i-1], "RIGHT", spacing, 0)
|
||||
end
|
||||
|
||||
|
||||
b:Hide()
|
||||
f.debuffs[i] = b
|
||||
end
|
||||
@@ -726,6 +888,7 @@ end
|
||||
|
||||
|
||||
function SFrames.Party:TickAuras(unit)
|
||||
if self.testing then return end
|
||||
local data = self:GetFrameByUnit(unit)
|
||||
if not data then return end
|
||||
local f = data.frame
|
||||
@@ -772,7 +935,10 @@ function SFrames.Party:UpdateAll()
|
||||
if inRaid and raidFramesEnabled then
|
||||
for i = 1, 4 do
|
||||
if self.frames[i] and self.frames[i].frame then
|
||||
self.frames[i].frame:Hide()
|
||||
local f = self.frames[i].frame
|
||||
f:Hide()
|
||||
if f.buffs then for j = 1, 4 do f.buffs[j]:Hide() end end
|
||||
if f.debuffs then for j = 1, 4 do f.debuffs[j]:Hide() end end
|
||||
end
|
||||
end
|
||||
if self._globalUpdateFrame then
|
||||
@@ -793,6 +959,8 @@ function SFrames.Party:UpdateAll()
|
||||
hasVisible = true
|
||||
else
|
||||
f:Hide()
|
||||
if f.buffs then for j = 1, 4 do f.buffs[j]:Hide() end end
|
||||
if f.debuffs then for j = 1, 4 do f.debuffs[j]:Hide() end end
|
||||
end
|
||||
end
|
||||
if self._globalUpdateFrame then
|
||||
@@ -812,11 +980,16 @@ function SFrames.Party:UpdateFrame(unit)
|
||||
if not data then return end
|
||||
local f = data.frame
|
||||
|
||||
f.portrait:SetUnit(unit)
|
||||
f.portrait:SetCamera(0)
|
||||
f.portrait:Hide()
|
||||
f.portrait:Show()
|
||||
|
||||
local use3D = not (SFramesDB and SFramesDB.partyPortrait3D == false)
|
||||
if use3D then
|
||||
f.portrait:SetUnit(unit)
|
||||
f.portrait:SetCamera(0)
|
||||
f.portrait:Hide()
|
||||
f.portrait:Show()
|
||||
else
|
||||
f.portrait:Hide()
|
||||
end
|
||||
|
||||
local name = UnitName(unit) or ""
|
||||
local level = UnitLevel(unit)
|
||||
if level == -1 then level = "??" end
|
||||
@@ -841,6 +1014,10 @@ function SFrames.Party:UpdateFrame(unit)
|
||||
f.nameText:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
-- Re-apply gradient after color change
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(f.health)
|
||||
end
|
||||
|
||||
-- Update Leader/Master Looter
|
||||
if GetPartyLeaderIndex() == data.index then
|
||||
@@ -870,6 +1047,8 @@ function SFrames.Party:UpdatePortrait(unit)
|
||||
local data = self:GetFrameByUnit(unit)
|
||||
if not data then return end
|
||||
local f = data.frame
|
||||
local use3D = not (SFramesDB and SFramesDB.partyPortrait3D == false)
|
||||
if not use3D then return end
|
||||
f.portrait:SetUnit(unit)
|
||||
f.portrait:SetCamera(0)
|
||||
f.portrait:Hide()
|
||||
@@ -917,14 +1096,8 @@ function SFrames.Party:UpdateHealPrediction(unit)
|
||||
local predOther = f.health.healPredOther
|
||||
local predOver = f.health.healPredOver
|
||||
|
||||
local function HidePredictions()
|
||||
predMine:Hide()
|
||||
predOther:Hide()
|
||||
predOver:Hide()
|
||||
end
|
||||
|
||||
if not UnitExists(unit) or not UnitIsConnected(unit) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -946,7 +1119,7 @@ function SFrames.Party:UpdateHealPrediction(unit)
|
||||
end
|
||||
|
||||
if maxHp <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -963,7 +1136,7 @@ function SFrames.Party:UpdateHealPrediction(unit)
|
||||
end
|
||||
local missing = maxHp - hp
|
||||
if missing <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -971,13 +1144,19 @@ function SFrames.Party:UpdateHealPrediction(unit)
|
||||
local remaining = missing - mineShown
|
||||
local otherShown = math.min(math.max(0, othersIncoming), remaining)
|
||||
if mineIncoming <= 0 and othersIncoming <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
local barWidth = f:GetWidth() - (f.portrait:GetWidth() + 4)
|
||||
local use3DForPred = not (SFramesDB and SFramesDB.partyPortrait3D == false)
|
||||
local barWidth
|
||||
if use3DForPred then
|
||||
barWidth = f:GetWidth() - (f.portrait:GetWidth() + 4)
|
||||
else
|
||||
barWidth = f:GetWidth() - 2
|
||||
end
|
||||
if barWidth <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1054,6 +1233,9 @@ function SFrames.Party:UpdatePowerType(unit)
|
||||
else
|
||||
f.power:SetStatusBarColor(0, 0, 1)
|
||||
end
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(f.power)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Party:UpdatePower(unit)
|
||||
@@ -1064,6 +1246,7 @@ function SFrames.Party:UpdatePower(unit)
|
||||
if not UnitIsConnected(unit) then
|
||||
f.power:SetMinMaxValues(0, 100)
|
||||
f.power:SetValue(0)
|
||||
if f.powerText then f.powerText:SetText("") end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1071,6 +1254,14 @@ function SFrames.Party:UpdatePower(unit)
|
||||
local maxPower = UnitManaMax(unit)
|
||||
f.power:SetMinMaxValues(0, maxPower)
|
||||
f.power:SetValue(power)
|
||||
if f.powerText then
|
||||
if maxPower and maxPower > 0 then
|
||||
f.powerText:SetText(SFrames:FormatCompactPair(power, maxPower))
|
||||
else
|
||||
f.powerText:SetText("")
|
||||
end
|
||||
end
|
||||
SFrames:UpdateRainbowBar(f.power, power, maxPower, unit)
|
||||
end
|
||||
|
||||
function SFrames.Party:UpdateRaidIcons()
|
||||
@@ -1106,6 +1297,7 @@ function SFrames.Party:UpdateRaidIcon(unit)
|
||||
end
|
||||
|
||||
function SFrames.Party:UpdateAuras(unit)
|
||||
if self.testing then return end
|
||||
local data = self:GetFrameByUnit(unit)
|
||||
if not data then return end
|
||||
local f = data.frame
|
||||
@@ -1114,7 +1306,9 @@ function SFrames.Party:UpdateAuras(unit)
|
||||
local showBuffs = not (SFramesDB and SFramesDB.partyShowBuffs == false)
|
||||
|
||||
local hasDebuff = false
|
||||
local debuffColor = {r=_A.slotBg[1], g=_A.slotBg[2], b=_A.slotBg[3]}
|
||||
_partyDebuffColor.r = _A.slotBg[1]
|
||||
_partyDebuffColor.g = _A.slotBg[2]
|
||||
_partyDebuffColor.b = _A.slotBg[3]
|
||||
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
|
||||
@@ -1128,10 +1322,10 @@ function SFrames.Party:UpdateAuras(unit)
|
||||
if texture then
|
||||
if debuffType then
|
||||
hasDebuff = true
|
||||
if debuffType == "Magic" then debuffColor = {r=0.2, g=0.6, b=1}
|
||||
elseif debuffType == "Curse" then debuffColor = {r=0.6, g=0, b=1}
|
||||
elseif debuffType == "Disease" then debuffColor = {r=0.6, g=0.4, b=0}
|
||||
elseif debuffType == "Poison" then debuffColor = {r=0, g=0.6, b=0}
|
||||
if debuffType == "Magic" then _partyDebuffColor.r = 0.2; _partyDebuffColor.g = 0.6; _partyDebuffColor.b = 1
|
||||
elseif debuffType == "Curse" then _partyDebuffColor.r = 0.6; _partyDebuffColor.g = 0; _partyDebuffColor.b = 1
|
||||
elseif debuffType == "Disease" then _partyDebuffColor.r = 0.6; _partyDebuffColor.g = 0.4; _partyDebuffColor.b = 0
|
||||
elseif debuffType == "Poison" then _partyDebuffColor.r = 0; _partyDebuffColor.g = 0.6; _partyDebuffColor.b = 0
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1174,7 +1368,7 @@ function SFrames.Party:UpdateAuras(unit)
|
||||
end
|
||||
|
||||
if hasDebuff then
|
||||
f.health.bg:SetVertexColor(debuffColor.r, debuffColor.g, debuffColor.b, 1)
|
||||
f.health.bg:SetVertexColor(_partyDebuffColor.r, _partyDebuffColor.g, _partyDebuffColor.b, 1)
|
||||
else
|
||||
f.health.bg:SetVertexColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 1)
|
||||
end
|
||||
@@ -1254,10 +1448,38 @@ function SFrames.Party:TestMode()
|
||||
f.masterIcon:Show()
|
||||
end
|
||||
|
||||
-- Show one dummy debuff to test positioning
|
||||
f.debuffs[1].icon:SetTexture("Interface\\Icons\\Spell_Shadow_ShadowWordPain")
|
||||
f.debuffs[1]:Show()
|
||||
|
||||
-- Show test buffs (all 4)
|
||||
local testBuffIcons = {
|
||||
"Interface\\Icons\\Spell_Holy_PowerWordFortitude",
|
||||
"Interface\\Icons\\Spell_Holy_Renew",
|
||||
"Interface\\Icons\\Spell_Holy_GreaterHeal",
|
||||
"Interface\\Icons\\Spell_Nature_Abolishmagic",
|
||||
}
|
||||
for j = 1, 4 do
|
||||
local fakeTime = math.random(30, 300)
|
||||
f.buffs[j].icon:SetTexture(testBuffIcons[j])
|
||||
f.buffs[j].expirationTime = GetTime() + fakeTime
|
||||
f.buffs[j].cdText:SetText(SFrames:FormatTime(fakeTime))
|
||||
f.buffs[j]:Show()
|
||||
end
|
||||
|
||||
-- Show test debuffs (all 4, different types for color test)
|
||||
local testDebuffIcons = {
|
||||
"Interface\\Icons\\Spell_Shadow_ShadowWordPain", -- Magic (blue)
|
||||
"Interface\\Icons\\Spell_Shadow_Curse", -- Curse (purple)
|
||||
"Interface\\Icons\\Ability_Rogue_FeignDeath", -- Disease (brown)
|
||||
"Interface\\Icons\\Ability_Poisoning", -- Poison (green)
|
||||
}
|
||||
for j = 1, 4 do
|
||||
local debuffTime = math.random(5, 25)
|
||||
f.debuffs[j].icon:SetTexture(testDebuffIcons[j])
|
||||
f.debuffs[j].expirationTime = GetTime() + debuffTime
|
||||
f.debuffs[j].cdText:SetText(SFrames:FormatTime(debuffTime))
|
||||
f.debuffs[j]:Show()
|
||||
end
|
||||
-- Magic debuff background color
|
||||
f.health.bg:SetVertexColor(0.2, 0.6, 1, 1)
|
||||
|
||||
-- Test pet
|
||||
if f.petFrame then
|
||||
f.petFrame:Show()
|
||||
@@ -1268,9 +1490,18 @@ function SFrames.Party:TestMode()
|
||||
end
|
||||
end
|
||||
else
|
||||
self:UpdateAll()
|
||||
for i = 1, 4 do
|
||||
self.frames[i].frame.debuffs[1]:Hide()
|
||||
local f = self.frames[i].frame
|
||||
f.health.bg:SetVertexColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 1)
|
||||
for j = 1, 4 do
|
||||
f.buffs[j].expirationTime = nil
|
||||
f.buffs[j].cdText:SetText("")
|
||||
f.buffs[j]:Hide()
|
||||
f.debuffs[j].expirationTime = nil
|
||||
f.debuffs[j].cdText:SetText("")
|
||||
f.debuffs[j]:Hide()
|
||||
end
|
||||
end
|
||||
self:UpdateAll()
|
||||
end
|
||||
end
|
||||
|
||||
141
Units/Pet.lua
141
Units/Pet.lua
@@ -225,16 +225,22 @@ function SFrames.Pet:Initialize()
|
||||
local f = CreateFrame("Button", "SFramesPetFrame", UIParent)
|
||||
f:SetWidth(150)
|
||||
f:SetHeight(30)
|
||||
|
||||
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["PetFrame"] then
|
||||
local pos = SFramesDB.Positions["PetFrame"]
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs, pos.yOfs)
|
||||
else
|
||||
f:SetPoint("TOPLEFT", SFramesPlayerFrame, "BOTTOMLEFT", 10, -55)
|
||||
end
|
||||
|
||||
|
||||
local frameScale = (SFramesDB and type(SFramesDB.petFrameScale) == "number") and SFramesDB.petFrameScale or 1
|
||||
f:SetScale(Clamp(frameScale, 0.7, 1.8))
|
||||
|
||||
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["PetFrame"] then
|
||||
local pos = SFramesDB.Positions["PetFrame"]
|
||||
local fScale = f:GetEffectiveScale() / UIParent:GetEffectiveScale()
|
||||
if fScale > 0.01 and math.abs(fScale - 1) > 0.001 then
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint,
|
||||
(pos.xOfs or 0) / fScale, (pos.yOfs or 0) / fScale)
|
||||
else
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs or 0, pos.yOfs or 0)
|
||||
end
|
||||
else
|
||||
f:SetPoint("TOPLEFT", SFramesPlayerFrame, "BOTTOMLEFT", 0, -75)
|
||||
end
|
||||
|
||||
f:SetMovable(true)
|
||||
f:EnableMouse(true)
|
||||
@@ -245,6 +251,11 @@ function SFrames.Pet:Initialize()
|
||||
if not SFramesDB then SFramesDB = {} end
|
||||
if not SFramesDB.Positions then SFramesDB.Positions = {} end
|
||||
local point, relativeTo, relativePoint, xOfs, yOfs = f:GetPoint()
|
||||
local fScale = f:GetEffectiveScale() / UIParent:GetEffectiveScale()
|
||||
if fScale > 0.01 and math.abs(fScale - 1) > 0.001 then
|
||||
xOfs = (xOfs or 0) * fScale
|
||||
yOfs = (yOfs or 0) * fScale
|
||||
end
|
||||
SFramesDB.Positions["PetFrame"] = { point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs }
|
||||
end)
|
||||
|
||||
@@ -294,6 +305,8 @@ function SFrames.Pet:Initialize()
|
||||
hbg:SetFrameLevel(f:GetFrameLevel() - 1)
|
||||
SFrames:CreateUnitBackdrop(hbg)
|
||||
|
||||
f.healthBGFrame = hbg
|
||||
|
||||
f.health.bg = f.health:CreateTexture(nil, "BACKGROUND")
|
||||
f.health.bg:SetAllPoints()
|
||||
f.health.bg:SetTexture(SFrames:GetTexture())
|
||||
@@ -328,6 +341,7 @@ function SFrames.Pet:Initialize()
|
||||
pbg:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 1, -1)
|
||||
pbg:SetFrameLevel(f:GetFrameLevel() - 1)
|
||||
SFrames:CreateUnitBackdrop(pbg)
|
||||
f.powerBGFrame = pbg
|
||||
|
||||
f.power.bg = f.power:CreateTexture(nil, "BACKGROUND")
|
||||
f.power.bg:SetAllPoints()
|
||||
@@ -394,11 +408,13 @@ function SFrames.Pet:Initialize()
|
||||
SFrames:RegisterEvent("PLAYER_ENTERING_WORLD", function() self:UpdateAll() end)
|
||||
|
||||
self:InitFoodFeature()
|
||||
self:ApplyConfig()
|
||||
self:UpdateAll()
|
||||
|
||||
if SFrames.Movers and SFrames.Movers.RegisterMover and self.frame then
|
||||
SFrames.Movers:RegisterMover("PetFrame", self.frame, "宠物",
|
||||
"TOPLEFT", "SFramesPlayerFrame", "BOTTOMLEFT", 10, -55)
|
||||
"TOPLEFT", "SFramesPlayerFrame", "BOTTOMLEFT", 0, -75,
|
||||
nil, { alwaysShowInLayout = true })
|
||||
end
|
||||
|
||||
if StaticPopup_Show then
|
||||
@@ -413,6 +429,90 @@ function SFrames.Pet:Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Pet:ApplyConfig()
|
||||
if not self.frame then return end
|
||||
local f = self.frame
|
||||
|
||||
-- Apply bar textures
|
||||
SFrames:ApplyStatusBarTexture(f.health, "petHealthTexture", "barTexture")
|
||||
SFrames:ApplyStatusBarTexture(f.power, "petPowerTexture", "barTexture")
|
||||
local healthTex = SFrames:ResolveBarTexture("petHealthTexture", "barTexture")
|
||||
local powerTex = SFrames:ResolveBarTexture("petPowerTexture", "barTexture")
|
||||
if f.health and f.health.bg then f.health.bg:SetTexture(healthTex) end
|
||||
if f.power and f.power.bg then f.power.bg:SetTexture(powerTex) end
|
||||
|
||||
if SFrames:IsGradientStyle() then
|
||||
-- Strip backdrops
|
||||
SFrames:ClearBackdrop(f)
|
||||
SFrames:ClearBackdrop(f.healthBGFrame)
|
||||
SFrames:ClearBackdrop(f.powerBGFrame)
|
||||
-- Health bar full width
|
||||
if f.health then
|
||||
f.health:ClearAllPoints()
|
||||
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
|
||||
f.health:SetHeight(18)
|
||||
end
|
||||
-- Power bar full width
|
||||
if f.power then
|
||||
f.power:ClearAllPoints()
|
||||
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", 0, -2)
|
||||
f.power:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
-- Apply gradient overlays
|
||||
SFrames:ApplyGradientStyle(f.health)
|
||||
SFrames:ApplyGradientStyle(f.power)
|
||||
-- Flush BG frames
|
||||
if f.healthBGFrame then
|
||||
f.healthBGFrame:ClearAllPoints()
|
||||
f.healthBGFrame:SetPoint("TOPLEFT", f.health, "TOPLEFT", 0, 0)
|
||||
f.healthBGFrame:SetPoint("BOTTOMRIGHT", f.health, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
if f.powerBGFrame then
|
||||
f.powerBGFrame:ClearAllPoints()
|
||||
f.powerBGFrame:SetPoint("TOPLEFT", f.power, "TOPLEFT", 0, 0)
|
||||
f.powerBGFrame:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
-- Hide bar backgrounds (transparent)
|
||||
if f.healthBGFrame then f.healthBGFrame:Hide() end
|
||||
if f.powerBGFrame then f.powerBGFrame:Hide() end
|
||||
if f.health and f.health.bg then f.health.bg:Hide() end
|
||||
if f.power and f.power.bg then f.power.bg:Hide() end
|
||||
else
|
||||
-- Classic style: restore backdrops
|
||||
SFrames:CreateUnitBackdrop(f)
|
||||
if f.health and f.health.bg then f.health.bg:Show() end
|
||||
if f.power and f.power.bg then f.power.bg:Show() end
|
||||
if f.healthBGFrame then
|
||||
SFrames:CreateUnitBackdrop(f.healthBGFrame)
|
||||
f.healthBGFrame:Show()
|
||||
f.healthBGFrame:ClearAllPoints()
|
||||
f.healthBGFrame:SetPoint("TOPLEFT", f.health, "TOPLEFT", -1, 1)
|
||||
f.healthBGFrame:SetPoint("BOTTOMRIGHT", f.health, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
if f.powerBGFrame then
|
||||
SFrames:CreateUnitBackdrop(f.powerBGFrame)
|
||||
f.powerBGFrame:Show()
|
||||
f.powerBGFrame:ClearAllPoints()
|
||||
f.powerBGFrame:SetPoint("TOPLEFT", f.power, "TOPLEFT", -1, 1)
|
||||
f.powerBGFrame:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
if f.health then
|
||||
f.health:ClearAllPoints()
|
||||
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 1, -1)
|
||||
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, -1)
|
||||
f.health:SetHeight(18)
|
||||
end
|
||||
if f.power then
|
||||
f.power:ClearAllPoints()
|
||||
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", 0, -1)
|
||||
f.power:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
|
||||
end
|
||||
SFrames:RemoveGradientStyle(f.health)
|
||||
SFrames:RemoveGradientStyle(f.power)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Pet:UpdateAll()
|
||||
if UnitExists("pet") then
|
||||
if SFramesDB and SFramesDB.showPetFrame == false then
|
||||
@@ -437,6 +537,9 @@ function SFrames.Pet:UpdateAll()
|
||||
|
||||
local r, g, b = 0.33, 0.59, 0.33
|
||||
self.frame.health:SetStatusBarColor(r, g, b)
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(self.frame.health)
|
||||
end
|
||||
else
|
||||
self.frame:Hide()
|
||||
if self.foodPanel then self.foodPanel:Hide() end
|
||||
@@ -465,12 +568,6 @@ function SFrames.Pet:UpdateHealPrediction()
|
||||
local predOther = self.frame.health.healPredOther
|
||||
local predOver = self.frame.health.healPredOver
|
||||
|
||||
local function HidePredictions()
|
||||
predMine:Hide()
|
||||
predOther:Hide()
|
||||
predOver:Hide()
|
||||
end
|
||||
|
||||
local hp = UnitHealth("pet") or 0
|
||||
local maxHp = UnitHealthMax("pet") or 0
|
||||
|
||||
@@ -485,7 +582,7 @@ function SFrames.Pet:UpdateHealPrediction()
|
||||
end
|
||||
|
||||
if maxHp <= 0 or UnitIsDeadOrGhost("pet") then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -497,7 +594,7 @@ function SFrames.Pet:UpdateHealPrediction()
|
||||
|
||||
local missing = maxHp - hp
|
||||
if missing <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -505,13 +602,13 @@ function SFrames.Pet:UpdateHealPrediction()
|
||||
local remaining = missing - mineShown
|
||||
local otherShown = math.min(math.max(0, othersIncoming), remaining)
|
||||
if mineShown <= 0 and otherShown <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
local barWidth = self.frame.health:GetWidth()
|
||||
if barWidth <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -521,7 +618,7 @@ function SFrames.Pet:UpdateHealPrediction()
|
||||
|
||||
local availableWidth = barWidth - currentWidth
|
||||
if availableWidth <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -587,6 +684,9 @@ function SFrames.Pet:UpdatePowerType()
|
||||
else
|
||||
self.frame.power:SetStatusBarColor(0, 0, 1)
|
||||
end
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(self.frame.power)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Pet:UpdatePower()
|
||||
@@ -594,6 +694,7 @@ function SFrames.Pet:UpdatePower()
|
||||
local maxPower = UnitManaMax("pet")
|
||||
self.frame.power:SetMinMaxValues(0, maxPower)
|
||||
self.frame.power:SetValue(power)
|
||||
SFrames:UpdateRainbowBar(self.frame.power, power, maxPower, "pet")
|
||||
end
|
||||
|
||||
function SFrames.Pet:UpdateHappiness()
|
||||
|
||||
866
Units/Player.lua
866
Units/Player.lua
File diff suppressed because it is too large
Load Diff
297
Units/Raid.lua
297
Units/Raid.lua
@@ -9,10 +9,76 @@ local UNIT_PADDING = 2
|
||||
local RAID_UNIT_LOOKUP = {}
|
||||
for i = 1, 40 do RAID_UNIT_LOOKUP["raid" .. i] = true end
|
||||
|
||||
-- Pre-allocated tables reused every UpdateAuras call to avoid per-call garbage
|
||||
local _foundIndicators = { [1] = false, [2] = false, [3] = false, [4] = false }
|
||||
local _debuffColor = { r = 0, g = 0, b = 0 }
|
||||
|
||||
-- Module-level helper: match aura name against a list (no closure allocation)
|
||||
local function MatchesList(auraName, list)
|
||||
for _, name in ipairs(list) do
|
||||
if string.find(auraName, name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Module-level helper: get buff name via SuperWoW aura ID or tooltip scan
|
||||
local function RaidGetBuffName(unit, index)
|
||||
if SFrames.superwow_active and SpellInfo then
|
||||
local texture, auraID = UnitBuff(unit, index)
|
||||
if auraID and SpellInfo then
|
||||
local spellName = SpellInfo(auraID)
|
||||
if spellName and spellName ~= "" then
|
||||
return spellName, texture
|
||||
end
|
||||
end
|
||||
end
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:SetUnitBuff(unit, index)
|
||||
local buffName = SFramesScanTooltipTextLeft1:GetText()
|
||||
SFrames.Tooltip:Hide()
|
||||
return buffName, UnitBuff(unit, index)
|
||||
end
|
||||
|
||||
local function RaidGetDebuffName(unit, index)
|
||||
if SFrames.superwow_active and SpellInfo then
|
||||
local texture, count, dtype, auraID = UnitDebuff(unit, index)
|
||||
if auraID and SpellInfo then
|
||||
local spellName = SpellInfo(auraID)
|
||||
if spellName and spellName ~= "" then
|
||||
return spellName, texture, count, dtype
|
||||
end
|
||||
end
|
||||
end
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:SetUnitDebuff(unit, index)
|
||||
local debuffName = SFramesScanTooltipTextLeft1:GetText()
|
||||
SFrames.Tooltip:Hide()
|
||||
local texture, count, dtype = UnitDebuff(unit, index)
|
||||
return debuffName, texture, count, dtype
|
||||
end
|
||||
|
||||
local function GetIncomingHeals(unit)
|
||||
return SFrames:GetIncomingHeals(unit)
|
||||
end
|
||||
|
||||
local function Clamp(value, minValue, maxValue)
|
||||
if value < minValue then
|
||||
return minValue
|
||||
end
|
||||
if value > maxValue then
|
||||
return maxValue
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function SetTextureIfPresent(region, texturePath)
|
||||
if region and region.SetTexture and texturePath then
|
||||
region:SetTexture(texturePath)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Raid:GetMetrics()
|
||||
local db = SFramesDB or {}
|
||||
|
||||
@@ -25,29 +91,66 @@ function SFrames.Raid:GetMetrics()
|
||||
local healthHeight = tonumber(db.raidHealthHeight) or math.floor((height - 3) * 0.8)
|
||||
healthHeight = math.max(10, math.min(height - 6, healthHeight))
|
||||
|
||||
local powerHeight = height - healthHeight - 3
|
||||
local powerHeight = tonumber(db.raidPowerHeight) or (height - healthHeight - 3)
|
||||
powerHeight = math.max(0, math.min(height - 3, powerHeight))
|
||||
if not db.raidShowPower then
|
||||
powerHeight = 0
|
||||
healthHeight = height - 2
|
||||
end
|
||||
|
||||
local gradientStyle = SFrames:IsGradientStyle()
|
||||
local availablePowerWidth = width - 2
|
||||
if availablePowerWidth < 20 then
|
||||
availablePowerWidth = 20
|
||||
end
|
||||
|
||||
local rawPowerWidth = tonumber(db.raidPowerWidth)
|
||||
local legacyFullWidth = tonumber(db.raidFrameWidth) or width
|
||||
local defaultPowerWidth = gradientStyle and width or availablePowerWidth
|
||||
local maxPowerWidth = gradientStyle and width or availablePowerWidth
|
||||
local powerWidth
|
||||
if gradientStyle then
|
||||
-- 渐变风格:能量条始终与血条等宽(全宽)
|
||||
powerWidth = width
|
||||
elseif not rawPowerWidth
|
||||
or math.abs(rawPowerWidth - legacyFullWidth) < 0.5
|
||||
or math.abs(rawPowerWidth - availablePowerWidth) < 0.5 then
|
||||
powerWidth = defaultPowerWidth
|
||||
else
|
||||
powerWidth = rawPowerWidth
|
||||
end
|
||||
powerWidth = Clamp(math.floor(powerWidth + 0.5), 20, maxPowerWidth)
|
||||
|
||||
local powerOffsetX = Clamp(math.floor((tonumber(db.raidPowerOffsetX) or 0) + 0.5), -120, 120)
|
||||
local powerOffsetY = Clamp(math.floor((tonumber(db.raidPowerOffsetY) or 0) + 0.5), -80, 80)
|
||||
|
||||
local hgap = tonumber(db.raidHorizontalGap) or UNIT_PADDING
|
||||
local vgap = tonumber(db.raidVerticalGap) or UNIT_PADDING
|
||||
local groupGap = tonumber(db.raidGroupGap) or GROUP_PADDING
|
||||
|
||||
local nameFont = tonumber(db.raidNameFontSize) or 10
|
||||
local valueFont = tonumber(db.raidValueFontSize) or 9
|
||||
local healthFont = tonumber(db.raidHealthFontSize) or valueFont
|
||||
local powerFont = tonumber(db.raidPowerFontSize) or valueFont
|
||||
|
||||
return {
|
||||
width = width,
|
||||
height = height,
|
||||
healthHeight = healthHeight,
|
||||
powerHeight = powerHeight,
|
||||
powerWidth = powerWidth,
|
||||
powerOffsetX = powerOffsetX,
|
||||
powerOffsetY = powerOffsetY,
|
||||
powerOnTop = db.raidPowerOnTop == true,
|
||||
horizontalGap = hgap,
|
||||
verticalGap = vgap,
|
||||
groupGap = groupGap,
|
||||
nameFont = nameFont,
|
||||
valueFont = valueFont,
|
||||
healthFont = healthFont,
|
||||
powerFont = powerFont,
|
||||
healthTexture = SFrames:ResolveBarTexture("raidHealthTexture", "barTexture"),
|
||||
powerTexture = SFrames:ResolveBarTexture("raidPowerTexture", "barTexture"),
|
||||
showPower = db.raidShowPower ~= false,
|
||||
}
|
||||
end
|
||||
@@ -87,8 +190,8 @@ function SFrames.Raid:ApplyFrameStyle(frame, metrics)
|
||||
frame.power:Show()
|
||||
if frame.powerBGFrame then frame.powerBGFrame:Show() end
|
||||
frame.power:ClearAllPoints()
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", 0, -1)
|
||||
frame.power:SetPoint("TOPRIGHT", frame.health, "BOTTOMRIGHT", 0, 0)
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", metrics.powerOffsetX, -1 + metrics.powerOffsetY)
|
||||
frame.power:SetWidth(metrics.powerWidth)
|
||||
frame.power:SetHeight(metrics.powerHeight)
|
||||
else
|
||||
frame.power:Hide()
|
||||
@@ -96,14 +199,80 @@ function SFrames.Raid:ApplyFrameStyle(frame, metrics)
|
||||
end
|
||||
end
|
||||
|
||||
local outline = (SFrames and SFrames.Media and SFrames.Media.fontOutline) or "OUTLINE"
|
||||
local fontPath = SFrames:GetFont()
|
||||
SFrames:ApplyStatusBarTexture(frame.health, "raidHealthTexture", "barTexture")
|
||||
SFrames:ApplyStatusBarTexture(frame.power, "raidPowerTexture", "barTexture")
|
||||
if frame.health and frame.power then
|
||||
local healthLevel = frame:GetFrameLevel() + 2
|
||||
local powerLevel = metrics.powerOnTop and (healthLevel + 1) or (healthLevel - 1)
|
||||
frame.health:SetFrameLevel(healthLevel)
|
||||
frame.power:SetFrameLevel(powerLevel)
|
||||
end
|
||||
SFrames:ApplyConfiguredUnitBackdrop(frame, "raid")
|
||||
if frame.healthBGFrame then SFrames:ApplyConfiguredUnitBackdrop(frame.healthBGFrame, "raid") end
|
||||
if frame.powerBGFrame then SFrames:ApplyConfiguredUnitBackdrop(frame.powerBGFrame, "raid") end
|
||||
SetTextureIfPresent(frame.health and frame.health.bg, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredMine, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredOther, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.health and frame.health.healPredOver, metrics.healthTexture)
|
||||
SetTextureIfPresent(frame.power and frame.power.bg, metrics.powerTexture)
|
||||
|
||||
-- Gradient style preset
|
||||
if SFrames:IsGradientStyle() then
|
||||
-- Strip backdrops
|
||||
SFrames:ClearBackdrop(frame)
|
||||
SFrames:ClearBackdrop(frame.healthBGFrame)
|
||||
SFrames:ClearBackdrop(frame.powerBGFrame)
|
||||
-- Health bar full width
|
||||
if frame.health then
|
||||
frame.health:ClearAllPoints()
|
||||
frame.health:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
|
||||
frame.health:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
|
||||
frame.health:SetHeight(metrics.healthHeight)
|
||||
end
|
||||
-- Power bar full width
|
||||
if frame.power and metrics.showPower then
|
||||
frame.power:ClearAllPoints()
|
||||
frame.power:SetPoint("TOPLEFT", frame.health, "BOTTOMLEFT", metrics.powerOffsetX, -1 + metrics.powerOffsetY)
|
||||
frame.power:SetWidth(metrics.powerWidth)
|
||||
frame.power:SetHeight(metrics.powerHeight)
|
||||
end
|
||||
-- Apply gradient overlays
|
||||
SFrames:ApplyGradientStyle(frame.health)
|
||||
SFrames:ApplyGradientStyle(frame.power)
|
||||
-- Flush BG frames
|
||||
if frame.healthBGFrame then
|
||||
frame.healthBGFrame:ClearAllPoints()
|
||||
frame.healthBGFrame:SetPoint("TOPLEFT", frame.health, "TOPLEFT", 0, 0)
|
||||
frame.healthBGFrame:SetPoint("BOTTOMRIGHT", frame.health, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
if frame.powerBGFrame then
|
||||
frame.powerBGFrame:ClearAllPoints()
|
||||
frame.powerBGFrame:SetPoint("TOPLEFT", frame.power, "TOPLEFT", 0, 0)
|
||||
frame.powerBGFrame:SetPoint("BOTTOMRIGHT", frame.power, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
-- Hide bar backgrounds (transparent)
|
||||
if frame.healthBGFrame then frame.healthBGFrame:Hide() end
|
||||
if frame.powerBGFrame then frame.powerBGFrame:Hide() end
|
||||
if frame.health and frame.health.bg then frame.health.bg:Hide() end
|
||||
if frame.power and frame.power.bg then frame.power.bg:Hide() end
|
||||
else
|
||||
SFrames:RemoveGradientStyle(frame.health)
|
||||
SFrames:RemoveGradientStyle(frame.power)
|
||||
-- Restore bar backgrounds
|
||||
if frame.healthBGFrame then frame.healthBGFrame:Show() end
|
||||
if frame.powerBGFrame then frame.powerBGFrame:Show() end
|
||||
if frame.health and frame.health.bg then frame.health.bg:Show() end
|
||||
if frame.power and frame.power.bg then frame.power.bg:Show() end
|
||||
end
|
||||
|
||||
if frame.nameText then
|
||||
frame.nameText:SetFont(fontPath, metrics.nameFont, outline)
|
||||
SFrames:ApplyFontString(frame.nameText, metrics.nameFont, "raidNameFontKey", "fontKey")
|
||||
end
|
||||
if frame.healthText then
|
||||
frame.healthText:SetFont(fontPath, metrics.valueFont, outline)
|
||||
SFrames:ApplyFontString(frame.healthText, metrics.healthFont, "raidHealthFontKey", "fontKey")
|
||||
end
|
||||
if frame.powerText then
|
||||
SFrames:ApplyFontString(frame.powerText, metrics.powerFont, "raidPowerFontKey", "fontKey")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -724,6 +893,9 @@ function SFrames.Raid:UpdateFrame(unit)
|
||||
f.nameText:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(f.health)
|
||||
end
|
||||
|
||||
self:UpdateHealth(unit)
|
||||
self:UpdatePower(unit)
|
||||
@@ -794,11 +966,10 @@ function SFrames.Raid:UpdateHealth(unit)
|
||||
txt = percent .. "%"
|
||||
elseif db.raidHealthFormat == "deficit" then
|
||||
if maxHp - hp > 0 then
|
||||
txt = "-" .. (maxHp - hp)
|
||||
txt = "-" .. SFrames:FormatCompactNumber(maxHp - hp)
|
||||
end
|
||||
else
|
||||
txt = (math.floor(hp/100)/10).."k" -- default compact e.g. 4.5k
|
||||
if hp < 1000 then txt = tostring(hp) end
|
||||
txt = SFrames:FormatCompactNumber(hp)
|
||||
end
|
||||
|
||||
f.healthText:SetText(txt)
|
||||
@@ -826,14 +997,8 @@ function SFrames.Raid:UpdateHealPrediction(unit)
|
||||
local predOther = f.health.healPredOther
|
||||
local predOver = f.health.healPredOver
|
||||
|
||||
local function HidePredictions()
|
||||
predMine:Hide()
|
||||
predOther:Hide()
|
||||
predOver:Hide()
|
||||
end
|
||||
|
||||
if not UnitExists(unit) or not UnitIsConnected(unit) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -855,7 +1020,7 @@ function SFrames.Raid:UpdateHealPrediction(unit)
|
||||
end
|
||||
|
||||
if maxHp <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -872,7 +1037,7 @@ function SFrames.Raid:UpdateHealPrediction(unit)
|
||||
end
|
||||
local missing = maxHp - hp
|
||||
if missing <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -880,13 +1045,13 @@ function SFrames.Raid:UpdateHealPrediction(unit)
|
||||
local remaining = missing - mineShown
|
||||
local otherShown = math.min(math.max(0, othersIncoming), remaining)
|
||||
if mineIncoming <= 0 and othersIncoming <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
local barWidth = f:GetWidth() - 2
|
||||
if barWidth <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -896,7 +1061,7 @@ function SFrames.Raid:UpdateHealPrediction(unit)
|
||||
|
||||
local availableWidth = barWidth - currentPosition
|
||||
if availableWidth <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -972,6 +1137,10 @@ function SFrames.Raid:UpdatePower(unit)
|
||||
local pType = UnitPowerType(unit)
|
||||
local color = SFrames.Config.colors.power[pType] or SFrames.Config.colors.power[0]
|
||||
f.power:SetStatusBarColor(color.r, color.g, color.b)
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(f.power)
|
||||
end
|
||||
SFrames:UpdateRainbowBar(f.power, power, maxPower, unit)
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -1072,7 +1241,11 @@ function SFrames.Raid:UpdateAuras(unit)
|
||||
local f = frameData.frame
|
||||
local buffsNeeded = self:GetClassBuffs()
|
||||
|
||||
local foundIndicators = { [1] = false, [2] = false, [3] = false, [4] = false }
|
||||
-- Reuse pre-allocated table
|
||||
_foundIndicators[1] = false
|
||||
_foundIndicators[2] = false
|
||||
_foundIndicators[3] = false
|
||||
_foundIndicators[4] = false
|
||||
|
||||
-- Hide all first
|
||||
for i = 1, 4 do
|
||||
@@ -1085,70 +1258,22 @@ function SFrames.Raid:UpdateAuras(unit)
|
||||
return
|
||||
end
|
||||
|
||||
local function MatchesList(auraName, list)
|
||||
for _, name in ipairs(list) do
|
||||
if string.find(auraName, name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Helper: get buff name via SuperWoW aura ID (fast) or tooltip scan (fallback)
|
||||
local hasSuperWoW = SFrames.superwow_active and SpellInfo
|
||||
local function GetBuffName(unit, index)
|
||||
if hasSuperWoW then
|
||||
local texture, auraID = UnitBuff(unit, index)
|
||||
if auraID and SpellInfo then
|
||||
local spellName = SpellInfo(auraID)
|
||||
if spellName and spellName ~= "" then
|
||||
return spellName, texture
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fallback: tooltip scan
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:SetUnitBuff(unit, index)
|
||||
local buffName = SFramesScanTooltipTextLeft1:GetText()
|
||||
SFrames.Tooltip:Hide()
|
||||
return buffName, UnitBuff(unit, index)
|
||||
end
|
||||
|
||||
local function GetDebuffName(unit, index)
|
||||
if hasSuperWoW then
|
||||
local texture, count, dtype, auraID = UnitDebuff(unit, index)
|
||||
if auraID and SpellInfo then
|
||||
local spellName = SpellInfo(auraID)
|
||||
if spellName and spellName ~= "" then
|
||||
return spellName, texture, count, dtype
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fallback: tooltip scan
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:SetUnitDebuff(unit, index)
|
||||
local debuffName = SFramesScanTooltipTextLeft1:GetText()
|
||||
SFrames.Tooltip:Hide()
|
||||
local texture, count, dtype = UnitDebuff(unit, index)
|
||||
return debuffName, texture, count, dtype
|
||||
end
|
||||
|
||||
-- Check Buffs
|
||||
-- Check Buffs (using module-level helpers, no closures)
|
||||
for i = 1, 32 do
|
||||
local texture, applications = UnitBuff(unit, i)
|
||||
if not texture then break end
|
||||
|
||||
local buffName = GetBuffName(unit, i)
|
||||
local buffName = RaidGetBuffName(unit, i)
|
||||
|
||||
if buffName then
|
||||
for pos, listData in pairs(buffsNeeded) do
|
||||
if pos <= 4 and not listData.isDebuff and not foundIndicators[pos] then
|
||||
if pos <= 4 and not listData.isDebuff and not _foundIndicators[pos] then
|
||||
if MatchesList(buffName, listData) then
|
||||
f.indicators[pos].icon:SetTexture(texture)
|
||||
f.indicators[pos].index = i
|
||||
f.indicators[pos].isDebuff = false
|
||||
f.indicators[pos]:Show()
|
||||
foundIndicators[pos] = true
|
||||
_foundIndicators[pos] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1156,7 +1281,10 @@ function SFrames.Raid:UpdateAuras(unit)
|
||||
end
|
||||
|
||||
local hasDebuff = false
|
||||
local debuffColor = {r=_A.slotBg[1], g=_A.slotBg[2], b=_A.slotBg[3]}
|
||||
-- Reuse pre-allocated table
|
||||
_debuffColor.r = _A.slotBg[1]
|
||||
_debuffColor.g = _A.slotBg[2]
|
||||
_debuffColor.b = _A.slotBg[3]
|
||||
|
||||
-- Check Debuffs
|
||||
for i = 1, 16 do
|
||||
@@ -1165,24 +1293,24 @@ function SFrames.Raid:UpdateAuras(unit)
|
||||
|
||||
if dispelType then
|
||||
hasDebuff = true
|
||||
if dispelType == "Magic" then debuffColor = {r=0.2, g=0.6, b=1}
|
||||
elseif dispelType == "Curse" then debuffColor = {r=0.6, g=0, b=1}
|
||||
elseif dispelType == "Disease" then debuffColor = {r=0.6, g=0.4, b=0}
|
||||
elseif dispelType == "Poison" then debuffColor = {r=0, g=0.6, b=0}
|
||||
if dispelType == "Magic" then _debuffColor.r = 0.2; _debuffColor.g = 0.6; _debuffColor.b = 1
|
||||
elseif dispelType == "Curse" then _debuffColor.r = 0.6; _debuffColor.g = 0; _debuffColor.b = 1
|
||||
elseif dispelType == "Disease" then _debuffColor.r = 0.6; _debuffColor.g = 0.4; _debuffColor.b = 0
|
||||
elseif dispelType == "Poison" then _debuffColor.r = 0; _debuffColor.g = 0.6; _debuffColor.b = 0
|
||||
end
|
||||
end
|
||||
|
||||
local debuffName = GetDebuffName(unit, i)
|
||||
local debuffName = RaidGetDebuffName(unit, i)
|
||||
|
||||
if debuffName then
|
||||
for pos, listData in pairs(buffsNeeded) do
|
||||
if pos <= 4 and listData.isDebuff and not foundIndicators[pos] then
|
||||
if pos <= 4 and listData.isDebuff and not _foundIndicators[pos] then
|
||||
if MatchesList(debuffName, listData) then
|
||||
f.indicators[pos].icon:SetTexture(texture)
|
||||
f.indicators[pos].index = i
|
||||
f.indicators[pos].isDebuff = true
|
||||
f.indicators[pos]:Show()
|
||||
foundIndicators[pos] = true
|
||||
_foundIndicators[pos] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1190,9 +1318,8 @@ function SFrames.Raid:UpdateAuras(unit)
|
||||
end
|
||||
|
||||
if hasDebuff then
|
||||
f.health.bg:SetVertexColor(debuffColor.r, debuffColor.g, debuffColor.b, 1)
|
||||
f.health.bg:SetVertexColor(_debuffColor.r, _debuffColor.g, _debuffColor.b, 1)
|
||||
else
|
||||
f.health.bg:SetVertexColor(_A.slotBg[1], _A.slotBg[2], _A.slotBg[3], _A.slotBg[4] or 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
416
Units/Target.lua
416
Units/Target.lua
@@ -182,6 +182,17 @@ local function Clamp(value, minValue, maxValue)
|
||||
return value
|
||||
end
|
||||
|
||||
local function SetTextureIfPresent(region, texturePath)
|
||||
if region and region.SetTexture and texturePath then
|
||||
region:SetTexture(texturePath)
|
||||
end
|
||||
end
|
||||
|
||||
local function ApplyFontIfPresent(fs, size, fontKey, fallbackFontKey)
|
||||
if not fs then return end
|
||||
SFrames:ApplyFontString(fs, size, fontKey, fallbackFontKey)
|
||||
end
|
||||
|
||||
local DIST_BASE_WIDTH = 80
|
||||
local DIST_BASE_HEIGHT = 24
|
||||
local DIST_BASE_FONTSIZE = 14
|
||||
@@ -232,6 +243,33 @@ function SFrames.Target:GetConfig()
|
||||
local powerHeight = tonumber(db.targetPowerHeight) or 9
|
||||
powerHeight = Clamp(math.floor(powerHeight + 0.5), 6, 40)
|
||||
|
||||
local showPortrait = db.targetShowPortrait ~= false
|
||||
local gradientStyle = SFrames:IsGradientStyle()
|
||||
local classicDefaultPowerWidth = width - (showPortrait and portraitWidth or 0) - 2
|
||||
if classicDefaultPowerWidth < 60 then
|
||||
classicDefaultPowerWidth = 60
|
||||
end
|
||||
|
||||
local rawPowerWidth = tonumber(db.targetPowerWidth)
|
||||
local legacyFullWidth = tonumber(db.targetFrameWidth) or width
|
||||
local defaultPowerWidth = gradientStyle and width or classicDefaultPowerWidth
|
||||
local maxPowerWidth = gradientStyle and width or (width - 2)
|
||||
local powerWidth
|
||||
if gradientStyle then
|
||||
-- 渐变风格:能量条始终与血条等宽(全宽)
|
||||
powerWidth = width
|
||||
elseif not rawPowerWidth
|
||||
or math.abs(rawPowerWidth - legacyFullWidth) < 0.5
|
||||
or math.abs(rawPowerWidth - classicDefaultPowerWidth) < 0.5 then
|
||||
powerWidth = defaultPowerWidth
|
||||
else
|
||||
powerWidth = rawPowerWidth
|
||||
end
|
||||
powerWidth = Clamp(math.floor(powerWidth + 0.5), 60, maxPowerWidth)
|
||||
|
||||
local powerOffsetX = Clamp(math.floor((tonumber(db.targetPowerOffsetX) or 0) + 0.5), -120, 120)
|
||||
local powerOffsetY = Clamp(math.floor((tonumber(db.targetPowerOffsetY) or 0) + 0.5), -80, 80)
|
||||
|
||||
local height = healthHeight + powerHeight + 4
|
||||
height = Clamp(height, 30, 140)
|
||||
|
||||
@@ -241,6 +279,12 @@ function SFrames.Target:GetConfig()
|
||||
local valueFont = tonumber(db.targetValueFontSize) or 10
|
||||
valueFont = Clamp(math.floor(valueFont + 0.5), 8, 18)
|
||||
|
||||
local healthFont = tonumber(db.targetHealthFontSize) or valueFont
|
||||
healthFont = Clamp(math.floor(healthFont + 0.5), 8, 18)
|
||||
|
||||
local powerFont = tonumber(db.targetPowerFontSize) or valueFont
|
||||
powerFont = Clamp(math.floor(powerFont + 0.5), 8, 18)
|
||||
|
||||
local frameScale = tonumber(db.targetFrameScale) or 1
|
||||
frameScale = Clamp(frameScale, 0.7, 1.8)
|
||||
|
||||
@@ -250,8 +294,16 @@ function SFrames.Target:GetConfig()
|
||||
portraitWidth = portraitWidth,
|
||||
healthHeight = healthHeight,
|
||||
powerHeight = powerHeight,
|
||||
powerWidth = powerWidth,
|
||||
powerOffsetX = powerOffsetX,
|
||||
powerOffsetY = powerOffsetY,
|
||||
powerOnTop = db.targetPowerOnTop == true,
|
||||
nameFont = nameFont,
|
||||
valueFont = valueFont,
|
||||
healthFont = healthFont,
|
||||
powerFont = powerFont,
|
||||
healthTexture = SFrames:ResolveBarTexture("targetHealthTexture", "barTexture"),
|
||||
powerTexture = SFrames:ResolveBarTexture("targetPowerTexture", "barTexture"),
|
||||
scale = frameScale,
|
||||
}
|
||||
end
|
||||
@@ -334,8 +386,8 @@ function SFrames.Target:ApplyConfig()
|
||||
|
||||
if f.power then
|
||||
f.power:ClearAllPoints()
|
||||
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", 0, -1)
|
||||
f.power:SetPoint("TOPRIGHT", f.health, "BOTTOMRIGHT", 0, 0)
|
||||
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", cfg.powerOffsetX, -1 + cfg.powerOffsetY)
|
||||
f.power:SetWidth(cfg.powerWidth)
|
||||
f.power:SetHeight(cfg.powerHeight)
|
||||
end
|
||||
|
||||
@@ -345,19 +397,71 @@ function SFrames.Target:ApplyConfig()
|
||||
f.powerBGFrame:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 1, -1)
|
||||
end
|
||||
|
||||
local outline = (SFrames and SFrames.Media and SFrames.Media.fontOutline) or "OUTLINE"
|
||||
local fontPath = SFrames:GetFont()
|
||||
SFrames:ApplyStatusBarTexture(f.health, "targetHealthTexture", "barTexture")
|
||||
SFrames:ApplyStatusBarTexture(f.power, "targetPowerTexture", "barTexture")
|
||||
SetTextureIfPresent(f.health and f.health.bg, cfg.healthTexture)
|
||||
SetTextureIfPresent(f.health and f.health.healPredMine, cfg.healthTexture)
|
||||
SetTextureIfPresent(f.health and f.health.healPredOther, cfg.healthTexture)
|
||||
SetTextureIfPresent(f.health and f.health.healPredOver, cfg.healthTexture)
|
||||
SetTextureIfPresent(f.power and f.power.bg, cfg.powerTexture)
|
||||
|
||||
if f.nameText then
|
||||
f.nameText:SetFont(fontPath, cfg.nameFont, outline)
|
||||
end
|
||||
if f.healthText then
|
||||
f.healthText:SetFont(fontPath, cfg.valueFont, outline)
|
||||
end
|
||||
if f.powerText then
|
||||
f.powerText:SetFont(fontPath, cfg.valueFont, outline)
|
||||
-- Gradient style preset
|
||||
if SFrames:IsGradientStyle() then
|
||||
-- Hide portrait & its backdrop
|
||||
if f.portrait then f.portrait:Hide() end
|
||||
if f.portraitBG then f.portraitBG:Hide() end
|
||||
-- Strip backdrops
|
||||
SFrames:ClearBackdrop(f)
|
||||
SFrames:ClearBackdrop(f.healthBGFrame)
|
||||
SFrames:ClearBackdrop(f.powerBGFrame)
|
||||
-- Health bar full width
|
||||
if f.health then
|
||||
f.health:ClearAllPoints()
|
||||
f.health:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
|
||||
f.health:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
|
||||
f.health:SetHeight(cfg.healthHeight)
|
||||
end
|
||||
-- Power bar full width, below health
|
||||
if f.power then
|
||||
f.power:ClearAllPoints()
|
||||
f.power:SetPoint("TOPLEFT", f.health, "BOTTOMLEFT", cfg.powerOffsetX, -2 + cfg.powerOffsetY)
|
||||
f.power:SetWidth(cfg.powerWidth)
|
||||
f.power:SetHeight(cfg.powerHeight)
|
||||
end
|
||||
-- Apply gradient overlays
|
||||
SFrames:ApplyGradientStyle(f.health)
|
||||
SFrames:ApplyGradientStyle(f.power)
|
||||
-- Flush BG frames (no border padding)
|
||||
if f.healthBGFrame then
|
||||
f.healthBGFrame:ClearAllPoints()
|
||||
f.healthBGFrame:SetPoint("TOPLEFT", f.health, "TOPLEFT", 0, 0)
|
||||
f.healthBGFrame:SetPoint("BOTTOMRIGHT", f.health, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
if f.powerBGFrame then
|
||||
f.powerBGFrame:ClearAllPoints()
|
||||
f.powerBGFrame:SetPoint("TOPLEFT", f.power, "TOPLEFT", 0, 0)
|
||||
f.powerBGFrame:SetPoint("BOTTOMRIGHT", f.power, "BOTTOMRIGHT", 0, 0)
|
||||
end
|
||||
-- Hide bar backgrounds (transparent)
|
||||
if f.healthBGFrame then f.healthBGFrame:Hide() end
|
||||
if f.powerBGFrame then f.powerBGFrame:Hide() end
|
||||
if f.health and f.health.bg then f.health.bg:Hide() end
|
||||
if f.power and f.power.bg then f.power.bg:Hide() end
|
||||
else
|
||||
-- Classic style: remove gradient overlays if they exist
|
||||
SFrames:RemoveGradientStyle(f.health)
|
||||
SFrames:RemoveGradientStyle(f.power)
|
||||
-- Restore bar backgrounds
|
||||
if f.healthBGFrame then f.healthBGFrame:Show() end
|
||||
if f.powerBGFrame then f.powerBGFrame:Show() end
|
||||
if f.health and f.health.bg then f.health.bg:Show() end
|
||||
if f.power and f.power.bg then f.power.bg:Show() end
|
||||
end
|
||||
|
||||
ApplyFontIfPresent(f.nameText, cfg.nameFont, "targetNameFontKey")
|
||||
ApplyFontIfPresent(f.healthText, cfg.healthFont, "targetHealthFontKey")
|
||||
ApplyFontIfPresent(f.powerText, cfg.powerFont, "targetPowerFontKey")
|
||||
|
||||
if f.castbar then
|
||||
f.castbar:ClearAllPoints()
|
||||
if showPortrait then
|
||||
@@ -374,6 +478,24 @@ function SFrames.Target:ApplyConfig()
|
||||
self:ApplyDistanceScale(dScale)
|
||||
end
|
||||
|
||||
if f.distText then
|
||||
local dfs = (db.targetDistanceFontSize and tonumber(db.targetDistanceFontSize)) or 10
|
||||
dfs = Clamp(dfs, 8, 24)
|
||||
SFrames:ApplyFontString(f.distText, dfs, "targetDistanceFontKey", "fontKey")
|
||||
end
|
||||
|
||||
if f.health and f.power then
|
||||
local healthLevel = f:GetFrameLevel() + 2
|
||||
local powerLevel = cfg.powerOnTop and (healthLevel + 1) or (healthLevel - 1)
|
||||
f.health:SetFrameLevel(healthLevel)
|
||||
f.power:SetFrameLevel(powerLevel)
|
||||
end
|
||||
|
||||
SFrames:ApplyConfiguredUnitBackdrop(f, "target")
|
||||
if f.healthBGFrame then SFrames:ApplyConfiguredUnitBackdrop(f.healthBGFrame, "target") end
|
||||
if f.powerBGFrame then SFrames:ApplyConfiguredUnitBackdrop(f.powerBGFrame, "target") end
|
||||
if f.portraitBG then SFrames:ApplyConfiguredUnitBackdrop(f.portraitBG, "target", true) end
|
||||
|
||||
if UnitExists("target") then
|
||||
self:UpdateAll()
|
||||
end
|
||||
@@ -386,8 +508,6 @@ function SFrames.Target:ApplyDistanceScale(scale)
|
||||
f:SetWidth(DIST_BASE_WIDTH * scale)
|
||||
f:SetHeight(DIST_BASE_HEIGHT * scale)
|
||||
if f.text then
|
||||
local fontPath = SFrames:GetFont()
|
||||
local outline = (SFrames.Media and SFrames.Media.fontOutline) or "OUTLINE"
|
||||
local customSize = SFramesDB and tonumber(SFramesDB.targetDistanceFontSize)
|
||||
local fontSize
|
||||
if customSize and customSize >= 8 and customSize <= 24 then
|
||||
@@ -395,7 +515,7 @@ function SFrames.Target:ApplyDistanceScale(scale)
|
||||
else
|
||||
fontSize = math.max(8, math.floor(DIST_BASE_FONTSIZE * scale + 0.5))
|
||||
end
|
||||
f.text:SetFont(fontPath, fontSize, outline)
|
||||
SFrames:ApplyFontString(f.text, fontSize, "targetDistanceFontKey", "fontKey")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -437,54 +557,46 @@ function SFrames.Target:InitializeDistanceFrame()
|
||||
f.text:SetShadowColor(0, 0, 0, 1)
|
||||
f.text:SetShadowOffset(1, -1)
|
||||
|
||||
-- Behind indicator text (shown next to distance)
|
||||
f.behindText = SFrames:CreateFontString(f, fontSize, "LEFT")
|
||||
f.behindText:SetPoint("LEFT", f.text, "RIGHT", 4, 0)
|
||||
f.behindText:SetShadowColor(0, 0, 0, 1)
|
||||
f.behindText:SetShadowOffset(1, -1)
|
||||
f.behindText:Hide()
|
||||
|
||||
SFrames.Target.distanceFrame = f
|
||||
f:Hide()
|
||||
|
||||
f.timer = 0
|
||||
f:SetScript("OnUpdate", function()
|
||||
if SFramesDB and SFramesDB.targetDistanceEnabled == false then
|
||||
if this:IsShown() then this:Hide() end
|
||||
local ticker = CreateFrame("Frame", nil, UIParent)
|
||||
ticker:SetWidth(1)
|
||||
ticker:SetHeight(1)
|
||||
ticker.timer = 0
|
||||
ticker:Show()
|
||||
ticker:SetScript("OnUpdate", function()
|
||||
local distFrame = SFrames.Target.distanceFrame
|
||||
if not distFrame then return end
|
||||
local disabled = SFramesDB and SFramesDB.targetDistanceEnabled == false
|
||||
local onFrame = not SFramesDB or SFramesDB.targetDistanceOnFrame ~= false
|
||||
local tgtFrame = SFrames.Target and SFrames.Target.frame
|
||||
local embeddedText = tgtFrame and tgtFrame.distText
|
||||
|
||||
if disabled then
|
||||
if distFrame:IsShown() then distFrame:Hide() end
|
||||
if embeddedText and embeddedText:IsShown() then embeddedText:Hide() end
|
||||
return
|
||||
end
|
||||
if not UnitExists("target") then
|
||||
if this:IsShown() then this:Hide() end
|
||||
if this.behindText then this.behindText:Hide() end
|
||||
if distFrame:IsShown() then distFrame:Hide() end
|
||||
if embeddedText and embeddedText:IsShown() then embeddedText:Hide() end
|
||||
return
|
||||
end
|
||||
this.timer = this.timer + (arg1 or 0)
|
||||
if this.timer >= 0.4 then
|
||||
this.timer = 0
|
||||
local dist = SFrames.Target:GetDistance("target")
|
||||
this.text:SetText(dist or "---")
|
||||
if not this:IsShown() then this:Show() end
|
||||
local distStr = dist or "---"
|
||||
|
||||
-- Behind indicator
|
||||
if this.behindText then
|
||||
local showBehind = not SFramesDB or SFramesDB.Tweaks == nil
|
||||
or SFramesDB.Tweaks.behindIndicator ~= false
|
||||
if showBehind and IsUnitXPAvailable() then
|
||||
local ok, isBehind = pcall(UnitXP, "behind", "player", "target")
|
||||
if ok and isBehind then
|
||||
this.behindText:SetText("背后")
|
||||
this.behindText:SetTextColor(0.2, 1.0, 0.3)
|
||||
this.behindText:Show()
|
||||
elseif ok then
|
||||
this.behindText:SetText("正面")
|
||||
this.behindText:SetTextColor(1.0, 0.35, 0.3)
|
||||
this.behindText:Show()
|
||||
else
|
||||
this.behindText:Hide()
|
||||
end
|
||||
else
|
||||
this.behindText:Hide()
|
||||
end
|
||||
if onFrame and embeddedText then
|
||||
embeddedText:SetText(distStr)
|
||||
if not embeddedText:IsShown() then embeddedText:Show() end
|
||||
if distFrame:IsShown() then distFrame:Hide() end
|
||||
else
|
||||
distFrame.text:SetText(distStr)
|
||||
if not distFrame:IsShown() then distFrame:Show() end
|
||||
if embeddedText and embeddedText:IsShown() then embeddedText:Hide() end
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -515,15 +627,23 @@ function SFrames.Target:Initialize()
|
||||
local f = CreateFrame("Button", "SFramesTargetFrame", UIParent)
|
||||
f:SetWidth(SFrames.Config.width)
|
||||
f:SetHeight(SFrames.Config.height)
|
||||
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["TargetFrame"] then
|
||||
local pos = SFramesDB.Positions["TargetFrame"]
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs, pos.yOfs)
|
||||
else
|
||||
f:SetPoint("CENTER", UIParent, "CENTER", 200, -100) -- Mirrored from player
|
||||
end
|
||||
|
||||
local frameScale = (SFramesDB and type(SFramesDB.targetFrameScale) == "number") and SFramesDB.targetFrameScale or 1
|
||||
f:SetScale(frameScale)
|
||||
|
||||
|
||||
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["TargetFrame"] then
|
||||
local pos = SFramesDB.Positions["TargetFrame"]
|
||||
local fScale = f:GetEffectiveScale() / UIParent:GetEffectiveScale()
|
||||
if fScale > 0.01 and math.abs(fScale - 1) > 0.001 then
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint,
|
||||
(pos.xOfs or 0) / fScale, (pos.yOfs or 0) / fScale)
|
||||
else
|
||||
f:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs or 0, pos.yOfs or 0)
|
||||
end
|
||||
else
|
||||
f:SetPoint("CENTER", UIParent, "CENTER", 200, -100)
|
||||
end
|
||||
|
||||
f:SetMovable(true)
|
||||
f:EnableMouse(true)
|
||||
f:RegisterForDrag("LeftButton")
|
||||
@@ -533,25 +653,21 @@ function SFrames.Target:Initialize()
|
||||
if not SFramesDB then SFramesDB = {} end
|
||||
if not SFramesDB.Positions then SFramesDB.Positions = {} end
|
||||
local point, relativeTo, relativePoint, xOfs, yOfs = f:GetPoint()
|
||||
local fSc = f:GetEffectiveScale() / UIParent:GetEffectiveScale()
|
||||
if fSc > 0.01 and math.abs(fSc - 1) > 0.001 then
|
||||
xOfs = (xOfs or 0) * fSc
|
||||
yOfs = (yOfs or 0) * fSc
|
||||
end
|
||||
SFramesDB.Positions["TargetFrame"] = { point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs }
|
||||
end)
|
||||
|
||||
f:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||
f:SetScript("OnClick", function()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] OnClick fired: " .. tostring(arg1) .. "|r")
|
||||
if arg1 == "LeftButton" then
|
||||
-- Shift+左键 = 设为焦点
|
||||
if IsShiftKeyDown() then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] Shift+LeftButton -> SetFocus|r")
|
||||
if SFrames.Focus and SFrames.Focus.SetFromTarget then
|
||||
local ok, err = pcall(SFrames.Focus.SetFromTarget, SFrames.Focus)
|
||||
if ok then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] Focus set OK|r")
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] Focus error: " .. tostring(err) .. "|r")
|
||||
end
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] SFrames.Focus missing!|r")
|
||||
pcall(SFrames.Focus.SetFromTarget, SFrames.Focus)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -562,31 +678,25 @@ function SFrames.Target:Initialize()
|
||||
SpellTargetUnit(this.unit)
|
||||
end
|
||||
elseif arg1 == "RightButton" then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] RightButton hit|r")
|
||||
if SpellIsTargeting and SpellIsTargeting() then
|
||||
SpellStopTargeting()
|
||||
return
|
||||
end
|
||||
if not UnitExists("target") then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] No target, abort|r")
|
||||
return
|
||||
end
|
||||
if not SFrames.Target.dropDown then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] Creating dropdown...|r")
|
||||
local ok1, err1 = pcall(function()
|
||||
SFrames.Target.dropDown = CreateFrame("Frame", "SFramesTargetDropDown", UIParent, "UIDropDownMenuTemplate")
|
||||
end)
|
||||
if not ok1 then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] CreateFrame failed: " .. tostring(err1) .. "|r")
|
||||
return
|
||||
end
|
||||
SFrames.Target.dropDown.displayMode = "MENU"
|
||||
SFrames.Target.dropDown.initialize = function()
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] initialize() called|r")
|
||||
local dd = SFrames.Target.dropDown
|
||||
local name = dd.targetName
|
||||
if not name then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] initialize: no targetName|r")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -678,16 +788,9 @@ function SFrames.Target:Initialize()
|
||||
|
||||
-- 取消按钮不添加,点击菜单外部即可关闭(节省按钮位)
|
||||
end
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] Dropdown created OK|r")
|
||||
end
|
||||
SFrames.Target.dropDown.targetName = UnitName("target")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] Calling ToggleDropDownMenu...|r")
|
||||
local ok3, err3 = pcall(ToggleDropDownMenu, 1, nil, SFrames.Target.dropDown, "cursor")
|
||||
if not ok3 then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff4444[Nanami] ToggleDropDownMenu failed: " .. tostring(err3) .. "|r")
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nanami] ToggleDropDownMenu OK|r")
|
||||
end
|
||||
pcall(ToggleDropDownMenu, 1, nil, SFrames.Target.dropDown, "cursor")
|
||||
end
|
||||
end)
|
||||
f:SetScript("OnReceiveDrag", function()
|
||||
@@ -799,6 +902,19 @@ function SFrames.Target:Initialize()
|
||||
f.comboText:SetTextColor(1, 0.8, 0)
|
||||
f.comboText:SetText("")
|
||||
|
||||
-- Embedded distance text (high-level overlay so it's never covered)
|
||||
local distOverlay = CreateFrame("Frame", nil, f)
|
||||
distOverlay:SetFrameLevel((f:GetFrameLevel() or 0) + 20)
|
||||
distOverlay:SetAllPoints(f.health)
|
||||
local distFS = (SFramesDB and tonumber(SFramesDB.targetDistanceFontSize)) or 10
|
||||
f.distText = SFrames:CreateFontString(distOverlay, distFS, "CENTER")
|
||||
f.distText:SetPoint("CENTER", f.health, "TOP", 0, 0)
|
||||
f.distText:SetTextColor(1, 0.82, 0.25)
|
||||
f.distText:SetShadowColor(0, 0, 0, 1)
|
||||
f.distText:SetShadowOffset(1, -1)
|
||||
f.distText:SetText("")
|
||||
f.distText:Hide()
|
||||
|
||||
-- Raid Target Icon (top center of health bar, half outside frame)
|
||||
local raidIconSize = 22
|
||||
local raidIconOvr = CreateFrame("Frame", nil, f)
|
||||
@@ -864,7 +980,8 @@ function SFrames.Target:Initialize()
|
||||
-- Register movers
|
||||
if SFrames.Movers and SFrames.Movers.RegisterMover then
|
||||
SFrames.Movers:RegisterMover("TargetFrame", f, "目标",
|
||||
"CENTER", "UIParent", "CENTER", 200, -100)
|
||||
"CENTER", "UIParent", "CENTER", 200, -100,
|
||||
nil, { alwaysShowInLayout = true })
|
||||
if SFrames.Target.distanceFrame then
|
||||
SFrames.Movers:RegisterMover("TargetDistanceFrame", SFrames.Target.distanceFrame, "目标距离",
|
||||
"CENTER", "UIParent", "CENTER", 0, 100)
|
||||
@@ -1047,18 +1164,24 @@ function SFrames.Target:OnTargetChanged()
|
||||
if UnitExists("target") then
|
||||
self.frame:Show()
|
||||
self:UpdateAll()
|
||||
local enabled = not (SFramesDB and SFramesDB.targetDistanceEnabled == false)
|
||||
local onFrame = not SFramesDB or SFramesDB.targetDistanceOnFrame ~= false
|
||||
if SFrames.Target.distanceFrame then
|
||||
local dist = self:GetDistance("target")
|
||||
SFrames.Target.distanceFrame.text:SetText(dist or "---")
|
||||
if not (SFramesDB and SFramesDB.targetDistanceEnabled == false) then
|
||||
SFrames.Target.distanceFrame:Show()
|
||||
else
|
||||
if onFrame and self.frame.distText then
|
||||
self.frame.distText:SetText(dist or "---")
|
||||
if enabled then self.frame.distText:Show() else self.frame.distText:Hide() end
|
||||
SFrames.Target.distanceFrame:Hide()
|
||||
else
|
||||
SFrames.Target.distanceFrame.text:SetText(dist or "---")
|
||||
if enabled then SFrames.Target.distanceFrame:Show() else SFrames.Target.distanceFrame:Hide() end
|
||||
if self.frame.distText then self.frame.distText:Hide() end
|
||||
end
|
||||
end
|
||||
else
|
||||
self.frame:Hide()
|
||||
if SFrames.Target.distanceFrame then SFrames.Target.distanceFrame:Hide() end
|
||||
if self.frame and self.frame.distText then self.frame.distText:Hide() end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1153,6 +1276,8 @@ function SFrames.Target:UpdateAll()
|
||||
end
|
||||
|
||||
local useClassColor = not (SFramesDB and SFramesDB.classColorHealth == false)
|
||||
-- Gradient style always uses class colors
|
||||
if SFrames:IsGradientStyle() then useClassColor = true end
|
||||
|
||||
if UnitIsPlayer("target") and useClassColor then
|
||||
local _, class = UnitClass("target")
|
||||
@@ -1184,6 +1309,10 @@ function SFrames.Target:UpdateAll()
|
||||
self.frame.nameText:SetText(formattedLevel .. name)
|
||||
self.frame.nameText:SetTextColor(r, g, b)
|
||||
end
|
||||
-- Re-apply gradient after color change
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(self.frame.health)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Target:UpdateHealth()
|
||||
@@ -1208,9 +1337,9 @@ function SFrames.Target:UpdateHealth()
|
||||
end
|
||||
|
||||
if displayMax > 0 then
|
||||
self.frame.healthText:SetText(displayHp .. " / " .. displayMax)
|
||||
self.frame.healthText:SetText(SFrames:FormatCompactPair(displayHp, displayMax))
|
||||
else
|
||||
self.frame.healthText:SetText(displayHp)
|
||||
self.frame.healthText:SetText(SFrames:FormatCompactNumber(displayHp))
|
||||
end
|
||||
|
||||
self:UpdateHealPrediction()
|
||||
@@ -1222,14 +1351,8 @@ function SFrames.Target:UpdateHealPrediction()
|
||||
local predOther = self.frame.health.healPredOther
|
||||
local predOver = self.frame.health.healPredOver
|
||||
|
||||
local function HidePredictions()
|
||||
predMine:Hide()
|
||||
predOther:Hide()
|
||||
predOver:Hide()
|
||||
end
|
||||
|
||||
if not UnitExists("target") then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1251,7 +1374,7 @@ function SFrames.Target:UpdateHealPrediction()
|
||||
end
|
||||
|
||||
if maxHp <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1268,7 +1391,7 @@ function SFrames.Target:UpdateHealPrediction()
|
||||
end
|
||||
local missing = maxHp - hp
|
||||
if missing <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1276,14 +1399,14 @@ function SFrames.Target:UpdateHealPrediction()
|
||||
local remaining = missing - mineShown
|
||||
local otherShown = math.min(math.max(0, othersIncoming), remaining)
|
||||
if mineShown <= 0 and otherShown <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
local showPortrait = SFramesDB and SFramesDB.targetShowPortrait ~= false
|
||||
local barWidth = self.frame:GetWidth() - (showPortrait and (self.frame.portrait:GetWidth() + 2) or 2)
|
||||
if barWidth <= 0 then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1293,7 +1416,7 @@ function SFrames.Target:UpdateHealPrediction()
|
||||
|
||||
local availableWidth = barWidth - currentWidth
|
||||
if availableWidth <= 0 and (mineIncoming <= 0 and othersIncoming <= 0) then
|
||||
HidePredictions()
|
||||
predMine:Hide(); predOther:Hide(); predOver:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1359,6 +1482,9 @@ function SFrames.Target:UpdatePowerType()
|
||||
else
|
||||
self.frame.power:SetStatusBarColor(0, 0, 1)
|
||||
end
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyBarGradient(self.frame.power)
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.Target:UpdatePower()
|
||||
@@ -1367,10 +1493,11 @@ function SFrames.Target:UpdatePower()
|
||||
self.frame.power:SetMinMaxValues(0, maxPower)
|
||||
self.frame.power:SetValue(power)
|
||||
if maxPower > 0 then
|
||||
self.frame.powerText:SetText(power .. " / " .. maxPower)
|
||||
self.frame.powerText:SetText(SFrames:FormatCompactPair(power, maxPower))
|
||||
else
|
||||
self.frame.powerText:SetText("")
|
||||
end
|
||||
SFrames:UpdateRainbowBar(self.frame.power, power, maxPower, "target")
|
||||
end
|
||||
|
||||
function SFrames.Target:UpdateComboPoints()
|
||||
@@ -1501,23 +1628,15 @@ end
|
||||
function SFrames.Target:TickAuras()
|
||||
if not UnitExists("target") then return end
|
||||
|
||||
local timeNow = GetTime()
|
||||
local tracker = SFrames.AuraTracker
|
||||
local npFormat = NanamiPlates_Auras and NanamiPlates_Auras.FormatTime
|
||||
local hasNP = NanamiPlates_SpellDB and NanamiPlates_SpellDB.FindEffectData
|
||||
|
||||
local targetName, targetLevel, targetGUID
|
||||
if hasNP then
|
||||
targetName = UnitName("target")
|
||||
targetLevel = UnitLevel("target") or 0
|
||||
targetGUID = UnitGUID and UnitGUID("target")
|
||||
end
|
||||
|
||||
-- Buffs
|
||||
for i = 1, 32 do
|
||||
local b = self.frame.buffs[i]
|
||||
if b:IsShown() and b.expirationTime then
|
||||
local timeLeft = b.expirationTime - timeNow
|
||||
if timeLeft > 0 and timeLeft < 3600 then
|
||||
if b:IsShown() then
|
||||
local timeLeft = tracker and tracker:GetAuraTimeLeft("target", "buff", i)
|
||||
if timeLeft and timeLeft > 0 and timeLeft < 3600 then
|
||||
if npFormat then
|
||||
local text, r, g, bc, a = npFormat(timeLeft)
|
||||
b.cdText:SetText(text)
|
||||
@@ -1531,30 +1650,11 @@ function SFrames.Target:TickAuras()
|
||||
end
|
||||
end
|
||||
|
||||
-- Debuffs: re-query SpellDB for live-accurate timers
|
||||
-- Debuffs
|
||||
for i = 1, 32 do
|
||||
local b = self.frame.debuffs[i]
|
||||
if b:IsShown() then
|
||||
local timeLeft = nil
|
||||
|
||||
if hasNP and b.effectName then
|
||||
local data = targetGUID and NanamiPlates_SpellDB:FindEffectData(targetGUID, targetLevel, b.effectName)
|
||||
if not data and targetName then
|
||||
data = NanamiPlates_SpellDB:FindEffectData(targetName, targetLevel, b.effectName)
|
||||
end
|
||||
if data and data.start and data.duration then
|
||||
local remaining = data.duration + data.start - timeNow
|
||||
if remaining > 0 then
|
||||
timeLeft = remaining
|
||||
b.expirationTime = timeNow + remaining
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not timeLeft and b.expirationTime then
|
||||
timeLeft = b.expirationTime - timeNow
|
||||
end
|
||||
|
||||
local timeLeft = tracker and tracker:GetAuraTimeLeft("target", "debuff", i)
|
||||
if timeLeft and timeLeft > 0 and timeLeft < 3600 then
|
||||
if npFormat then
|
||||
local text, r, g, bc, a = npFormat(timeLeft)
|
||||
@@ -1573,6 +1673,11 @@ end
|
||||
function SFrames.Target:UpdateAuras()
|
||||
if not UnitExists("target") then return end
|
||||
|
||||
local tracker = SFrames.AuraTracker
|
||||
if tracker and tracker.HandleAuraSnapshot then
|
||||
tracker:HandleAuraSnapshot("target")
|
||||
end
|
||||
|
||||
local hasSuperWoW = SFrames.superwow_active and SpellInfo
|
||||
local numBuffs = 0
|
||||
-- Buffs
|
||||
@@ -1584,12 +1689,9 @@ function SFrames.Target:UpdateAuras()
|
||||
b.icon:SetTexture(texture)
|
||||
-- Store aura ID when SuperWoW is available
|
||||
b.auraID = hasSuperWoW and swAuraID or nil
|
||||
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:ClearLines()
|
||||
SFrames.Tooltip:SetUnitBuff("target", i)
|
||||
local timeLeft = SFrames:GetAuraTimeLeft("target", i, true)
|
||||
SFrames.Tooltip:Hide()
|
||||
|
||||
local state = tracker and tracker:GetAuraState("target", "buff", i)
|
||||
local timeLeft = state and tracker:GetAuraTimeLeft("target", "buff", i)
|
||||
if timeLeft and timeLeft > 0 then
|
||||
b.expirationTime = GetTime() + timeLeft
|
||||
b.cdText:SetText(SFrames:FormatTime(timeLeft))
|
||||
@@ -1621,7 +1723,6 @@ function SFrames.Target:UpdateAuras()
|
||||
end
|
||||
|
||||
-- Debuffs
|
||||
local hasNP = NanamiPlates_SpellDB and NanamiPlates_SpellDB.UnitDebuff
|
||||
local npFormat = NanamiPlates_Auras and NanamiPlates_Auras.FormatTime
|
||||
|
||||
for i = 1, 32 do
|
||||
@@ -1633,39 +1734,12 @@ function SFrames.Target:UpdateAuras()
|
||||
-- Store aura ID when SuperWoW is available
|
||||
b.auraID = hasSuperWoW and swDebuffAuraID or nil
|
||||
|
||||
local timeLeft = 0
|
||||
local effectName = nil
|
||||
|
||||
if hasNP then
|
||||
local effect, rank, _, stacks, dtype, duration, npTimeLeft, isOwn = NanamiPlates_SpellDB:UnitDebuff("target", i)
|
||||
effectName = effect
|
||||
if npTimeLeft and npTimeLeft > 0 then
|
||||
timeLeft = npTimeLeft
|
||||
elseif effect and effect ~= "" and duration and duration > 0
|
||||
and NanamiPlates_Auras and NanamiPlates_Auras.timers then
|
||||
local unitKey = (UnitGUID and UnitGUID("target")) or UnitName("target") or ""
|
||||
local cached = NanamiPlates_Auras.timers[unitKey .. "_" .. effect]
|
||||
if not cached and UnitName("target") then
|
||||
cached = NanamiPlates_Auras.timers[UnitName("target") .. "_" .. effect]
|
||||
end
|
||||
if cached and cached.startTime and cached.duration then
|
||||
local remaining = cached.duration - (GetTime() - cached.startTime)
|
||||
if remaining > 0 then timeLeft = remaining end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if timeLeft <= 0 then
|
||||
SFrames.Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
SFrames.Tooltip:ClearLines()
|
||||
SFrames.Tooltip:SetUnitDebuff("target", i)
|
||||
timeLeft = SFrames:GetAuraTimeLeft("target", i, false)
|
||||
SFrames.Tooltip:Hide()
|
||||
end
|
||||
local state = tracker and tracker:GetAuraState("target", "debuff", i)
|
||||
local timeLeft = state and tracker:GetAuraTimeLeft("target", "debuff", i)
|
||||
|
||||
if timeLeft and timeLeft > 0 then
|
||||
b.expirationTime = GetTime() + timeLeft
|
||||
b.effectName = effectName
|
||||
b.effectName = state and state.name or nil
|
||||
if npFormat then
|
||||
local text, r, g, bc, a = npFormat(timeLeft)
|
||||
b.cdText:SetText(text)
|
||||
|
||||
@@ -1,12 +1,36 @@
|
||||
SFrames.ToT = {}
|
||||
local _A = SFrames.ActiveTheme
|
||||
|
||||
function SFrames.ToT:ApplyConfig()
|
||||
local f = self.frame
|
||||
if not f then return end
|
||||
SFrames:ApplyStatusBarTexture(f.health, "totHealthTexture", "barTexture")
|
||||
local tex = SFrames:ResolveBarTexture("totHealthTexture", "barTexture")
|
||||
if f.health and f.health.bg then f.health.bg:SetTexture(tex) end
|
||||
if SFrames:IsGradientStyle() then
|
||||
SFrames:ApplyGradientStyle(f.health)
|
||||
if f.hbg then f.hbg:Hide() end
|
||||
if f.health and f.health.bg then f.health.bg:Hide() end
|
||||
else
|
||||
SFrames:RemoveGradientStyle(f.health)
|
||||
if f.hbg then f.hbg:Show() end
|
||||
if f.health and f.health.bg then f.health.bg:Show() end
|
||||
end
|
||||
end
|
||||
|
||||
function SFrames.ToT:Initialize()
|
||||
local f = CreateFrame("Button", "SFramesToTFrame", UIParent)
|
||||
f:SetWidth(120)
|
||||
f:SetHeight(25)
|
||||
f:SetPoint("BOTTOMLEFT", SFramesTargetFrame, "BOTTOMRIGHT", 5, 0)
|
||||
|
||||
|
||||
if SFramesDB and SFramesDB.Positions and SFramesDB.Positions["ToTFrame"] then
|
||||
local pos = SFramesDB.Positions["ToTFrame"]
|
||||
f:SetPoint(pos.point or "BOTTOMLEFT", UIParent, pos.relativePoint or "BOTTOMLEFT",
|
||||
pos.xOfs or 0, pos.yOfs or 0)
|
||||
else
|
||||
f:SetPoint("BOTTOMLEFT", SFramesTargetFrame, "BOTTOMRIGHT", 5, 0)
|
||||
end
|
||||
|
||||
f:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||
f:SetScript("OnClick", function()
|
||||
if arg1 == "LeftButton" then
|
||||
@@ -24,6 +48,7 @@ function SFrames.ToT:Initialize()
|
||||
hbg:SetPoint("BOTTOMRIGHT", f.health, "BOTTOMRIGHT", 1, -1)
|
||||
hbg:SetFrameLevel(f:GetFrameLevel() - 1)
|
||||
SFrames:CreateUnitBackdrop(hbg)
|
||||
f.hbg = hbg
|
||||
|
||||
f.health.bg = f.health:CreateTexture(nil, "BACKGROUND")
|
||||
f.health.bg:SetAllPoints()
|
||||
@@ -35,7 +60,15 @@ function SFrames.ToT:Initialize()
|
||||
|
||||
self.frame = f
|
||||
f:Hide()
|
||||
|
||||
|
||||
self:ApplyConfig()
|
||||
|
||||
if SFrames.Movers and SFrames.Movers.RegisterMover then
|
||||
SFrames.Movers:RegisterMover("ToTFrame", f, "目标的目标",
|
||||
"BOTTOMLEFT", "SFramesTargetFrame", "BOTTOMRIGHT", 5, 0,
|
||||
nil, { alwaysShowInLayout = true })
|
||||
end
|
||||
|
||||
-- Update loop since targettarget changes don't fire precise events in Vanilla
|
||||
self.updater = CreateFrame("Frame")
|
||||
self.updater.timer = 0
|
||||
|
||||
Reference in New Issue
Block a user