mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-24 13:00:50 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
964c316cdc | ||
|
|
b73ed88346 | ||
|
|
b374a0914a | ||
|
|
aaddeb120a | ||
|
|
1ad78d43e9 | ||
|
|
dde4a5aa2d | ||
|
|
e7e1382693 | ||
|
|
6aaf4f2047 | ||
|
|
233d0dafc0 | ||
|
|
95e832835e | ||
|
|
cae7c2d68a | ||
|
|
8abde7beba | ||
|
|
fbb0c4c254 | ||
|
|
42e950639f | ||
|
|
e70c8025c2 | ||
|
|
8f1322d71c | ||
|
|
935b854073 | ||
|
|
df16988d3f | ||
|
|
627ab8b437 | ||
|
|
c36184081a | ||
|
|
d881d73246 | ||
|
|
b9f473c049 | ||
|
|
9cb21b982b | ||
|
|
65ad47e842 | ||
|
|
50aba54289 | ||
|
|
d58060b188 | ||
|
|
340bd9be9e | ||
|
|
287a4ed46c | ||
|
|
341ba95561 | ||
|
|
1600ec333b | ||
|
|
471c5713c5 | ||
|
|
5d38322b2e | ||
|
|
40dd9dd6db | ||
|
|
c1eba4d295 | ||
|
|
cbc531531c | ||
|
|
b57fc52f9a | ||
|
|
8268af915a | ||
|
|
1108746949 |
+1
-1
@@ -13,7 +13,7 @@ do
|
|||||||
-- on. There pfUI does load, and will throw wherever it reaches for something
|
-- on. There pfUI does load, and will throw wherever it reaches for something
|
||||||
-- the installed DLL doesn't have yet -- the popup names the cause so those
|
-- the installed DLL doesn't have yet -- the popup names the cause so those
|
||||||
-- errors aren't a mystery.
|
-- errors aren't a mystery.
|
||||||
local PFUI_CLASSIC_API_MIN = 11500 -- (X*10000 + Y*100 + Z)
|
local PFUI_CLASSIC_API_MIN = 11703 -- (X*10000 + Y*100 + Z)
|
||||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||||
|
|||||||
+52
-12
@@ -293,14 +293,6 @@ function pfUI.api.GetFactionIcon(raceKey)
|
|||||||
return FACTION_ICON[info.faction] or ""
|
return FACTION_ICON[info.faction] or ""
|
||||||
end
|
end
|
||||||
|
|
||||||
-- [ GetPlayerRaceIcons ]
|
|
||||||
-- Returns the faction and race emblems of the player character.
|
|
||||||
-- return: [string] both inline textures, or an empty string
|
|
||||||
function pfUI.api.GetPlayerRaceIcons()
|
|
||||||
local _, raceKey = UnitRace("player")
|
|
||||||
return pfUI.api.GetFactionIcon(raceKey) .. pfUI.api.GetRaceIcon(raceKey, UnitSex("player"))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- [ strvertical ]
|
-- [ strvertical ]
|
||||||
-- Creates vertical text using linebreaks. Multibyte char friendly.
|
-- Creates vertical text using linebreaks. Multibyte char friendly.
|
||||||
-- 'str' [string] String to columnize.
|
-- 'str' [string] String to columnize.
|
||||||
@@ -1333,6 +1325,32 @@ function pfUI.api.CreateBackdropShadow(f)
|
|||||||
f.backdrop_shadow:SetBackdropBorderColor(0, 0, 0, tonumber(pfUI_config.appearance.border.shadow_intensity))
|
f.backdrop_shadow:SetBackdropBorderColor(0, 0, 0, tonumber(pfUI_config.appearance.border.shadow_intensity))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- [ Set Castbar Shield ]
|
||||||
|
-- Colors a castbar for a cast that none of the player's own interrupts or
|
||||||
|
-- silences can stop. The bar and the icon's border both take the shield color,
|
||||||
|
-- so the state still reads on a bar configured without an icon. Not shielded
|
||||||
|
-- restores the normal cast/channel color and the configured border.
|
||||||
|
-- 'bar' [frame] the castbar statusbar
|
||||||
|
-- 'icon' [frame] the icon frame, or nil for a bar without one
|
||||||
|
-- 'shielded' [bool] whether the cast is uninterruptible
|
||||||
|
-- 'isChannel' [bool] selects the unshielded color
|
||||||
|
function pfUI.api.SetCastbarShield(bar, icon, shielded, isChannel)
|
||||||
|
if shielded then
|
||||||
|
bar:SetStatusBarColor(pfUI.api.GetStringColor(C.appearance.castbar.shieldcolor))
|
||||||
|
else
|
||||||
|
bar:SetStatusBarColor(pfUI.api.GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
|
||||||
|
end
|
||||||
|
|
||||||
|
local iconborder = icon and icon.backdrop
|
||||||
|
if not iconborder then return end
|
||||||
|
|
||||||
|
if shielded then
|
||||||
|
iconborder:SetBackdropBorderColor(pfUI.api.GetStringColor(C.appearance.castbar.shieldcolor))
|
||||||
|
else
|
||||||
|
iconborder:SetBackdropBorderColor(pfUI.api.GetStringColor(C.appearance.border.color))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- [ Bar Layout Options ] --
|
-- [ Bar Layout Options ] --
|
||||||
-- 'barsize' size of bar in number of buttons
|
-- 'barsize' size of bar in number of buttons
|
||||||
-- returns: array of options as strings for pfUI.gui.bar
|
-- returns: array of options as strings for pfUI.gui.bar
|
||||||
@@ -1517,6 +1535,18 @@ function pfUI.api.BarButtonAnchor(button,basename,buttonindex,barsize,formfactor
|
|||||||
return button._anchor
|
return button._anchor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- [ MouseIsOverHitRect ] --
|
||||||
|
-- Like frame:IsMouseOver(), but tests the frame's hit rect, the area the
|
||||||
|
-- engine uses for mouse focus and OnEnter/OnLeave. CreateBackdrop widens
|
||||||
|
-- that rect by the border, so plain IsMouseOver misses a band around it.
|
||||||
|
-- 'frame' the frame to test
|
||||||
|
-- return true when the cursor is inside the frame's hit rect
|
||||||
|
function pfUI.api.MouseIsOverHitRect(frame)
|
||||||
|
if not frame.GetHitRectInsets then return frame:IsMouseOver() end
|
||||||
|
local left, right, top, bottom = frame:GetHitRectInsets()
|
||||||
|
return frame:IsMouseOver(-top, bottom, left, -right)
|
||||||
|
end
|
||||||
|
|
||||||
-- [ Enable Autohide ] --
|
-- [ Enable Autohide ] --
|
||||||
-- 'frame' the frame that should be hidden
|
-- 'frame' the frame that should be hidden
|
||||||
function pfUI.api.EnableAutohide(frame, timeout, combat)
|
function pfUI.api.EnableAutohide(frame, timeout, combat)
|
||||||
@@ -1529,11 +1559,20 @@ function pfUI.api.EnableAutohide(frame, timeout, combat)
|
|||||||
frame.hover.parent = frame
|
frame.hover.parent = frame
|
||||||
frame.hover:Show()
|
frame.hover:Show()
|
||||||
|
|
||||||
|
if not frame.hover.fade then
|
||||||
|
frame.hover.fade = frame:CreateAnimationGroup()
|
||||||
|
local fade = frame.hover.fade:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-1)
|
||||||
|
fade:SetDuration(1)
|
||||||
|
frame.hover.fade:SetScript("OnFinished", function() frame:SetAlpha(0) end)
|
||||||
|
end
|
||||||
|
|
||||||
if combat then
|
if combat then
|
||||||
frame.hover:RegisterEvent("PLAYER_REGEN_ENABLED")
|
frame.hover:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||||
frame.hover:RegisterEvent("PLAYER_REGEN_DISABLED")
|
frame.hover:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||||
frame.hover:SetScript("OnEvent", function()
|
frame.hover:SetScript("OnEvent", function()
|
||||||
if event == "PLAYER_REGEN_DISABLED" then
|
if event == "PLAYER_REGEN_DISABLED" then
|
||||||
|
this.fade:Stop()
|
||||||
this.parent:SetAlpha(1)
|
this.parent:SetAlpha(1)
|
||||||
this.activeTo = "keep"
|
this.activeTo = "keep"
|
||||||
elseif event == "PLAYER_REGEN_ENABLED" then
|
elseif event == "PLAYER_REGEN_ENABLED" then
|
||||||
@@ -1549,13 +1588,13 @@ function pfUI.api.EnableAutohide(frame, timeout, combat)
|
|||||||
|
|
||||||
if this.activeTo == "keep" then return end
|
if this.activeTo == "keep" then return end
|
||||||
|
|
||||||
if MouseIsOver(this, 10, -10, -10, 10) then
|
if this:IsMouseOver(10, -10, -10, 10) then
|
||||||
this.activeTo = GetTime() + timeout
|
this.activeTo = GetTime() + timeout
|
||||||
|
this.fade:Stop()
|
||||||
this.parent:SetAlpha(1)
|
this.parent:SetAlpha(1)
|
||||||
elseif this.activeTo then
|
elseif this.activeTo then
|
||||||
if this.activeTo < GetTime() and this.parent:GetAlpha() > 0 then
|
if this.activeTo < GetTime() and this.parent:GetAlpha() > 0 and not this.fade:IsPlaying() then
|
||||||
local fps = (60 / math.max(GetFramerate(), 1))
|
this.fade:Play()
|
||||||
this.parent:SetAlpha(this.parent:GetAlpha() - 0.05*fps)
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
this.activeTo = GetTime() + timeout
|
this.activeTo = GetTime() + timeout
|
||||||
@@ -1572,6 +1611,7 @@ function pfUI.api.DisableAutohide(frame)
|
|||||||
frame.hover:SetScript("OnEvent", nil)
|
frame.hover:SetScript("OnEvent", nil)
|
||||||
frame.hover:SetScript("OnUpdate", nil)
|
frame.hover:SetScript("OnUpdate", nil)
|
||||||
frame.hover:Hide()
|
frame.hover:Hide()
|
||||||
|
frame.hover.fade:Stop()
|
||||||
frame:SetAlpha(1)
|
frame:SetAlpha(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+13
-3
@@ -156,6 +156,8 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8")
|
pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8")
|
pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "failcolor", "1,.2,.2,.8")
|
pfUI:UpdateConfig("appearance", "castbar", "failcolor", "1,.2,.2,.8")
|
||||||
|
pfUI:UpdateConfig("appearance", "castbar", "shieldcolor", ".8,.45,.45,.8")
|
||||||
|
pfUI:UpdateConfig("appearance", "castbar", "fsrcolor", ".9,.6,.2,.8")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar")
|
pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar")
|
||||||
pfUI:UpdateConfig("appearance", "infight", "screen", "0")
|
pfUI:UpdateConfig("appearance", "infight", "screen", "0")
|
||||||
pfUI:UpdateConfig("appearance", "infight", "aggro", "0")
|
pfUI:UpdateConfig("appearance", "infight", "aggro", "0")
|
||||||
@@ -226,7 +228,6 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("unitframes", nil, "rangecheck", "0")
|
pfUI:UpdateConfig("unitframes", nil, "rangecheck", "0")
|
||||||
pfUI:UpdateConfig("unitframes", nil, "rangecheck_mode", "vanilla")
|
pfUI:UpdateConfig("unitframes", nil, "rangecheck_mode", "vanilla")
|
||||||
pfUI:UpdateConfig("unitframes", nil, "rangecheck_distance", "40")
|
pfUI:UpdateConfig("unitframes", nil, "rangecheck_distance", "40")
|
||||||
pfUI:UpdateConfig("unitframes", nil, "buffdetect", "0")
|
|
||||||
pfUI:UpdateConfig("unitframes", nil, "druidmanabar", "1")
|
pfUI:UpdateConfig("unitframes", nil, "druidmanabar", "1")
|
||||||
pfUI:UpdateConfig("unitframes", nil, "druidmanaheight", "10")
|
pfUI:UpdateConfig("unitframes", nil, "druidmanaheight", "10")
|
||||||
pfUI:UpdateConfig("unitframes", nil, "druidmanawidth", "-1")
|
pfUI:UpdateConfig("unitframes", nil, "druidmanawidth", "-1")
|
||||||
@@ -324,6 +325,9 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("unitframes", "player", "showRest", "0")
|
pfUI:UpdateConfig("unitframes", "player", "showRest", "0")
|
||||||
pfUI:UpdateConfig("unitframes", "player", "energy", "1")
|
pfUI:UpdateConfig("unitframes", "player", "energy", "1")
|
||||||
pfUI:UpdateConfig("unitframes", "player", "manatick", "0")
|
pfUI:UpdateConfig("unitframes", "player", "manatick", "0")
|
||||||
|
pfUI:UpdateConfig("unitframes", "player", "showfsr", "1")
|
||||||
|
pfUI:UpdateConfig("unitframes", "player", "fsrheight", "4")
|
||||||
|
pfUI:UpdateConfig("unitframes", "player", "fsrstyle", "0")
|
||||||
pfUI:UpdateConfig("unitframes", "player", "display_haste", "0")
|
pfUI:UpdateConfig("unitframes", "player", "display_haste", "0")
|
||||||
pfUI:UpdateConfig("unitframes", "player", "display_haste_color", "1,1,1,1")
|
pfUI:UpdateConfig("unitframes", "player", "display_haste_color", "1,1,1,1")
|
||||||
pfUI:UpdateConfig("unitframes", "player", "display_spellpower", "1")
|
pfUI:UpdateConfig("unitframes", "player", "display_spellpower", "1")
|
||||||
@@ -516,10 +520,16 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("unitframes", unit, "buffsize", "20")
|
pfUI:UpdateConfig("unitframes", unit, "buffsize", "20")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "bufflimit", "32")
|
pfUI:UpdateConfig("unitframes", unit, "bufflimit", "32")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "buffperrow", "8")
|
pfUI:UpdateConfig("unitframes", unit, "buffperrow", "8")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "ownbuffsize", "-1")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "buffspacingx", "1")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "buffspacingy", "1")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "debuffs", "TOPLEFT")
|
pfUI:UpdateConfig("unitframes", unit, "debuffs", "TOPLEFT")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "debuffsize", "20")
|
pfUI:UpdateConfig("unitframes", unit, "debuffsize", "20")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "debufflimit", "32")
|
pfUI:UpdateConfig("unitframes", unit, "debufflimit", "32")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "debuffperrow", "8")
|
pfUI:UpdateConfig("unitframes", unit, "debuffperrow", "8")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "owndebuffsize", "-1")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "debuffspacingx", "1")
|
||||||
|
pfUI:UpdateConfig("unitframes", unit, "debuffspacingy", "1")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "invert_healthbar", "0")
|
pfUI:UpdateConfig("unitframes", unit, "invert_healthbar", "0")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "verticalbar", "0")
|
pfUI:UpdateConfig("unitframes", unit, "verticalbar", "0")
|
||||||
pfUI:UpdateConfig("unitframes", unit, "buff_indicator", "0")
|
pfUI:UpdateConfig("unitframes", unit, "buff_indicator", "0")
|
||||||
@@ -816,8 +826,8 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("chat", "text", "playerlinks", "1")
|
pfUI:UpdateConfig("chat", "text", "playerlinks", "1")
|
||||||
pfUI:UpdateConfig("chat", "text", "detecturl", "1")
|
pfUI:UpdateConfig("chat", "text", "detecturl", "1")
|
||||||
pfUI:UpdateConfig("chat", "text", "classcolor", "1")
|
pfUI:UpdateConfig("chat", "text", "classcolor", "1")
|
||||||
pfUI:UpdateConfig("chat", "text", "playericons", "0")
|
pfUI:UpdateConfig("chat", "text", "factionicons", "0")
|
||||||
pfUI:UpdateConfig("chat", "text", "whosearchunknown", "0")
|
pfUI:UpdateConfig("chat", "text", "raceicons", "0")
|
||||||
pfUI:UpdateConfig("chat", "text", "playerlevel", "0")
|
pfUI:UpdateConfig("chat", "text", "playerlevel", "0")
|
||||||
pfUI:UpdateConfig("chat", "left", "width", "380")
|
pfUI:UpdateConfig("chat", "left", "width", "380")
|
||||||
pfUI:UpdateConfig("chat", "left", "height", "180")
|
pfUI:UpdateConfig("chat", "left", "height", "180")
|
||||||
|
|||||||
+15
-9
@@ -170,7 +170,7 @@ do -- dropdown
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function MenuOnUpdate()
|
local function MenuOnUpdate()
|
||||||
if not MouseIsOver(this, 100, -100, -100, 100) then
|
if not this:IsMouseOver(100, -100, -100, 100) then
|
||||||
this.button:HideMenu()
|
this.button:HideMenu()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -661,7 +661,7 @@ function pfUI.api.SkinButton(button, cr, cg, cb, icon, disableHighlight)
|
|||||||
end
|
end
|
||||||
|
|
||||||
b.UnlockHighlight = function()
|
b.UnlockHighlight = function()
|
||||||
if not MouseIsOver(b) then
|
if not MouseIsOverHitRect(b) then
|
||||||
b:SetBackdropBorderColor(GetStringColor(pfUI_config.appearance.border.color))
|
b:SetBackdropBorderColor(GetStringColor(pfUI_config.appearance.border.color))
|
||||||
end
|
end
|
||||||
b.locked = false
|
b.locked = false
|
||||||
@@ -683,6 +683,7 @@ function pfUI.api.SkinCollapseButton(button, all)
|
|||||||
b.icon:SetSize(size, size)
|
b.icon:SetSize(size, size)
|
||||||
b.icon:SetPoint("LEFT", 2, 2)
|
b.icon:SetPoint("LEFT", 2, 2)
|
||||||
CreateBackdrop(b.icon)
|
CreateBackdrop(b.icon)
|
||||||
|
b.icon:EnableMouse(false)
|
||||||
b.icon.text = b.icon:CreateFontString(nil, "OVERLAY")
|
b.icon.text = b.icon:CreateFontString(nil, "OVERLAY")
|
||||||
b.icon.text:SetFontObject(GameFontWhite)
|
b.icon.text:SetFontObject(GameFontWhite)
|
||||||
b.icon.text:SetPoint("CENTER", -1, 0)
|
b.icon.text:SetPoint("CENTER", -1, 0)
|
||||||
@@ -1160,18 +1161,22 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
|
|||||||
infobox = CreateFrame("Button", "pfInfoBox", UIParent)
|
infobox = CreateFrame("Button", "pfInfoBox", UIParent)
|
||||||
infobox:Hide()
|
infobox:Hide()
|
||||||
|
|
||||||
|
infobox.fade = infobox:CreateAnimationGroup()
|
||||||
|
local fade = infobox.fade:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-1)
|
||||||
|
fade:SetDuration(.3)
|
||||||
|
infobox.fade:SetScript("OnFinished", function()
|
||||||
|
infobox:Hide()
|
||||||
|
infobox:SetAlpha(1)
|
||||||
|
end)
|
||||||
|
|
||||||
infobox:SetScript("OnUpdate", function()
|
infobox:SetScript("OnUpdate", function()
|
||||||
local time = infobox.lastshow + infobox.duration - GetTime()
|
local time = infobox.lastshow + infobox.duration - GetTime()
|
||||||
infobox.timeout:SetValue(time)
|
infobox.timeout:SetValue(time)
|
||||||
|
|
||||||
if GetTime() > infobox.lastshow + infobox.duration then
|
if GetTime() > infobox.lastshow + infobox.duration then
|
||||||
infobox:SetAlpha(infobox:GetAlpha()-0.05)
|
if not infobox.fade:IsPlaying() then infobox.fade:Play() end
|
||||||
|
elseif MouseIsOverHitRect(this) then
|
||||||
if infobox:GetAlpha() <= 0.1 then
|
|
||||||
infobox:Hide()
|
|
||||||
infobox:SetAlpha(1)
|
|
||||||
end
|
|
||||||
elseif MouseIsOver(this) then
|
|
||||||
this:SetAlpha(max(0.4, this:GetAlpha() - .1))
|
this:SetAlpha(max(0.4, this:GetAlpha() - .1))
|
||||||
else
|
else
|
||||||
this:SetAlpha(min(1, this:GetAlpha() + .1))
|
this:SetAlpha(min(1, this:GetAlpha() + .1))
|
||||||
@@ -1214,6 +1219,7 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
|
|||||||
infobox:SetParent(parent)
|
infobox:SetParent(parent)
|
||||||
|
|
||||||
infobox:SetFrameStrata("FULLSCREEN_DIALOG")
|
infobox:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||||
|
infobox.fade:Stop()
|
||||||
infobox:Show()
|
infobox:Show()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+140
-233
@@ -10,10 +10,64 @@ pfUI.uf.frames = {}
|
|||||||
-- Scans run back to back and consume the buffer before the next refill.
|
-- Scans run back to back and consume the buffer before the next refill.
|
||||||
local auraSlots = {}
|
local auraSlots = {}
|
||||||
|
|
||||||
-- Separate buffer for the tooltip handlers. They run from OnEnter, which can
|
-- Aura block corner -> { icon anchor point, x direction, y direction, below frame }
|
||||||
-- fire while RefreshUnit is showing/hiding icons under the cursor, so they must
|
local auraCorners = {
|
||||||
-- not share the refresh buffer.
|
TOPLEFT = { "BOTTOMLEFT", 1, 1 },
|
||||||
local tooltipSlots = {}
|
BOTTOMLEFT = { "TOPLEFT", 1, -1, true },
|
||||||
|
TOPRIGHT = { "BOTTOMRIGHT", -1, 1 },
|
||||||
|
BOTTOMRIGHT = { "TOPRIGHT", -1, -1, true },
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Flows the shown icons of an aura block outward from the frame edge, starting
|
||||||
|
-- `offset` away from it (its own row gap when nil): `perrow` icons per row,
|
||||||
|
-- each row as tall as its largest icon. The first `icons.own` icons are the
|
||||||
|
-- player's (C_UnitAuras lists them first) and use `icons.ownsize`. Returns the
|
||||||
|
-- offset just past the block's last row, where a block sharing the same corner
|
||||||
|
-- continues.
|
||||||
|
local function LayoutAuraBlock(unit, icons, offset)
|
||||||
|
local corner = auraCorners[icons.pos]
|
||||||
|
local anchor = unit.config.portraitheight ~= "-1" and unit.hp or unit
|
||||||
|
if anchor == unit.hp and corner[4] then anchor = unit.power end
|
||||||
|
|
||||||
|
offset = offset or icons.gapy
|
||||||
|
|
||||||
|
local x, rowsize, col = 0, 0, 0
|
||||||
|
local i = 1
|
||||||
|
while icons[i] and icons[i]:IsShown() do
|
||||||
|
if col == icons.perrow then
|
||||||
|
offset = offset + rowsize + icons.gapy
|
||||||
|
x, rowsize, col = 0, 0, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local size = i <= icons.own and icons.ownsize or icons.size
|
||||||
|
icons[i]:SetSize(size, size)
|
||||||
|
icons[i]:ClearAllPoints()
|
||||||
|
icons[i]:SetPoint(corner[1], anchor, icons.pos, corner[2] * x, corner[3] * offset)
|
||||||
|
|
||||||
|
x = x + size + icons.gapx
|
||||||
|
if size > rowsize then rowsize = size end
|
||||||
|
col = col + 1
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if col > 0 then offset = offset + rowsize + icons.gapy end
|
||||||
|
return offset
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Buffs and debuffs sharing a corner stack in one column: buffs first on
|
||||||
|
-- friendly units, debuffs first on neutral and hostile ones.
|
||||||
|
local function LayoutAuras(unit, unitstr)
|
||||||
|
local first, second = unit.buffs, unit.debuffs
|
||||||
|
if not UnitIsFriend("player", unitstr) then first, second = second, first end
|
||||||
|
|
||||||
|
if not first then first, second = second, nil end
|
||||||
|
if not first then return end
|
||||||
|
|
||||||
|
local offset = LayoutAuraBlock(unit, first)
|
||||||
|
if second then
|
||||||
|
LayoutAuraBlock(unit, second, second.pos == first.pos and offset or nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
-- GUID-based Roster Tracking for Smart Updates
|
-- GUID-based Roster Tracking for Smart Updates
|
||||||
@@ -78,10 +132,6 @@ local glow2 = {
|
|||||||
insets = {left = 0, right = 0, top = 0, bottom = 0},
|
insets = {left = 0, right = 0, top = 0, bottom = 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
local function DoNothing()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local function BuffOnEnter()
|
local function BuffOnEnter()
|
||||||
local parent = this:GetParent()
|
local parent = this:GetParent()
|
||||||
if not parent.label then return end
|
if not parent.label then return end
|
||||||
@@ -119,32 +169,8 @@ local function DebuffOnEnter()
|
|||||||
local unitstr = this:GetParent().label .. this:GetParent().id
|
local unitstr = this:GetParent().label .. this:GetParent().id
|
||||||
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT")
|
||||||
|
|
||||||
if this:GetParent().label ~= "player" then
|
-- C_UnitAuras lists the player's own auras first, so the selfdebuff
|
||||||
local parent = this:GetParent()
|
-- (HARMFUL|PLAYER) list is a prefix of the HARMFUL list: same index.
|
||||||
|
|
||||||
-- selfdebuff filters the displayed list to player-cast harmful auras, but
|
|
||||||
-- SetUnitAura's index has to be into the unfiltered HARMFUL list. Look up
|
|
||||||
-- the displayed aura via the PLAYER filter, then find its position in the
|
|
||||||
-- unfiltered list by name + sourceGUID.
|
|
||||||
--
|
|
||||||
-- The unfiltered list is NOT capped at 16: once a unit's 16 debuff slots
|
|
||||||
-- are full the server parks further debuffs in buff slots, and C_UnitAuras
|
|
||||||
-- reports those as harmful too. So enumerate however many the unit has.
|
|
||||||
if parent.config and parent.config.selfdebuff == "1" then
|
|
||||||
local ownAura = C_UnitAuras.GetAuraDataByIndex(unitstr, this.id, "HARMFUL|PLAYER")
|
|
||||||
if ownAura then
|
|
||||||
local n = ScanAuraSlots(unitstr, "HARMFUL", tooltipSlots)
|
|
||||||
for i = 1, n do
|
|
||||||
local check = C_UnitAuras.GetAuraDataBySlot(unitstr, tooltipSlots[i])
|
|
||||||
if check and check.name == ownAura.name and check.sourceGUID == ownAura.sourceGUID then
|
|
||||||
GameTooltip:SetUnitAura(unitstr, i, "HARMFUL")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
GameTooltip:SetUnitAura(unitstr, this.id, "HARMFUL")
|
GameTooltip:SetUnitAura(unitstr, this.id, "HARMFUL")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -219,27 +245,6 @@ function pfUI.api.UnitHasAggro(unit)
|
|||||||
return data.state
|
return data.state
|
||||||
end
|
end
|
||||||
|
|
||||||
pfUI.uf.glow = CreateFrame("Frame", nil, UIParent)
|
|
||||||
pfUI.uf.glow:SetScript("OnUpdate", function()
|
|
||||||
local fpsmod = GetFramerate() / 30
|
|
||||||
if not this.val or this.val >= .8 then
|
|
||||||
this.mod = -0.01 / fpsmod
|
|
||||||
elseif this.val <= .4 then
|
|
||||||
this.mod = 0.01 / fpsmod
|
|
||||||
end
|
|
||||||
this.val = this.val + this.mod
|
|
||||||
end)
|
|
||||||
|
|
||||||
pfUI.uf.glow.mod = 0
|
|
||||||
pfUI.uf.glow.val = 0.6
|
|
||||||
|
|
||||||
function pfUI.uf.glow.UpdateGlowAnimation()
|
|
||||||
local val = pfUI.uf.glow.val or 0.6
|
|
||||||
if val < 0.4 then val = 0.4 end
|
|
||||||
if val > 0.8 then val = 0.8 end
|
|
||||||
this:SetAlpha(val)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf:UpdateVisibility()
|
function pfUI.uf:UpdateVisibility()
|
||||||
local self = self or this
|
local self = self or this
|
||||||
|
|
||||||
@@ -313,10 +318,16 @@ function pfUI.uf:UpdateVisibility()
|
|||||||
self._label, self._id = nil, nil
|
self._label, self._id = nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local unitstr = ("%s%s"):format(self.label or "", self.id or "")
|
-- this runs for every frame five times a second, so only touch the
|
||||||
self.unitstr = unitstr ~= "" and unitstr or nil
|
-- attribute when the unit actually changed
|
||||||
self:SetAttribute("unit", self.unitstr)
|
local unitstr = (self.label or "") .. (self.id or "")
|
||||||
local visibility = ("[target=%s,exists] show; hide"):format(unitstr)
|
local unit = unitstr ~= "" and unitstr or nil
|
||||||
|
if unit ~= self.unitstr then
|
||||||
|
self.unitstr = unit
|
||||||
|
self:SetAttribute("unit", unit)
|
||||||
|
end
|
||||||
|
-- anything but "show"/"hide" means "show if the unit exists"
|
||||||
|
local visibility = "exists"
|
||||||
|
|
||||||
-- Group frames are redundant when the group is already shown as a raid grid:
|
-- Group frames are redundant when the group is already shown as a raid grid:
|
||||||
-- either an actual raid, or a party promoted to the raid grid via
|
-- either an actual raid, or a party promoted to the raid grid via
|
||||||
@@ -425,6 +436,8 @@ function pfUI.uf:UpdateConfig()
|
|||||||
local C = pfUI_config
|
local C = pfUI_config
|
||||||
local rawborder, default_border = GetBorderSize("unitframes")
|
local rawborder, default_border = GetBorderSize("unitframes")
|
||||||
local spacing = f.config.pspace * GetPerfectPixel()
|
local spacing = f.config.pspace * GetPerfectPixel()
|
||||||
|
-- aura icon backdrops sit outside the icon, so gaps clear both borders
|
||||||
|
local aura_border = (C.appearance.border.force_blizz == "1" and 1 or 2) * default_border
|
||||||
|
|
||||||
local cooldown_text = tonumber(f.config.cooldown_text)
|
local cooldown_text = tonumber(f.config.cooldown_text)
|
||||||
local cooldown_anim = tonumber(f.config.cooldown_anim)
|
local cooldown_anim = tonumber(f.config.cooldown_anim)
|
||||||
@@ -451,7 +464,6 @@ function pfUI.uf:UpdateConfig()
|
|||||||
f.glow:SetBackdrop(glow2)
|
f.glow:SetBackdrop(glow2)
|
||||||
f.glow:SetPoint("TOPLEFT", f, "TOPLEFT", -6 - default_border,6 + default_border)
|
f.glow:SetPoint("TOPLEFT", f, "TOPLEFT", -6 - default_border,6 + default_border)
|
||||||
f.glow:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 6 + default_border,-6 - default_border)
|
f.glow:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 6 + default_border,-6 - default_border)
|
||||||
f.glow:SetScript("OnUpdate", pfUI.uf.glow.UpdateGlowAnimation)
|
|
||||||
f.glow:Hide()
|
f.glow:Hide()
|
||||||
|
|
||||||
f.combat:SetSize(tonumber(f.config.squaresize), tonumber(f.config.squaresize))
|
f.combat:SetSize(tonumber(f.config.squaresize), tonumber(f.config.squaresize))
|
||||||
@@ -757,13 +769,17 @@ function pfUI.uf:UpdateConfig()
|
|||||||
f.buffs = nil
|
f.buffs = nil
|
||||||
else
|
else
|
||||||
f.buffs = f.buffs or {}
|
f.buffs = f.buffs or {}
|
||||||
|
f.buffs.pos = f.config.buffs
|
||||||
|
f.buffs.size = tonumber(f.config.buffsize)
|
||||||
|
f.buffs.ownsize = f.config.ownbuffsize == "-1" and f.buffs.size or tonumber(f.config.ownbuffsize)
|
||||||
|
f.buffs.perrow = tonumber(f.config.buffperrow)
|
||||||
|
f.buffs.gapx = aura_border + tonumber(f.config.buffspacingx)
|
||||||
|
f.buffs.gapy = aura_border + tonumber(f.config.buffspacingy)
|
||||||
|
f.buffs.own = 0
|
||||||
|
|
||||||
for i=1, 32 do
|
for i=1, 32 do
|
||||||
if i > tonumber(f.config.bufflimit) then break end
|
if i > tonumber(f.config.bufflimit) then break end
|
||||||
|
|
||||||
local perrow = f.config.buffperrow
|
|
||||||
local row = floor((i-1) / perrow)
|
|
||||||
|
|
||||||
f.buffs[i] = f.buffs[i] or CreateFrame("Button", "pfUI" .. f.fname .. "Buff" .. i, f)
|
f.buffs[i] = f.buffs[i] or CreateFrame("Button", "pfUI" .. f.fname .. "Buff" .. i, f)
|
||||||
f.buffs[i].texture = f.buffs[i].texture or f.buffs[i]:CreateTexture()
|
f.buffs[i].texture = f.buffs[i].texture or f.buffs[i]:CreateTexture()
|
||||||
f.buffs[i].texture:SetTexCoord(.08, .92, .08, .92)
|
f.buffs[i].texture:SetTexCoord(.08, .92, .08, .92)
|
||||||
@@ -778,57 +794,8 @@ function pfUI.uf:UpdateConfig()
|
|||||||
|
|
||||||
f.buffs[i]:SetFrameLevel(12)
|
f.buffs[i]:SetFrameLevel(12)
|
||||||
f.buffs[i]:RegisterForClicks("RightButtonUp")
|
f.buffs[i]:RegisterForClicks("RightButtonUp")
|
||||||
f.buffs[i]:ClearAllPoints()
|
|
||||||
|
|
||||||
local invert_h, invert_v, af
|
f.buffs[i].cd = f.buffs[i].cd or CreateFrame("Cooldown", f.buffs[i]:GetName() .. "Cooldown", f.buffs[i], "CooldownFrameTemplate")
|
||||||
if f.config.buffs == "TOPLEFT" then
|
|
||||||
invert_h = 1
|
|
||||||
invert_v = 1
|
|
||||||
af = "BOTTOMLEFT"
|
|
||||||
elseif f.config.buffs == "BOTTOMLEFT" then
|
|
||||||
invert_h = -1
|
|
||||||
invert_v = 1
|
|
||||||
af = "TOPLEFT"
|
|
||||||
elseif f.config.buffs == "TOPRIGHT" then
|
|
||||||
invert_h = 1
|
|
||||||
invert_v = -1
|
|
||||||
af = "BOTTOMRIGHT"
|
|
||||||
elseif f.config.buffs == "BOTTOMRIGHT" then
|
|
||||||
invert_h = -1
|
|
||||||
invert_v = -1
|
|
||||||
af = "TOPRIGHT"
|
|
||||||
end
|
|
||||||
|
|
||||||
local anchor = f.config.portraitheight ~= "-1" and f.hp or f
|
|
||||||
if anchor == f.hp and (f.config.buffs == "BOTTOMLEFT" or f.config.buffs == "BOTTOMRIGHT") then
|
|
||||||
anchor = f.power
|
|
||||||
end
|
|
||||||
local multiply = C.appearance.border.force_blizz == "1" and 1 or 2
|
|
||||||
f.buffs[i]:SetPoint(af, anchor, f.config.buffs,
|
|
||||||
invert_v * (i-1-row*perrow)*(multiply*default_border + f.config.buffsize + 1),
|
|
||||||
invert_h * (row*(multiply*default_border + f.config.buffsize + 1) + (multiply*default_border + 1)))
|
|
||||||
|
|
||||||
f.buffs[i]:SetSize(f.config.buffsize, f.config.buffsize)
|
|
||||||
|
|
||||||
-- Create CD frame if it doesn't exist
|
|
||||||
if not f.buffs[i].cd then
|
|
||||||
if cooldown_anim == 1 then
|
|
||||||
-- Animation enabled: Use Model frame with CooldownFrameTemplate
|
|
||||||
f.buffs[i].cd = CreateFrame("Model", f.buffs[i]:GetName() .. "Cooldown", f.buffs[i], "CooldownFrameTemplate")
|
|
||||||
else
|
|
||||||
-- Animation disabled: Use regular Frame with dummy functions
|
|
||||||
f.buffs[i].cd = CreateFrame("Frame", f.buffs[i]:GetName() .. "Cooldown", f.buffs[i])
|
|
||||||
f.buffs[i].cd.AdvanceTime = DoNothing
|
|
||||||
f.buffs[i].cd.SetSequence = DoNothing
|
|
||||||
f.buffs[i].cd.SetSequenceTime = DoNothing
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Always update CD properties (in case size changed)
|
|
||||||
local cdScale = f.config.buffsize / 32
|
|
||||||
f.buffs[i].cd:ClearAllPoints()
|
|
||||||
f.buffs[i].cd:SetScale(cdScale)
|
|
||||||
f.buffs[i].cd:SetAllPoints(f.buffs[i])
|
|
||||||
f.buffs[i].cd:SetFrameLevel(14)
|
f.buffs[i].cd:SetFrameLevel(14)
|
||||||
f.buffs[i].cd.pfCooldownType = "ALL"
|
f.buffs[i].cd.pfCooldownType = "ALL"
|
||||||
f.buffs[i].cd.pfCooldownStyleText = cooldown_text
|
f.buffs[i].cd.pfCooldownStyleText = cooldown_text
|
||||||
@@ -861,6 +828,13 @@ function pfUI.uf:UpdateConfig()
|
|||||||
f.debuffs = nil
|
f.debuffs = nil
|
||||||
else
|
else
|
||||||
f.debuffs = f.debuffs or {}
|
f.debuffs = f.debuffs or {}
|
||||||
|
f.debuffs.pos = f.config.debuffs
|
||||||
|
f.debuffs.size = tonumber(f.config.debuffsize)
|
||||||
|
f.debuffs.ownsize = f.config.owndebuffsize == "-1" and f.debuffs.size or tonumber(f.config.owndebuffsize)
|
||||||
|
f.debuffs.perrow = tonumber(f.config.debuffperrow)
|
||||||
|
f.debuffs.gapx = aura_border + tonumber(f.config.debuffspacingx)
|
||||||
|
f.debuffs.gapy = aura_border + tonumber(f.config.debuffspacingy)
|
||||||
|
f.debuffs.own = 0
|
||||||
|
|
||||||
for i=1, 32 do
|
for i=1, 32 do
|
||||||
if i > tonumber(f.config.debufflimit) then break end
|
if i > tonumber(f.config.debufflimit) then break end
|
||||||
@@ -879,29 +853,9 @@ function pfUI.uf:UpdateConfig()
|
|||||||
|
|
||||||
f.debuffs[i]:SetFrameLevel(12)
|
f.debuffs[i]:SetFrameLevel(12)
|
||||||
f.debuffs[i]:RegisterForClicks("RightButtonUp")
|
f.debuffs[i]:RegisterForClicks("RightButtonUp")
|
||||||
f.debuffs[i]:ClearAllPoints()
|
|
||||||
f.debuffs[i]:SetSize(f.config.debuffsize, f.config.debuffsize)
|
|
||||||
f.debuffs[i]:SetNormalTexture(nil)
|
f.debuffs[i]:SetNormalTexture(nil)
|
||||||
|
|
||||||
-- Create CD frame if it doesn't exist
|
f.debuffs[i].cd = f.debuffs[i].cd or CreateFrame("Cooldown", f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i], "CooldownFrameTemplate")
|
||||||
if not f.debuffs[i].cd then
|
|
||||||
if cooldown_anim == 1 then
|
|
||||||
-- Animation enabled: Use Model frame with CooldownFrameTemplate
|
|
||||||
f.debuffs[i].cd = CreateFrame("Model", f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i], "CooldownFrameTemplate")
|
|
||||||
else
|
|
||||||
-- Animation disabled: Use regular Frame with dummy functions
|
|
||||||
f.debuffs[i].cd = CreateFrame("Frame", f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i])
|
|
||||||
f.debuffs[i].cd.AdvanceTime = DoNothing
|
|
||||||
f.debuffs[i].cd.SetSequence = DoNothing
|
|
||||||
f.debuffs[i].cd.SetSequenceTime = DoNothing
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Always update CD properties (in case size changed)
|
|
||||||
local cdScale = f.config.debuffsize / 32
|
|
||||||
f.debuffs[i].cd:ClearAllPoints()
|
|
||||||
f.debuffs[i].cd:SetScale(cdScale)
|
|
||||||
f.debuffs[i].cd:SetAllPoints(f.debuffs[i])
|
|
||||||
f.debuffs[i].cd:SetFrameLevel(14)
|
f.debuffs[i].cd:SetFrameLevel(14)
|
||||||
f.debuffs[i].cd.pfCooldownType = "ALL"
|
f.debuffs[i].cd.pfCooldownType = "ALL"
|
||||||
f.debuffs[i].cd.pfCooldownStyleText = cooldown_text
|
f.debuffs[i].cd.pfCooldownStyleText = cooldown_text
|
||||||
@@ -943,32 +897,6 @@ function pfUI.uf.OnShow()
|
|||||||
pfUI.uf:RefreshUnit(this, "base")
|
pfUI.uf:RefreshUnit(this, "base")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- GUID-keyed aura start-time tracker, fed by Nampower's BUFF_ADDED_OTHER /
|
|
||||||
-- BUFF_REMOVED_OTHER. Non-player units have aura.expirationTime == 0 (server
|
|
||||||
-- doesn't broadcast time), so we reconstruct the swirl from "when we saw it
|
|
||||||
-- applied" + aura.duration (Spell.dbc base). Only auras we actually witnessed
|
|
||||||
-- being cast get tracked — pre-existing auras (already on a unit when you
|
|
||||||
-- target them) intentionally show no timer rather than a fabricated one.
|
|
||||||
pfUI.uf.aura_starts = {} -- {[guid] = {[spellId] = startTime}}
|
|
||||||
|
|
||||||
local auraTracker = CreateFrame("Frame", "pfUF_AuraTracker", UIParent)
|
|
||||||
auraTracker:RegisterEvent("BUFF_ADDED_OTHER")
|
|
||||||
auraTracker:RegisterEvent("BUFF_REMOVED_OTHER")
|
|
||||||
auraTracker:SetScript("OnEvent", function()
|
|
||||||
-- Nampower arg layout: arg1=guid, arg3=spellId. State code 0=added, 1=removed,
|
|
||||||
-- 2=modified; we treat any added/modified as "reset start = now" and let the
|
|
||||||
-- REMOVED event clear the entry.
|
|
||||||
if not arg1 or not arg3 or arg3 == 0 then return end
|
|
||||||
if event == "BUFF_REMOVED_OTHER" then
|
|
||||||
if pfUI.uf.aura_starts[arg1] then
|
|
||||||
pfUI.uf.aura_starts[arg1][arg3] = nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
pfUI.uf.aura_starts[arg1] = pfUI.uf.aura_starts[arg1] or {}
|
|
||||||
pfUI.uf.aura_starts[arg1][arg3] = GetTime()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
function pfUI.uf.OnEvent()
|
function pfUI.uf.OnEvent()
|
||||||
-- Handle shutdown to prevent crash 132
|
-- Handle shutdown to prevent crash 132
|
||||||
if event == "PLAYER_LOGOUT" then
|
if event == "PLAYER_LOGOUT" then
|
||||||
@@ -1140,7 +1068,18 @@ function pfUI.uf.OnUpdate()
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
pfUI.uf:RefreshUnitState(this)
|
pfUI.uf:RefreshUnitState(this)
|
||||||
pfUI.uf:RefreshIndicators(this)
|
-- group frames get their leader/loot/raid mark icons refreshed by
|
||||||
|
-- events through update_indicators, so polling them is only a safety
|
||||||
|
-- net; frames whose unit changes without events keep polling per tick
|
||||||
|
local label = this.label
|
||||||
|
if label == "raid" or label == "party" or label == "raidpet" or label == "partypet" then
|
||||||
|
if (this.lastIndicatorPoll or 0) < now then
|
||||||
|
this.lastIndicatorPoll = now + 3
|
||||||
|
pfUI.uf:RefreshIndicators(this)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pfUI.uf:RefreshIndicators(this)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.config and this.config.glowaggro == "1" and pfUI.api.UnitHasAggro(unitstr) > 0 then
|
if this.config and this.config.glowaggro == "1" and pfUI.api.UnitHasAggro(unitstr) > 0 then
|
||||||
@@ -1153,9 +1092,18 @@ function pfUI.uf.OnUpdate()
|
|||||||
this.glow:Hide()
|
this.glow:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update everything on eventless frames (targettarget, etc)
|
-- update eventless frames (targettarget, etc). A full refresh rescans
|
||||||
|
-- every aura and the portrait, so only do it when the unit behind the
|
||||||
|
-- frame changes or once a second; other ticks refresh the bars only.
|
||||||
if this.tick then
|
if this.tick then
|
||||||
pfUI.uf:RefreshUnit(this, "all")
|
local guid = UnitGUID(unitstr)
|
||||||
|
if guid ~= this.tickGuid or (this.tickFull or 0) < now then
|
||||||
|
this.tickGuid = guid
|
||||||
|
this.tickFull = now + 1
|
||||||
|
pfUI.uf:RefreshUnit(this, "all")
|
||||||
|
else
|
||||||
|
pfUI.uf:RefreshUnit(this, "base")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1482,7 +1430,18 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
|||||||
end
|
end
|
||||||
|
|
||||||
f.glow = CreateFrame("Frame", nil, f)
|
f.glow = CreateFrame("Frame", nil, f)
|
||||||
f.combat = CreateFrame("Frame", nil, f.hp.bar)
|
-- Pulse between .8 and .4 for good. The group only advances while the glow
|
||||||
|
-- is shown, so a hidden glow costs nothing.
|
||||||
|
f.glow:SetAlpha(.8)
|
||||||
|
f.glow.pulse = f.glow:CreateAnimationGroup()
|
||||||
|
f.glow.pulse:SetLooping("BOUNCE")
|
||||||
|
local fade = f.glow.pulse:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-.4)
|
||||||
|
fade:SetDuration(1.3)
|
||||||
|
fade:SetSmoothing("IN_OUT")
|
||||||
|
f.glow.pulse:Play()
|
||||||
|
|
||||||
|
f.combat =CreateFrame("Frame", nil, f.hp.bar)
|
||||||
f.combat.tex = f.combat:CreateTexture(nil, "OVERLAY")
|
f.combat.tex = f.combat:CreateTexture(nil, "OVERLAY")
|
||||||
f.combat.tex:SetAllPoints()
|
f.combat.tex:SetAllPoints()
|
||||||
|
|
||||||
@@ -1767,15 +1726,6 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
else
|
else
|
||||||
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
||||||
end
|
end
|
||||||
elseif duration > 0 then
|
|
||||||
local guid = UnitGUID(unitstr)
|
|
||||||
local guidStarts = guid and pfUI.uf.aura_starts[guid]
|
|
||||||
local start = guidStarts and guidStarts[spellId]
|
|
||||||
if start then
|
|
||||||
CooldownFrame_SetTimer(unit.buffs[i].cd, start, duration, 1)
|
|
||||||
else
|
|
||||||
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
CooldownFrame_SetTimer(unit.buffs[i].cd, 0, 0, 0)
|
||||||
end
|
end
|
||||||
@@ -1783,47 +1733,18 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
unit.buffs[i]:Hide()
|
unit.buffs[i]:Hide()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- own buffs lead the list; count them only when they're drawn larger
|
||||||
|
if unit.buffs.ownsize ~= unit.buffs.size then
|
||||||
|
unit.buffs.own = ScanAuraSlots(unitstr, "HELPFUL|PLAYER", auraSlots, unit.config.bufflimit)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- debuffs
|
-- debuffs
|
||||||
if unit.debuffs and ( component == "all" or component == "aura" ) then
|
if unit.debuffs and ( component == "all" or component == "aura" ) then
|
||||||
local texture, stacks, dtype
|
local texture, stacks, dtype
|
||||||
local perrow = unit.config.debuffperrow
|
|
||||||
local bperrow = unit.config.buffperrow
|
|
||||||
local selfdebuff = unit.config.selfdebuff
|
local selfdebuff = unit.config.selfdebuff
|
||||||
|
|
||||||
local invert_h, invert_v, af
|
|
||||||
if unit.config.debuffs == "TOPLEFT" then
|
|
||||||
invert_h = 1
|
|
||||||
invert_v = 1
|
|
||||||
af = "BOTTOMLEFT"
|
|
||||||
elseif unit.config.debuffs == "BOTTOMLEFT" then
|
|
||||||
invert_h = -1
|
|
||||||
invert_v = 1
|
|
||||||
af = "TOPLEFT"
|
|
||||||
elseif unit.config.debuffs == "TOPRIGHT" then
|
|
||||||
invert_h = 1
|
|
||||||
invert_v = -1
|
|
||||||
af = "BOTTOMRIGHT"
|
|
||||||
elseif unit.config.debuffs == "BOTTOMRIGHT" then
|
|
||||||
invert_h = -1
|
|
||||||
invert_v = -1
|
|
||||||
af = "TOPRIGHT"
|
|
||||||
end
|
|
||||||
|
|
||||||
local buffrow, reposition = 0, ( component == "all" and true or nil )
|
|
||||||
if unit.config.buffs == unit.config.debuffs then
|
|
||||||
if unit.buffs[0*bperrow+1] and unit.buffs[0*bperrow+1]:IsShown() then buffrow = buffrow + 1 end
|
|
||||||
if unit.buffs[1*bperrow+1] and unit.buffs[1*bperrow+1]:IsShown() then buffrow = buffrow + 1 end
|
|
||||||
if unit.buffs[2*bperrow+1] and unit.buffs[2*bperrow+1]:IsShown() then buffrow = buffrow + 1 end
|
|
||||||
if unit.buffs[3*bperrow+1] and unit.buffs[3*bperrow+1]:IsShown() then buffrow = buffrow + 1 end
|
|
||||||
end
|
|
||||||
|
|
||||||
if buffrow ~= unit.lastbuffrow then
|
|
||||||
unit.lastbuffrow = buffrow
|
|
||||||
reposition = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- selfdebuff narrows to player-cast harmful auras via the PLAYER filter.
|
-- 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
|
-- Player-frame debuffs aren't gated on it (it'd hide most party-applied
|
||||||
-- effects on you). One GetAuraSlots enumeration per refresh; the i-th slot
|
-- effects on you). One GetAuraSlots enumeration per refresh; the i-th slot
|
||||||
@@ -1834,19 +1755,6 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
for i=1, unit.config.debufflimit do
|
for i=1, unit.config.debufflimit do
|
||||||
if not unit.debuffs[i] then break end
|
if not unit.debuffs[i] then break end
|
||||||
|
|
||||||
local row = floor((i-1) / unit.config.debuffperrow)
|
|
||||||
|
|
||||||
if reposition then
|
|
||||||
local anchor = unit.config.portraitheight ~= "-1" and unit.hp or unit
|
|
||||||
if anchor == unit.hp and (unit.config.debuffs == "BOTTOMLEFT" or unit.config.debuffs == "BOTTOMRIGHT") then
|
|
||||||
anchor = unit.power
|
|
||||||
end
|
|
||||||
local multiply = C.appearance.border.force_blizz == "1" and 1 or 2
|
|
||||||
unit.debuffs[i]:SetPoint(af, anchor, unit.config.debuffs,
|
|
||||||
invert_v * (i-1-row*perrow)*(multiply*default_border + unit.config.debuffsize + 1),
|
|
||||||
invert_h * ((row+buffrow)*(multiply*default_border + unit.config.debuffsize + 1) + (multiply*default_border + 1)))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- positional read by slot id allocates nothing
|
-- positional read by slot id allocates nothing
|
||||||
local name, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
|
local name, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
|
||||||
if name then
|
if name then
|
||||||
@@ -1891,6 +1799,15 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
unit.debuffs[i]:Hide()
|
unit.debuffs[i]:Hide()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- own debuffs lead the list; count them only when they're drawn larger
|
||||||
|
if unit.debuffs.ownsize ~= unit.debuffs.size then
|
||||||
|
unit.debuffs.own = ScanAuraSlots(unitstr, "HARMFUL|PLAYER", auraSlots, unit.config.debufflimit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if component == "all" or component == "aura" then
|
||||||
|
LayoutAuras(unit, unitstr)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- indicators
|
-- indicators
|
||||||
@@ -2329,17 +2246,7 @@ function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
|
|||||||
frame.icon[pos].stacks:SetJustifyH("RIGHT")
|
frame.icon[pos].stacks:SetJustifyH("RIGHT")
|
||||||
frame.icon[pos].stacks:SetJustifyV("BOTTOM")
|
frame.icon[pos].stacks:SetJustifyV("BOTTOM")
|
||||||
|
|
||||||
-- Check if parent frame has cooldown animation enabled
|
frame.icon[pos].cd = CreateFrame("Cooldown", nil, frame.icon[pos], "CooldownFrameTemplate")
|
||||||
local parent_cooldown_anim = frame.config and tonumber(frame.config.cooldown_anim) or 1
|
|
||||||
if parent_cooldown_anim == 1 then
|
|
||||||
frame.icon[pos].cd = CreateFrame("Model", nil, frame.icon[pos])
|
|
||||||
else
|
|
||||||
frame.icon[pos].cd = CreateFrame("Frame", nil, frame.icon[pos])
|
|
||||||
frame.icon[pos].cd.AdvanceTime = DoNothing
|
|
||||||
frame.icon[pos].cd.SetSequence = DoNothing
|
|
||||||
frame.icon[pos].cd.SetSequenceTime = DoNothing
|
|
||||||
end
|
|
||||||
|
|
||||||
frame.icon[pos].cd.pfCooldownStyleAnimation = 0
|
frame.icon[pos].cd.pfCooldownStyleAnimation = 0
|
||||||
frame.icon[pos].cd.pfCooldownType = "ALL"
|
frame.icon[pos].cd.pfCooldownType = "ALL"
|
||||||
frame.icon[pos].cd:SetFrameLevel(48)
|
frame.icon[pos].cd:SetFrameLevel(48)
|
||||||
@@ -2647,7 +2554,7 @@ function pfUI.uf:GetStatusValue(unit, pos)
|
|||||||
elseif config == "healthmax" then
|
elseif config == "healthmax" then
|
||||||
return unit:GetColor("health") .. pfUI.api.Abbreviate(rhpmax)
|
return unit:GetColor("health") .. pfUI.api.Abbreviate(rhpmax)
|
||||||
elseif config == "healthperc" then
|
elseif config == "healthperc" then
|
||||||
return unit:GetColor("health") .. ceil(hp / hpmax * 100)
|
return unit:GetColor("health") .. ceil(hp / hpmax * 100) .. "%"
|
||||||
elseif config == "healthmiss" then
|
elseif config == "healthmiss" then
|
||||||
local health = ceil(rhp - rhpmax)
|
local health = ceil(rhp - rhpmax)
|
||||||
if UnitIsDead(unitstr) then
|
if UnitIsDead(unitstr) then
|
||||||
@@ -2700,7 +2607,7 @@ function pfUI.uf:GetStatusValue(unit, pos)
|
|||||||
return unit:GetColor("power") .. pfUI.api.Abbreviate(mpmax)
|
return unit:GetColor("power") .. pfUI.api.Abbreviate(mpmax)
|
||||||
elseif config == "powerperc" then
|
elseif config == "powerperc" then
|
||||||
local perc = UnitPowerMax(unitstr) > 0 and ceil(mp / mpmax * 100) or 0
|
local perc = UnitPowerMax(unitstr) > 0 and ceil(mp / mpmax * 100) or 0
|
||||||
return unit:GetColor("power") .. perc
|
return unit:GetColor("power") .. perc .. "%"
|
||||||
elseif config == "powermiss" then
|
elseif config == "powermiss" then
|
||||||
local power = ceil(mp - mpmax)
|
local power = ceil(mp - mpmax)
|
||||||
if power == 0 then
|
if power == 0 then
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["deDE"] = {
|
|||||||
["Description Font"] = nil,
|
["Description Font"] = nil,
|
||||||
["Description Font Size"] = nil,
|
["Description Font Size"] = nil,
|
||||||
["Detailed Random Roll Announcement"] = nil,
|
["Detailed Random Roll Announcement"] = nil,
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = nil,
|
["Disable"] = nil,
|
||||||
["Disable Blizzard Castbar"] = nil,
|
["Disable Blizzard Castbar"] = nil,
|
||||||
["Disabled"] = nil,
|
["Disabled"] = nil,
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["deDE"] = {
|
|||||||
["Website"] = nil,
|
["Website"] = nil,
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = nil,
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = nil,
|
||||||
["Whitelist"] = nil,
|
["Whitelist"] = nil,
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = nil,
|
["Width"] = nil,
|
||||||
["Wobble Zoom"] = nil,
|
["Wobble Zoom"] = nil,
|
||||||
["Won"] = nil,
|
["Won"] = nil,
|
||||||
|
|||||||
Vendored
+6
-2
@@ -87,6 +87,8 @@ pfUI_translation["enUS"] = {
|
|||||||
["Buffs"] = nil,
|
["Buffs"] = nil,
|
||||||
["Buff Size"] = nil,
|
["Buff Size"] = nil,
|
||||||
["Buff Spacing"] = nil,
|
["Buff Spacing"] = nil,
|
||||||
|
["Buff X-Spacing"] = nil,
|
||||||
|
["Buff Y-Spacing"] = nil,
|
||||||
["Buffs Per Row"] = nil,
|
["Buffs Per Row"] = nil,
|
||||||
["Button"] = nil,
|
["Button"] = nil,
|
||||||
["Button already exists in pfMinimapButtons frame"] = nil,
|
["Button already exists in pfMinimapButtons frame"] = nil,
|
||||||
@@ -192,6 +194,8 @@ pfUI_translation["enUS"] = {
|
|||||||
["Debuff Position"] = nil,
|
["Debuff Position"] = nil,
|
||||||
["Debuffs"] = nil,
|
["Debuffs"] = nil,
|
||||||
["Debuff Size"] = nil,
|
["Debuff Size"] = nil,
|
||||||
|
["Debuff X-Spacing"] = nil,
|
||||||
|
["Debuff Y-Spacing"] = nil,
|
||||||
["Debuffs Per Row"] = nil,
|
["Debuffs Per Row"] = nil,
|
||||||
["Decode"] = nil,
|
["Decode"] = nil,
|
||||||
["Default"] = nil,
|
["Default"] = nil,
|
||||||
@@ -205,7 +209,6 @@ pfUI_translation["enUS"] = {
|
|||||||
["Description Font"] = nil,
|
["Description Font"] = nil,
|
||||||
["Description Font Size"] = nil,
|
["Description Font Size"] = nil,
|
||||||
["Detailed Random Roll Announcement"] = nil,
|
["Detailed Random Roll Announcement"] = nil,
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = nil,
|
["Disable"] = nil,
|
||||||
["Disable Blizzard Castbar"] = nil,
|
["Disable Blizzard Castbar"] = nil,
|
||||||
["Disabled"] = nil,
|
["Disabled"] = nil,
|
||||||
@@ -582,6 +585,8 @@ pfUI_translation["enUS"] = {
|
|||||||
["Overwrite If Unit Is Attacking Others"] = nil,
|
["Overwrite If Unit Is Attacking Others"] = nil,
|
||||||
["Overwrite If Unit Is Attacking You"] = nil,
|
["Overwrite If Unit Is Attacking You"] = nil,
|
||||||
["Overwrite If Unit Is Casting"] = nil,
|
["Overwrite If Unit Is Casting"] = nil,
|
||||||
|
["Own Buff Size"] = nil,
|
||||||
|
["Own Debuff Size"] = nil,
|
||||||
["Owner Name"] = nil,
|
["Owner Name"] = nil,
|
||||||
["Pageable"] = nil,
|
["Pageable"] = nil,
|
||||||
["Paging Actionbar"] = nil,
|
["Paging Actionbar"] = nil,
|
||||||
@@ -895,7 +900,6 @@ pfUI_translation["enUS"] = {
|
|||||||
["Website"] = nil,
|
["Website"] = nil,
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = nil,
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = nil,
|
||||||
["Whitelist"] = nil,
|
["Whitelist"] = nil,
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = nil,
|
["Width"] = nil,
|
||||||
["Wobble Zoom"] = nil,
|
["Wobble Zoom"] = nil,
|
||||||
["Won"] = nil,
|
["Won"] = nil,
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["esES"] = {
|
|||||||
["Description Font"] = "Fuente de descripción",
|
["Description Font"] = "Fuente de descripción",
|
||||||
["Description Font Size"] = "Tamaño de la fuente de descripción",
|
["Description Font Size"] = "Tamaño de la fuente de descripción",
|
||||||
["Detailed Random Roll Announcement"] = "Anuncio detallado para tirar los dados aleatoriamente",
|
["Detailed Random Roll Announcement"] = "Anuncio detallado para tirar los dados aleatoriamente",
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = "Desactivar",
|
["Disable"] = "Desactivar",
|
||||||
["Disable Blizzard Castbar"] = "Desactivar la barra de lanzamiento de Blizzard",
|
["Disable Blizzard Castbar"] = "Desactivar la barra de lanzamiento de Blizzard",
|
||||||
["Disabled"] = "Desactivado",
|
["Disabled"] = "Desactivado",
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["esES"] = {
|
|||||||
["Website"] = "Sitio de web",
|
["Website"] = "Sitio de web",
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "¡Bienvenido a |cff33ffccpf|cffffffffUI|r!\n\nSoy el asistente de instalación que te guiará con la configuración básica. Si prefieres, puedes hacer clic el botón \"Predeterminado\" para cargar la configuración por defecto. Si quieres abrir este diálogo de nuevo, ve a la configuración y haz clic en el botón \"Reiniciar Primera vez\".\n\nVisita |cff33ffcc%s|r para descargar la última versión.",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "¡Bienvenido a |cff33ffccpf|cffffffffUI|r!\n\nSoy el asistente de instalación que te guiará con la configuración básica. Si prefieres, puedes hacer clic el botón \"Predeterminado\" para cargar la configuración por defecto. Si quieres abrir este diálogo de nuevo, ve a la configuración y haz clic en el botón \"Reiniciar Primera vez\".\n\nVisita |cff33ffcc%s|r para descargar la última versión.",
|
||||||
["Whitelist"] = "Lista blanca",
|
["Whitelist"] = "Lista blanca",
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = "Ancho",
|
["Width"] = "Ancho",
|
||||||
["Wobble Zoom"] = "Acerca tambalea",
|
["Wobble Zoom"] = "Acerca tambalea",
|
||||||
["Won"] = "Ganado",
|
["Won"] = "Ganado",
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["frFR"] = {
|
|||||||
["Description Font"] = "Description de la Police",
|
["Description Font"] = "Description de la Police",
|
||||||
["Description Font Size"] = "Description de la taille de la Police",
|
["Description Font Size"] = "Description de la taille de la Police",
|
||||||
["Detailed Random Roll Announcement"] = "Annonce détaillée des Rolls aléatoires",
|
["Detailed Random Roll Announcement"] = "Annonce détaillée des Rolls aléatoires",
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = "Désactiver",
|
["Disable"] = "Désactiver",
|
||||||
["Disable Blizzard Castbar"] = "Désactiver la barre d'incantation d'origine",
|
["Disable Blizzard Castbar"] = "Désactiver la barre d'incantation d'origine",
|
||||||
["Disabled"] = "Désactivé",
|
["Disabled"] = "Désactivé",
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["frFR"] = {
|
|||||||
["Website"] = "Site web",
|
["Website"] = "Site web",
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "Bienvenue sur l'assistant d'installation de l'interface |cff33ffccpf|cffffffffUI|r!\n\nNous allons effectuer quelques configurations de base. Si vous n'avez pas la patience, cliquer sur le bouton \"Paramètres par défaut\". Si vous souhaitez relancer cette fenêtre de dialogue, allez dans les options et cliquez sur le bouton\"Réinitialiser l'assistant d'installation\" .\n\nAllez sur |cff33ffcc%s|r pour télécharger la dernière version.",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "Bienvenue sur l'assistant d'installation de l'interface |cff33ffccpf|cffffffffUI|r!\n\nNous allons effectuer quelques configurations de base. Si vous n'avez pas la patience, cliquer sur le bouton \"Paramètres par défaut\". Si vous souhaitez relancer cette fenêtre de dialogue, allez dans les options et cliquez sur le bouton\"Réinitialiser l'assistant d'installation\" .\n\nAllez sur |cff33ffcc%s|r pour télécharger la dernière version.",
|
||||||
["Whitelist"] = "List blanche",
|
["Whitelist"] = "List blanche",
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = "Largeur",
|
["Width"] = "Largeur",
|
||||||
["Wobble Zoom"] = "Zoom oscillant",
|
["Wobble Zoom"] = "Zoom oscillant",
|
||||||
["Won"] = "A gagné",
|
["Won"] = "A gagné",
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["koKR"] = {
|
|||||||
["Description Font"] = nil,
|
["Description Font"] = nil,
|
||||||
["Description Font Size"] = nil,
|
["Description Font Size"] = nil,
|
||||||
["Detailed Random Roll Announcement"] = nil,
|
["Detailed Random Roll Announcement"] = nil,
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = "가리기",
|
["Disable"] = "가리기",
|
||||||
["Disable Blizzard Castbar"] = "블리자드 캐스트바 사용 중지",
|
["Disable Blizzard Castbar"] = "블리자드 캐스트바 사용 중지",
|
||||||
["Disabled"] = "가리기",
|
["Disabled"] = "가리기",
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["koKR"] = {
|
|||||||
["Website"] = nil,
|
["Website"] = nil,
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "|cff33ffccpf|cffffffffUI|r에 |cff33ffcc오신걸 환영합니다.|r \n\n저는 몇 가지 기본 구성을 안내 할 첫 번째 실행 위자드입니다. 모든 단계를 건너 뛰고 싶으시면 \"기본값 사용\" 버튼을 누르십시오. 이 대화 상자를 다시 실행하려면 추후 설정으로 이동하여 \"첫단계로 재설정\" 버튼을 누르십시오.\n\n최신버전 다운로드 사이트: |cff33ffcc%s|r",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "|cff33ffccpf|cffffffffUI|r에 |cff33ffcc오신걸 환영합니다.|r \n\n저는 몇 가지 기본 구성을 안내 할 첫 번째 실행 위자드입니다. 모든 단계를 건너 뛰고 싶으시면 \"기본값 사용\" 버튼을 누르십시오. 이 대화 상자를 다시 실행하려면 추후 설정으로 이동하여 \"첫단계로 재설정\" 버튼을 누르십시오.\n\n최신버전 다운로드 사이트: |cff33ffcc%s|r",
|
||||||
["Whitelist"] = nil,
|
["Whitelist"] = nil,
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = nil,
|
["Width"] = nil,
|
||||||
["Wobble Zoom"] = nil,
|
["Wobble Zoom"] = nil,
|
||||||
["Won"] = nil,
|
["Won"] = nil,
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["ruRU"] = {
|
|||||||
["Description Font"] = "Шрифт описания",
|
["Description Font"] = "Шрифт описания",
|
||||||
["Description Font Size"] = "Размер шрифта описания",
|
["Description Font Size"] = "Размер шрифта описания",
|
||||||
["Detailed Random Roll Announcement"] = "Подробное объявление о случайном броске",
|
["Detailed Random Roll Announcement"] = "Подробное объявление о случайном броске",
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = "Отключить",
|
["Disable"] = "Отключить",
|
||||||
["Disable Blizzard Castbar"] = "Отключить панель применения Blizzard",
|
["Disable Blizzard Castbar"] = "Отключить панель применения Blizzard",
|
||||||
["Disabled"] = "Отключено",
|
["Disabled"] = "Отключено",
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["ruRU"] = {
|
|||||||
["Website"] = "Веб-сайт",
|
["Website"] = "Веб-сайт",
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "Добро пожаловать в |cff33ffccpf|cffffffffUI|r!\n\nЯ мастер первого запуска, который проведет вас через некоторую базовую конфигурацию. Если вы ленитесь, не стесняйтесь нажать кнопку \"По умолчанию\". Если вы хотите снова запустить этот диалог, перейдите к настройкам и нажмите кнопку \"Первый запуск\".\n\nПосетите |cff33ffcc%s|r, чтобы проверить последнюю версию.",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "Добро пожаловать в |cff33ffccpf|cffffffffUI|r!\n\nЯ мастер первого запуска, который проведет вас через некоторую базовую конфигурацию. Если вы ленитесь, не стесняйтесь нажать кнопку \"По умолчанию\". Если вы хотите снова запустить этот диалог, перейдите к настройкам и нажмите кнопку \"Первый запуск\".\n\nПосетите |cff33ffcc%s|r, чтобы проверить последнюю версию.",
|
||||||
["Whitelist"] = "\"Белый\" список",
|
["Whitelist"] = "\"Белый\" список",
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = "Ширина",
|
["Width"] = "Ширина",
|
||||||
["Wobble Zoom"] = "Подпрыгивание",
|
["Wobble Zoom"] = "Подпрыгивание",
|
||||||
["Won"] = "Победа",
|
["Won"] = "Победа",
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["zhCN"] = {
|
|||||||
["Description Font"] = "描述字体",
|
["Description Font"] = "描述字体",
|
||||||
["Description Font Size"] = "描述字体大小",
|
["Description Font Size"] = "描述字体大小",
|
||||||
["Detailed Random Roll Announcement"] = "通告详细随机Roll点",
|
["Detailed Random Roll Announcement"] = "通告详细随机Roll点",
|
||||||
["Detect Enemy Buffs"] = "探测敌方Buffs",
|
|
||||||
["Disable"] = "禁用",
|
["Disable"] = "禁用",
|
||||||
["Disable Blizzard Castbar"] = "隐藏暴雪施法条",
|
["Disable Blizzard Castbar"] = "隐藏暴雪施法条",
|
||||||
["Disabled"] = "不显示",
|
["Disabled"] = "不显示",
|
||||||
@@ -874,7 +873,6 @@ pfUI_translation["zhCN"] = {
|
|||||||
["Website"] = "网站",
|
["Website"] = "网站",
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "欢迎使用 |cff33ffccpf|cffffffffUI|r! \n\n这是第一次运行向导,将引导您完成一些基本配置。 如果你想跳过所有步骤\"使用默认\"按钮。 如果您再次运行此对话框,请转到设置并点击 \"Reset Firstrun\" 按钮。\n\n访问 |cff33ffcc%s|r 检查最新版本。",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "欢迎使用 |cff33ffccpf|cffffffffUI|r! \n\n这是第一次运行向导,将引导您完成一些基本配置。 如果你想跳过所有步骤\"使用默认\"按钮。 如果您再次运行此对话框,请转到设置并点击 \"Reset Firstrun\" 按钮。\n\n访问 |cff33ffcc%s|r 检查最新版本。",
|
||||||
["Whitelist"] = "白名单",
|
["Whitelist"] = "白名单",
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = "宽度",
|
["Width"] = "宽度",
|
||||||
["Wobble Zoom"] = "摆动变焦",
|
["Wobble Zoom"] = "摆动变焦",
|
||||||
["Won"] = "获胜",
|
["Won"] = "获胜",
|
||||||
|
|||||||
Vendored
-2
@@ -200,7 +200,6 @@ pfUI_translation["zhTW"] = {
|
|||||||
["Description Font"] = nil,
|
["Description Font"] = nil,
|
||||||
["Description Font Size"] = nil,
|
["Description Font Size"] = nil,
|
||||||
["Detailed Random Roll Announcement"] = "通告詳細隨機Roll點",
|
["Detailed Random Roll Announcement"] = "通告詳細隨機Roll點",
|
||||||
["Detect Enemy Buffs"] = nil,
|
|
||||||
["Disable"] = "禁用",
|
["Disable"] = "禁用",
|
||||||
["Disable Blizzard Castbar"] = "隱藏暴雪施法條",
|
["Disable Blizzard Castbar"] = "隱藏暴雪施法條",
|
||||||
["Disabled"] = "不顯示",
|
["Disabled"] = "不顯示",
|
||||||
@@ -873,7 +872,6 @@ pfUI_translation["zhTW"] = {
|
|||||||
["Website"] = nil,
|
["Website"] = nil,
|
||||||
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "歡迎使用 |cff33ffccpf|cffffffffUI|r! \n\n這是第一次運行嚮導,將引導您完成一些基本配置。 如果你想跳過所有步驟\"使用預設\"按鈕。 如果您再次運行此對話方塊,請轉到設置並點擊 \"Reset Firstrun\" 按鈕。\n\n訪問 |cff33ffcc%s|r 檢查最新版本。",
|
["Welcome to |cff33ffccpf|cffffffffUI|r!\n\nI'm the first run wizard that will guide you through some basic configuration. If you're lazy, feel free to hit the \"Defaults\" button. If you wish to run this dialog again, go to the settings and hit the \"Reset Firstrun\" button.\n\nVisit |cff33ffcc%s|r to check for the latest version."] = "歡迎使用 |cff33ffccpf|cffffffffUI|r! \n\n這是第一次運行嚮導,將引導您完成一些基本配置。 如果你想跳過所有步驟\"使用預設\"按鈕。 如果您再次運行此對話方塊,請轉到設置並點擊 \"Reset Firstrun\" 按鈕。\n\n訪問 |cff33ffcc%s|r 檢查最新版本。",
|
||||||
["Whitelist"] = "白名單",
|
["Whitelist"] = "白名單",
|
||||||
["Who Search Unknown Classes (|cffffaaaaExperimental|r)"] = nil,
|
|
||||||
["Width"] = nil,
|
["Width"] = nil,
|
||||||
["Wobble Zoom"] = nil,
|
["Wobble Zoom"] = nil,
|
||||||
["Won"] = nil,
|
["Won"] = nil,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
<Include file="..\skins\blizzard\options-sound.lua"/>
|
<Include file="..\skins\blizzard\options-sound.lua"/>
|
||||||
<Include file="..\skins\blizzard\options-video.lua"/>
|
<Include file="..\skins\blizzard\options-video.lua"/>
|
||||||
<Include file="..\skins\blizzard\options-new.lua"/>
|
<Include file="..\skins\blizzard\options-new.lua"/>
|
||||||
|
<Include file="..\skins\blizzard\options-interface.lua"/>
|
||||||
<Include file="..\skins\blizzard\petition.lua"/>
|
<Include file="..\skins\blizzard\petition.lua"/>
|
||||||
<Include file="..\skins\blizzard\taxi.lua"/>
|
<Include file="..\skins\blizzard\taxi.lua"/>
|
||||||
<Include file="..\skins\blizzard\tooltips.lua"/>
|
<Include file="..\skins\blizzard\tooltips.lua"/>
|
||||||
|
|||||||
+37
-14
@@ -18,12 +18,7 @@ local ItemQuality = Enum.ItemQuality
|
|||||||
local function SortCategoryPrefix(itemId, classID, quality)
|
local function SortCategoryPrefix(itemId, classID, quality)
|
||||||
if itemId == HEARTHSTONE_ITEM_ID then return "00" end
|
if itemId == HEARTHSTONE_ITEM_ID then return "00" end
|
||||||
if quality == ItemQuality.Poor then return "13" end -- gray always last
|
if quality == ItemQuality.Poor then return "13" end -- gray always last
|
||||||
if classID == ItemClass.Weapon or classID == ItemClass.Armor then
|
if classID == ItemClass.Weapon or classID == ItemClass.Armor then return "01" end
|
||||||
if quality and quality >= ItemQuality.Epic then return "01" end -- Epic+ gear
|
|
||||||
if quality == ItemQuality.Rare then return "02" end -- Rare gear
|
|
||||||
if quality == ItemQuality.Uncommon then return "03" end -- Uncommon gear
|
|
||||||
return "04" -- Common/poor gear
|
|
||||||
end
|
|
||||||
if classID == ItemClass.Consumable then return "05" end
|
if classID == ItemClass.Consumable then return "05" end
|
||||||
if classID == ItemClass.Reagent then return "06" end
|
if classID == ItemClass.Reagent then return "06" end
|
||||||
if classID == ItemClass.Tradegoods then return "07" end
|
if classID == ItemClass.Tradegoods then return "07" end
|
||||||
@@ -42,12 +37,40 @@ local function SortCountSuffix(count)
|
|||||||
return string.sub(s, -6)
|
return string.sub(s, -6)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SortKey(itemId, name, classID, subClassID, quality, count)
|
-- Gear's slot order, keyed by the equipLoc token (INVTYPE_*). Not the
|
||||||
-- Zero-pad the class/subclass so the secondary grouping sorts numerically
|
-- token's alphabetical order, which puts chest before head, and not its
|
||||||
-- (as a string, "10" would otherwise precede "2").
|
-- INVTYPE number, which parts robe (20) from chest (5). Same order as
|
||||||
return SortCategoryPrefix(itemId, classID, quality)
|
-- ClassicAPI's C_Container.SortBags, taken from Baganator: weapons by hand,
|
||||||
.. string.format("%02d|%02d|", classID or 99, subClassID or 99)
|
-- ranged and ammo, then armor with shields and off-hands first, head to
|
||||||
.. (name or "zzz") .. "|" .. SortCountSuffix(count)
|
-- feet, then jewelry, shirt and tabard.
|
||||||
|
local SLOT_ORDER = {
|
||||||
|
"INVTYPE_2HWEAPON", "INVTYPE_WEAPON", "INVTYPE_WEAPONMAINHAND",
|
||||||
|
"INVTYPE_SHIELD", "INVTYPE_HOLDABLE", "INVTYPE_RANGEDRIGHT",
|
||||||
|
"INVTYPE_WEAPONOFFHAND", "INVTYPE_RANGED", "INVTYPE_THROWN",
|
||||||
|
"INVTYPE_AMMO", "INVTYPE_QUIVER", "INVTYPE_RELIC",
|
||||||
|
"INVTYPE_HEAD", "INVTYPE_SHOULDER", "INVTYPE_CLOAK", "INVTYPE_CHEST",
|
||||||
|
"INVTYPE_ROBE", "INVTYPE_WRIST", "INVTYPE_HAND", "INVTYPE_WAIST",
|
||||||
|
"INVTYPE_LEGS", "INVTYPE_FEET",
|
||||||
|
"INVTYPE_NECK", "INVTYPE_FINGER", "INVTYPE_TRINKET", "INVTYPE_BODY",
|
||||||
|
"INVTYPE_TABARD", "INVTYPE_BAG",
|
||||||
|
}
|
||||||
|
local SLOT_RANK = {}
|
||||||
|
for i, token in ipairs(SLOT_ORDER) do SLOT_RANK[token] = i end
|
||||||
|
|
||||||
|
local function SortKey(itemId, name, classID, subClassID, quality, count, equipLoc)
|
||||||
|
-- Zero-pad the numeric fields so they sort numerically as strings ("10"
|
||||||
|
-- would otherwise precede "2").
|
||||||
|
local key = SortCategoryPrefix(itemId, classID, quality)
|
||||||
|
.. string.format("%02d|", classID or 99)
|
||||||
|
if classID == ItemClass.Weapon or classID == ItemClass.Armor then
|
||||||
|
-- Gear: slot, then subtype, then best quality first, so all helms sit
|
||||||
|
-- together, then all shoulders.
|
||||||
|
key = key .. string.format("%02d|%02d|%d|",
|
||||||
|
SLOT_RANK[equipLoc] or 99, subClassID or 99, 9 - (quality or 0))
|
||||||
|
else
|
||||||
|
key = key .. string.format("%02d|", subClassID or 99)
|
||||||
|
end
|
||||||
|
return key .. (name or "zzz") .. "|" .. SortCountSuffix(count)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ClearSortData()
|
local function ClearSortData()
|
||||||
@@ -168,10 +191,10 @@ local function BuildSortGrid()
|
|||||||
-- sit at positions 12/13. We categorize on those numeric class IDs
|
-- sit at positions 12/13. We categorize on those numeric class IDs
|
||||||
-- rather than the localized itemType/itemSubType strings. (pfUI's
|
-- rather than the localized itemType/itemSubType strings. (pfUI's
|
||||||
-- shimmed global GetItemInfo is only 10 fields and lacks them.)
|
-- shimmed global GetItemInfo is only 10 fields and lacks them.)
|
||||||
local name, _, quality, _, _, _, _, _, _, _, _, classID, subClassID = C_Item.GetItemInfo(itemId)
|
local name, _, quality, _, _, _, _, _, equipLoc, _, _, classID, subClassID = C_Item.GetItemInfo(itemId)
|
||||||
local _, count = GetContainerItemInfo(bag, slot)
|
local _, count = GetContainerItemInfo(bag, slot)
|
||||||
local item = {
|
local item = {
|
||||||
key = SortKey(itemId, name, classID, subClassID, quality, count),
|
key = SortKey(itemId, name, classID, subClassID, quality, count, equipLoc),
|
||||||
-- vanilla items carry at most one family bit, so equality
|
-- vanilla items carry at most one family bit, so equality
|
||||||
-- against a bag family suffices (no bit.band needed).
|
-- against a bag family suffices (no bit.band needed).
|
||||||
family = C_Item.GetItemFamily(itemId) or 0,
|
family = C_Item.GetItemFamily(itemId) or 0,
|
||||||
|
|||||||
+8
-1616
File diff suppressed because it is too large
Load Diff
+159
-206
@@ -13,34 +13,23 @@ setfenv(1, pfUI:GetEnvironment())
|
|||||||
-- including resurrections. It has an option to disable the sending of those
|
-- including resurrections. It has an option to disable the sending of those
|
||||||
-- messages in case HealComm is already active.
|
-- messages in case HealComm is already active.
|
||||||
--
|
--
|
||||||
-- HOT TRACKING INTEGRATION (NEW):
|
-- Casts are read from ClassicAPI's UNIT_SPELLCAST_* events and heal amounts
|
||||||
-- With Nampower enabled, HoT tracking now primarily uses libdebuff's AURA_CAST
|
-- from COMBAT_LOG_EVENT_UNFILTERED. GetHotDuration() reads live HoT timers
|
||||||
-- event system for accurate server-side buff/debuff tracking with full rank
|
-- from C_UnitAuras (via libdebuff) and falls back to the HealComm-fed table.
|
||||||
-- protection. GetHotDuration() first checks libdebuff, then falls back to the
|
|
||||||
-- legacy prediction system for backwards compatibility with non-Nampower clients.
|
|
||||||
-- This provides:
|
|
||||||
-- - Accurate duration from server (no prediction needed)
|
|
||||||
-- - Automatic rank protection (lower ranks won't overwrite higher ranks)
|
|
||||||
-- - Support for multiple casters of same HoT on one target
|
|
||||||
-- - Zero event overhead (libdebuff already tracks all auras)
|
|
||||||
|
|
||||||
-- return instantly when another libpredict is already active
|
-- return instantly when another libpredict is already active
|
||||||
if pfUI.api.libpredict then return end
|
if pfUI.api.libpredict then return end
|
||||||
|
|
||||||
-- Check if libdebuff integration is available
|
|
||||||
local libdebuff_available = (pfUI.api.libdebuff and pfUI.api.libdebuff.GetBestAuraCast) and true or false
|
|
||||||
|
|
||||||
-- Check if Nampower is available for SPELL_FAILED events
|
|
||||||
|
|
||||||
local senttarget
|
|
||||||
local heals, ress, events, hots = {}, {}, {}, {}
|
local heals, ress, events, hots = {}, {}, {}, {}
|
||||||
local spell_queue = { "DUMMY", "DUMMYRank 9", "TARGET" }
|
local spell_queue = { "DUMMY", "DUMMYRank 9", "TARGET" }
|
||||||
local player = UnitName("player")
|
local player = UnitName("player")
|
||||||
local cache, gear_string = {}, ""
|
local cache, gear_string = {}, ""
|
||||||
local foreignCache = {} -- [casterName][spellKey] = amount, in-memory cache for other healers
|
local foreignCache = {} -- [casterName][spellKey] = amount, in-memory cache for other healers
|
||||||
local rejuvDuration, renewDuration = 12, 15 --default durations
|
local rejuvDuration, renewDuration = 12, 15 --default durations
|
||||||
local ressGuidToName = {} -- [casterGuid] = casterName, for SPELL_FAILED_OTHER cleanup
|
local ressGuidToName = {} -- [casterGuid] = casterName, for interrupted-cast cleanup
|
||||||
local healGuidToName = {} -- [casterGuid] = casterName, for SPELL_FAILED_OTHER cleanup
|
local healGuidToName = {} -- [casterGuid] = casterName, for interrupted-cast cleanup
|
||||||
|
local sentTargets = {} -- [castGUID] = target name of an own cast, from UNIT_SPELLCAST_SENT
|
||||||
|
local castTargets = {} -- [castGUID] = target name of a foreign cast, from UNIT_SPELLCAST_START
|
||||||
local ress_timers = {} -- [target][sender] = expiry_timestamp (60s rez window)
|
local ress_timers = {} -- [target][sender] = expiry_timestamp (60s rez window)
|
||||||
local RESS_TIMEOUT = 60 -- Vanilla: rez offer expires after 60s
|
local RESS_TIMEOUT = 60 -- Vanilla: rez offer expires after 60s
|
||||||
|
|
||||||
@@ -124,43 +113,25 @@ libpredict:SetScript("OnEvent", function()
|
|||||||
if origOnEvent then origOnEvent() end
|
if origOnEvent then origOnEvent() end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- SPELL_START_SELF: own cast started (heals + rez)
|
-- Own cast-time spell started (heals + rez)
|
||||||
pfUI.libdebuff_spell_start_self_hooks = pfUI.libdebuff_spell_start_self_hooks or {}
|
local function OnOwnCastStart(spellId, castGUID)
|
||||||
pfUI.libdebuff_spell_start_self_hooks["libpredict"] = function(spellId, casterGuid, targetGuid, castTime)
|
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
local spellName = C_Spell.GetSpellName(spellId)
|
||||||
if not spellName then return end
|
if not spellName then return end
|
||||||
|
|
||||||
local pendingTarget = nil
|
-- SENT names the unit the cast went out at; self and no-target casts
|
||||||
local pendingTargetGuid = nil
|
-- carry none, so fall back to what the cast hooks recorded
|
||||||
local pending = pfUI.libpredict_pending_cast
|
local target = sentTargets[castGUID] or spell_queue[3]
|
||||||
if pending and pending.spellName == spellName and pending.targetGuid
|
local _, _, _, startMs, endMs = C_Spell.CastingInfo()
|
||||||
and pending.time and (GetTime() - pending.time) < 1 then
|
local castTime = startMs and endMs - startMs or 0
|
||||||
-- If SPELL_CAST_EVENT target differs from SPELL_START_SELF target,
|
|
||||||
-- the client redirected the cast (e.g. offline target → selfcast).
|
|
||||||
-- Discard pending and trust the actual targetGuid from SPELL_START_SELF.
|
|
||||||
if pending.targetGuid == targetGuid then
|
|
||||||
local name = UnitName(pending.targetGuid)
|
|
||||||
if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING then
|
|
||||||
pendingTarget = name
|
|
||||||
pendingTargetGuid = pending.targetGuid
|
|
||||||
end
|
|
||||||
end
|
|
||||||
pending.spellId = nil
|
|
||||||
pending.spellName = nil
|
|
||||||
pending.targetGuid = nil
|
|
||||||
pending.time = nil
|
|
||||||
end
|
|
||||||
local target = pendingTarget or resolveNameFromGuid(targetGuid) or senttarget or spell_queue[3]
|
|
||||||
-- resolved GUID: prefer pendingTargetGuid (mouseover/click-to-cast), fall back to targetGuid
|
|
||||||
local resolvedTargetGuid = pendingTargetGuid or targetGuid
|
|
||||||
|
|
||||||
|
|
||||||
|
libpredict.sender.castGUID = castGUID
|
||||||
|
libpredict.sender.delayMs = 0
|
||||||
libpredict.sender.current_cast = spellName
|
libpredict.sender.current_cast = spellName
|
||||||
libpredict.sender.current_cast_target = target
|
libpredict.sender.current_cast_target = target
|
||||||
|
|
||||||
if L["resurrections"][spellName] then
|
if L["resurrections"][spellName] then
|
||||||
if target then
|
if target then
|
||||||
libpredict:Ress(player, target, casterGuid)
|
libpredict:Ress(player, target, UnitGUID("player"))
|
||||||
libpredict.sender:SendHealCommMsg("Resurrection/" .. target .. "/start/")
|
libpredict.sender:SendHealCommMsg("Resurrection/" .. target .. "/start/")
|
||||||
libpredict.sender:SendResCommMsg("RES " .. target)
|
libpredict.sender:SendResCommMsg("RES " .. target)
|
||||||
libpredict.sender.resurrecting = true
|
libpredict.sender.resurrecting = true
|
||||||
@@ -235,27 +206,17 @@ pfUI.libdebuff_spell_start_self_hooks["libpredict"] = function(spellId, casterGu
|
|||||||
return -- skip the generic Heal call below
|
return -- skip the generic Heal call below
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If the resolved heal target is itself hostile (e.g. self-cast heal while targeting an enemy),
|
libpredict:Heal(player, target, amount, casttime)
|
||||||
-- store the heal under the player so the player frame shows the prediction.
|
libpredict.sender:SendHealCommMsg("Heal/" .. (target or "") .. "/" .. amount .. "/" .. casttime .. "/")
|
||||||
-- Use resolvedTargetGuid (prefers pendingTargetGuid from mouseover/click-to-cast) so we
|
|
||||||
-- don't wrongly fall back to player when healing a friend via mouseover with a foe in target.
|
|
||||||
local healTarget = target
|
|
||||||
local unitTargetGuid = UnitGUID and UnitGUID("target")
|
|
||||||
local healTargetIsHostile = resolvedTargetGuid and unitTargetGuid
|
|
||||||
and resolvedTargetGuid == unitTargetGuid
|
|
||||||
and UnitExists("target")
|
|
||||||
and (UnitCanAttack("player", "target") or not UnitIsFriend("player", "target"))
|
|
||||||
if healTargetIsHostile then
|
|
||||||
healTarget = player
|
|
||||||
end
|
|
||||||
libpredict:Heal(player, healTarget, amount, casttime)
|
|
||||||
libpredict.sender:SendHealCommMsg("Heal/" .. (healTarget or "") .. "/" .. amount .. "/" .. casttime .. "/")
|
|
||||||
libpredict.sender.healing = true
|
libpredict.sender.healing = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SPELL_GO_SELF: own cast landed (HealStop + Regrowth timer)
|
-- Own cast landed: HealStop, Regrowth timer, instant HoTs, own rez timer
|
||||||
pfUI.libdebuff_spell_go_hooks["libpredict_sender"] = function(spellId)
|
local function OnOwnCastSucceeded(spellId, castGUID)
|
||||||
|
local target = sentTargets[castGUID] or spell_queue[3]
|
||||||
|
sentTargets[castGUID] = nil
|
||||||
|
|
||||||
libpredict:HealStop(player)
|
libpredict:HealStop(player)
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
local spellName = C_Spell.GetSpellName(spellId)
|
||||||
if spellName == REGROWTH then
|
if spellName == REGROWTH then
|
||||||
@@ -267,32 +228,57 @@ pfUI.libdebuff_spell_go_hooks["libpredict_sender"] = function(spellId)
|
|||||||
end
|
end
|
||||||
libpredict.sender.regrowth_timer = now + 0.1
|
libpredict.sender.regrowth_timer = now + 0.1
|
||||||
end
|
end
|
||||||
|
libpredict.sender.castGUID = nil
|
||||||
libpredict.sender.current_cast = nil
|
libpredict.sender.current_cast = nil
|
||||||
libpredict.sender.current_cast_target = nil
|
libpredict.sender.current_cast_target = nil
|
||||||
|
|
||||||
|
if not target then return end
|
||||||
|
|
||||||
|
-- Instant HoTs — classify by name (rank-independent) instead of a
|
||||||
|
-- hardcoded per-rank ID table.
|
||||||
|
local hotType
|
||||||
|
if spellName == REJUVENATION then hotType = "Reju"
|
||||||
|
elseif spellName == RENEW then hotType = "Renew"
|
||||||
|
end
|
||||||
|
if hotType then
|
||||||
|
local duration = hotType == "Reju" and rejuvDuration or renewDuration
|
||||||
|
local rank = 0
|
||||||
|
local rankSub = C_Spell.GetSpellSubtext(spellId)
|
||||||
|
if rankSub and rankSub ~= "" then
|
||||||
|
rank = tonumber((string.gsub(rankSub, "Rank ", ""))) or 0
|
||||||
|
end
|
||||||
|
libpredict:Hot(player, target, hotType, duration, nil, "UNIT_SPELLCAST_SUCCEEDED", rank)
|
||||||
|
libpredict.sender:SendHealCommMsg(hotType .. "/" .. target .. "/" .. duration .. "/" .. rank .. "/")
|
||||||
|
end
|
||||||
|
|
||||||
|
if isRezSpell(spellId) then
|
||||||
|
libpredict:RessSetTimer(player, target)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SPELL_START_OTHER: foreign cast started (heals + rez)
|
-- Foreign cast-time spell started (heals + rez)
|
||||||
-- Signature: fn(spellId, casterGuid, targetGuid, castTime)
|
local function OnOtherCastStart(unit, spellId, castGUID)
|
||||||
pfUI.libdebuff_spell_start_other_hooks = pfUI.libdebuff_spell_start_other_hooks or {}
|
|
||||||
pfUI.libdebuff_spell_start_other_hooks["libpredict"] = function(spellId, casterGuid, targetGuid, castTime)
|
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
local spellName = C_Spell.GetSpellName(spellId)
|
||||||
if not spellName then return end
|
if not spellName then return end
|
||||||
|
|
||||||
|
local casterGuid = UnitGUID(unit)
|
||||||
local casterName = resolveNameFromGuid(casterGuid)
|
local casterName = resolveNameFromGuid(casterGuid)
|
||||||
if not casterName then return end
|
if not casterName then return end
|
||||||
|
|
||||||
|
local targetName = UnitSpellTargetName(unit)
|
||||||
|
if not targetName then return end
|
||||||
|
castTargets[castGUID] = targetName
|
||||||
|
|
||||||
-- Resurrection cast
|
-- Resurrection cast
|
||||||
if L["resurrections"][spellName] then
|
if L["resurrections"][spellName] then
|
||||||
local targetName = resolveNameFromGuid(targetGuid)
|
libpredict:Ress(casterName, targetName, casterGuid)
|
||||||
if targetName then
|
|
||||||
libpredict:Ress(casterName, targetName, casterGuid)
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Heal cast: look up cached amount from a previous cast by this healer
|
-- Heal cast: look up cached amount from a previous cast by this healer
|
||||||
local targetName = resolveNameFromGuid(targetGuid)
|
local _, _, _, startMs, endMs = C_Spell.UnitCastingInfo(unit)
|
||||||
if not targetName then return end
|
if not startMs then return end
|
||||||
|
local castTime = endMs - startMs
|
||||||
|
|
||||||
local rankStr = C_Spell.GetSpellSubtext(spellId) or ""
|
local rankStr = C_Spell.GetSpellSubtext(spellId) or ""
|
||||||
local spellKey = spellName .. (rankStr or "")
|
local spellKey = spellName .. (rankStr or "")
|
||||||
@@ -338,77 +324,26 @@ pfUI.libdebuff_spell_start_other_hooks["libpredict"] = function(spellId, casterG
|
|||||||
libpredict:Heal(casterName, targetName, amount, castTime, casterGuid)
|
libpredict:Heal(casterName, targetName, amount, castTime, casterGuid)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SPELL_GO_SELF: own cast landed - HoTs + own rez timer
|
-- Foreign cast landed: rez timer, or the predicted heal is fulfilled
|
||||||
-- Signature: fn(spellId, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
|
local function OnOtherCastSucceeded(unit, spellId, castGUID)
|
||||||
pfUI.libdebuff_spell_go_hooks = pfUI.libdebuff_spell_go_hooks or {}
|
local casterGuid = UnitGUID(unit)
|
||||||
pfUI.libdebuff_spell_go_hooks["libpredict"] = function(spellId, a1, a2, a3, a4, a5, a6, a7)
|
|
||||||
-- Instant HoTs — classify by name (rank-independent) instead of a
|
|
||||||
-- hardcoded per-rank ID table.
|
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
|
||||||
local hotType
|
|
||||||
if spellName == REJUVENATION then hotType = "Reju"
|
|
||||||
elseif spellName == RENEW then hotType = "Renew"
|
|
||||||
end
|
|
||||||
if hotType then
|
|
||||||
local targetGuid = a4
|
|
||||||
local targetName = resolveNameFromGuid(targetGuid)
|
|
||||||
if targetName then
|
|
||||||
local duration
|
|
||||||
if hotType == "Reju" then duration = rejuvDuration or 12
|
|
||||||
elseif hotType == "Renew" then duration = renewDuration or 15
|
|
||||||
end
|
|
||||||
local rank = 0
|
|
||||||
local rankSub = C_Spell.GetSpellSubtext(spellId)
|
|
||||||
if rankSub and rankSub ~= "" then
|
|
||||||
rank = tonumber((string.gsub(rankSub, "Rank ", ""))) or 0
|
|
||||||
end
|
|
||||||
local playerName = UnitName("player")
|
|
||||||
libpredict:Hot(playerName, targetName, hotType, duration, nil, "SPELL_GO_SELF", rank)
|
|
||||||
local rankStr = tostring(rank)
|
|
||||||
if libpredict.sender and libpredict.sender.SendHealCommMsg then
|
|
||||||
libpredict.sender:SendHealCommMsg(hotType .. "/" .. targetName .. "/" .. duration .. "/" .. rankStr .. "/")
|
|
||||||
elseif IsInRaid() then
|
|
||||||
SendAddonMessage("HealComm", hotType .. "/" .. targetName .. "/" .. duration .. "/" .. rankStr .. "/", "RAID")
|
|
||||||
elseif IsInGroup() then
|
|
||||||
SendAddonMessage("HealComm", hotType .. "/" .. targetName .. "/" .. duration .. "/" .. rankStr .. "/", "PARTY")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- Own rez landed: set timer
|
|
||||||
if isRezSpell(spellId) then
|
|
||||||
local targetGuid = a4
|
|
||||||
local targetName = resolveNameFromGuid(targetGuid)
|
|
||||||
local playerName = UnitName("player")
|
|
||||||
if playerName and targetName then
|
|
||||||
libpredict:RessSetTimer(playerName, targetName)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- SPELL_GO_OTHER: foreign cast landed - rez timer + HealStop
|
|
||||||
-- Signature: fn(spellId, casterGuid, targetGuid)
|
|
||||||
pfUI.libdebuff_spell_go_other_hooks = pfUI.libdebuff_spell_go_other_hooks or {}
|
|
||||||
pfUI.libdebuff_spell_go_other_hooks["libpredict"] = function(spellId, casterGuid, targetGuid)
|
|
||||||
local casterName = resolveNameFromGuid(casterGuid)
|
local casterName = resolveNameFromGuid(casterGuid)
|
||||||
if not casterName then return end
|
if not casterName then return end
|
||||||
|
|
||||||
if isRezSpell(spellId) then
|
if isRezSpell(spellId) then
|
||||||
local targetName = resolveNameFromGuid(targetGuid)
|
local targetName = castTargets[castGUID]
|
||||||
if targetName then
|
if targetName then
|
||||||
libpredict:RessSetTimer(casterName, targetName)
|
libpredict:RessSetTimer(casterName, targetName)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Heal landed → prediction fulfilled, clean up
|
|
||||||
libpredict:HealStop(casterName)
|
libpredict:HealStop(casterName)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SPELL_FAILED_OTHER: remove cancelled resses/heals
|
-- Foreign cast interrupted: remove cancelled resses/heals
|
||||||
-- Signature: fn(casterGuid, spellId)
|
local function OnOtherCastInterrupted(unit)
|
||||||
pfUI.libdebuff_spell_failed_other_hooks = pfUI.libdebuff_spell_failed_other_hooks or {}
|
local casterGuid = UnitGUID(unit)
|
||||||
pfUI.libdebuff_spell_failed_other_hooks["libpredict"] = function(casterGuid, spellId)
|
|
||||||
if not casterGuid then return end
|
if not casterGuid then return end
|
||||||
local ressName = ressGuidToName[casterGuid]
|
local ressName = ressGuidToName[casterGuid]
|
||||||
if ressName then
|
if ressName then
|
||||||
@@ -567,7 +502,7 @@ function libpredict:ParseChatMessage(sender, msg, comm)
|
|||||||
libpredict:Heal(sender, target, heal, time)
|
libpredict:Heal(sender, target, heal, time)
|
||||||
end
|
end
|
||||||
elseif msgtype == "Ress" then
|
elseif msgtype == "Ress" then
|
||||||
-- HealComm: only for other players (own resses tracked via SPELL_START_SELF hook)
|
-- HealComm: only for other players (own resses tracked via UNIT_SPELLCAST_START)
|
||||||
local playerName = UnitName("player")
|
local playerName = UnitName("player")
|
||||||
if sender ~= playerName then
|
if sender ~= playerName then
|
||||||
local senderGuid
|
local senderGuid
|
||||||
@@ -912,7 +847,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
|
|||||||
rankNum = tonumber((string.gsub(rank, "Rank ", ""))) or nil
|
rankNum = tonumber((string.gsub(rank, "Rank ", ""))) or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Instant HoTs: libdebuff/Nampower via GetHotDuration, hook method as fallback
|
-- Instant HoTs: UNIT_SPELLCAST_SUCCEEDED and C_UnitAuras, hook method as fallback
|
||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local target = spell_queue[3]
|
local target = spell_queue[3]
|
||||||
@@ -976,7 +911,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
|
|||||||
spell_queue[3] = target or default
|
spell_queue[3] = target or default
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Instant HoTs: libdebuff/Nampower via GetHotDuration, hook method as fallback
|
-- Instant HoTs: UNIT_SPELLCAST_SUCCEEDED and C_UnitAuras, hook method as fallback
|
||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local hotTarget = target or default
|
local hotTarget = target or default
|
||||||
@@ -1037,7 +972,7 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
|
|||||||
rankNum = tonumber((string.gsub(rank, "Rank ", ""))) or nil
|
rankNum = tonumber((string.gsub(rank, "Rank ", ""))) or nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Instant HoTs: libdebuff/Nampower via GetHotDuration, hook method as fallback
|
-- Instant HoTs: UNIT_SPELLCAST_SUCCEEDED and C_UnitAuras, hook method as fallback
|
||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local hotTarget = spell_queue[3]
|
local hotTarget = spell_queue[3]
|
||||||
@@ -1127,15 +1062,17 @@ libpredict.sender:SetScript("OnUpdate", function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Nampower events
|
-- Own casts arrive as "player"; every other caster fires once per unit token
|
||||||
libpredict.sender:RegisterEvent("SPELL_FAILED_SELF")
|
-- it currently holds (raidN, target, nameplateN, ...), so other-unit handlers
|
||||||
libpredict.sender:RegisterEvent("SPELL_DELAYED_SELF")
|
-- drop the repeats by castGUID.
|
||||||
libpredict.sender:RegisterEvent("SPELL_HEAL_BY_SELF")
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SENT")
|
||||||
libpredict.sender:RegisterEvent("SPELL_HEAL_BY_OTHER") -- populates foreignCache for other healers
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_START")
|
||||||
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_DELAYED")
|
||||||
-- force cache updates
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
|
||||||
libpredict.sender:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player")
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_FAILED")
|
||||||
libpredict.sender:RegisterEvent("SKILL_LINES_CHANGED")
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
||||||
|
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||||
|
libpredict.sender:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||||
|
|
||||||
-- Shared cleanup helper for failed/interrupted casts
|
-- Shared cleanup helper for failed/interrupted casts
|
||||||
local function onCastFailed()
|
local function onCastFailed()
|
||||||
@@ -1145,7 +1082,7 @@ local function onCastFailed()
|
|||||||
s:SendHealCommMsg("Healstop")
|
s:SendHealCommMsg("Healstop")
|
||||||
s.healing = nil
|
s.healing = nil
|
||||||
elseif s.resurrecting then
|
elseif s.resurrecting then
|
||||||
local target = s.current_cast_target or senttarget or spell_queue[3]
|
local target = s.current_cast_target or spell_queue[3]
|
||||||
libpredict:RessStop(UnitName("player"))
|
libpredict:RessStop(UnitName("player"))
|
||||||
s:SendHealCommMsg("Resurrection/stop/")
|
s:SendHealCommMsg("Resurrection/stop/")
|
||||||
s:SendResCommMsg("RESNO " .. (target or ""))
|
s:SendResCommMsg("RESNO " .. (target or ""))
|
||||||
@@ -1157,81 +1094,103 @@ local function onCastFailed()
|
|||||||
s.regrowth_target_next = nil
|
s.regrowth_target_next = nil
|
||||||
s.regrowth_start_next = nil
|
s.regrowth_start_next = nil
|
||||||
end
|
end
|
||||||
|
s.castGUID = nil
|
||||||
s.current_cast = nil
|
s.current_cast = nil
|
||||||
s.current_cast_target = nil
|
s.current_cast_target = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
libpredict.sender:SetScript("OnEvent", function()
|
-- Real heal amounts: own heals refresh the spell cache, other group healers'
|
||||||
-- ============================================================
|
-- heals fill foreignCache (one event per hit target for AoE heals like PoH).
|
||||||
-- NAMPOWER PATH
|
local function OnHeal()
|
||||||
-- ============================================================
|
-- arg4=sourceGUID, arg12=spellId, arg13=spellName, arg15=amount, arg18=critical
|
||||||
if event == "SPELL_HEAL_BY_SELF" then
|
local spellId, spellName, amount, isCrit = arg12, arg13, arg15, arg18 == 1
|
||||||
-- arg1=targetGuid, arg2=casterGuid, arg3=spellId, arg4=amount, arg5=critical, arg6=periodic
|
if not spellName or not amount or amount <= 0 then return end
|
||||||
local spellId = arg3
|
|
||||||
local amount = arg4
|
if IsPlayerGuid(arg4) then
|
||||||
local isCrit = arg5 == 1
|
if spell_queue[1] == spellName then
|
||||||
local isPeriodic = arg6 == 1
|
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
|
||||||
if spellName and spell_queue[1] == spellName then
|
|
||||||
UpdateCache(spell_queue[2], amount, isCrit)
|
UpdateCache(spell_queue[2], amount, isCrit)
|
||||||
end
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
elseif event == "SPELL_HEAL_BY_OTHER" then
|
local casterName = resolveNameFromGuid(arg4)
|
||||||
-- Fires once per hit target for AoE heals (e.g. PoH).
|
if not casterName then return end
|
||||||
-- Use this to build a per-caster cache of real heal amounts.
|
|
||||||
-- arg1=targetGuid, arg2=casterGuid, arg3=spellId, arg4=amount, arg5=critical, arg6=periodic
|
|
||||||
local casterGuid = arg2
|
|
||||||
local spellId = arg3
|
|
||||||
local amount = arg4
|
|
||||||
local isCrit = arg5 == 1
|
|
||||||
local isPeriodic = arg6 == 1
|
|
||||||
|
|
||||||
if isPeriodic or not spellId or not amount or amount <= 0 then return end
|
local spellKey = spellName .. (C_Spell.GetSpellSubtext(spellId) or "")
|
||||||
|
|
||||||
local casterName = resolveNameFromGuid(casterGuid)
|
foreignCache[casterName] = foreignCache[casterName] or {}
|
||||||
if not casterName or casterName == player then return end -- own heals handled by SPELL_HEAL_BY_SELF
|
local existing = foreignCache[casterName][spellKey]
|
||||||
|
-- Store highest non-crit value for best prediction accuracy
|
||||||
|
if isCrit then
|
||||||
|
-- Estimate base from crit (vanilla crit = 150%)
|
||||||
|
local base = math.floor(amount * 2 / 3)
|
||||||
|
if not existing or base > existing then
|
||||||
|
foreignCache[casterName][spellKey] = base
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not existing or amount > existing then
|
||||||
|
foreignCache[casterName][spellKey] = amount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local spellName = C_Spell.GetSpellName(spellId)
|
local lastOtherCast = {} -- [event] = castGUID of the last other-unit event handled
|
||||||
if not spellName then return end
|
|
||||||
local rankStr = C_Spell.GetSpellSubtext(spellId)
|
|
||||||
local spellKey = spellName .. (rankStr or "")
|
|
||||||
|
|
||||||
foreignCache[casterName] = foreignCache[casterName] or {}
|
libpredict.sender:SetScript("OnEvent", function()
|
||||||
local existing = foreignCache[casterName][spellKey]
|
if event == "COMBAT_LOG_EVENT_UNFILTERED" then
|
||||||
-- Store highest non-crit value for best prediction accuracy
|
if arg2 == "SPELL_HEAL" then OnHeal() end
|
||||||
if isCrit then
|
return
|
||||||
-- Estimate base from crit (vanilla crit = 150%)
|
end
|
||||||
local base = math.floor(amount * 2 / 3)
|
|
||||||
if not existing or base > existing then
|
-- UNIT_SPELLCAST_SENT: arg1=unit, arg2=target token, arg3=castGUID, arg4=spellID
|
||||||
foreignCache[casterName][spellKey] = base
|
-- every other UNIT_SPELLCAST_*: arg1=unit, arg2=castGUID, arg3=spellID
|
||||||
end
|
local unit = arg1
|
||||||
else
|
if unit == "player" then
|
||||||
if not existing or amount > existing then
|
if event == "UNIT_SPELLCAST_SENT" then
|
||||||
foreignCache[casterName][spellKey] = amount
|
sentTargets[arg3] = arg2 ~= "" and UnitName(arg2) or nil
|
||||||
|
elseif event == "UNIT_SPELLCAST_START" then
|
||||||
|
OnOwnCastStart(arg3, arg2)
|
||||||
|
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||||
|
OnOwnCastSucceeded(arg3, arg2)
|
||||||
|
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||||
|
sentTargets[arg2] = nil
|
||||||
|
-- a refused cast (cooldown, range) fails under its own castGUID and
|
||||||
|
-- must not cancel the heal that is still casting
|
||||||
|
if arg2 == this.castGUID then onCastFailed() end
|
||||||
|
elseif event == "UNIT_SPELLCAST_DELAYED" then
|
||||||
|
-- delayTimeMs is the pushback so far; HealComm wants each step
|
||||||
|
local _, _, _, _, _, _, _, _, _, _, delayMs = C_Spell.CastingInfo()
|
||||||
|
if this.healing and delayMs and delayMs > this.delayMs then
|
||||||
|
local step = delayMs - this.delayMs
|
||||||
|
this.delayMs = delayMs
|
||||||
|
libpredict:HealDelay(player, step)
|
||||||
|
this:SendHealCommMsg("Healdelay/" .. step .. "/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
elseif event == "SPELL_FAILED_SELF" then
|
if UnitIsUnit(unit, "player") or lastOtherCast[event] == arg2 then return end
|
||||||
onCastFailed()
|
lastOtherCast[event] = arg2
|
||||||
|
|
||||||
elseif event == "SPELL_DELAYED_SELF" then
|
|
||||||
-- arg1=casterGuid, arg2=delayMs
|
|
||||||
if libpredict.sender.healing then
|
|
||||||
libpredict:HealDelay(player, arg2)
|
|
||||||
libpredict.sender:SendHealCommMsg("Healdelay/" .. arg2 .. "/")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if event == "UNIT_SPELLCAST_START" then
|
||||||
|
OnOtherCastStart(unit, arg3, arg2)
|
||||||
|
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||||
|
OnOtherCastSucceeded(unit, arg3, arg2)
|
||||||
|
elseif event == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||||
|
OnOtherCastInterrupted(unit)
|
||||||
|
elseif event == "UNIT_SPELLCAST_STOP" then
|
||||||
|
castTargets[arg2] = nil
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function libpredict:GetHotDuration(unit, spell)
|
function libpredict:GetHotDuration(unit, spell)
|
||||||
if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then return end
|
if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then return end
|
||||||
|
|
||||||
-- NEW: Try libdebuff first (Nampower AURA_CAST events)
|
-- Live aura timer first (C_UnitAuras via libdebuff)
|
||||||
if pfUI.api.libdebuff and pfUI.api.libdebuff.GetBestAuraCast then
|
if pfUI.api.libdebuff then
|
||||||
local guid = UnitGUID(unit)
|
local guid = UnitGUID(unit)
|
||||||
if guid then
|
if guid then
|
||||||
-- Get the best (highest rank) aura cast for this spell
|
|
||||||
local spellName = spell
|
local spellName = spell
|
||||||
|
|
||||||
-- Map short spell codes to full names
|
-- Map short spell codes to full names
|
||||||
@@ -1246,7 +1205,6 @@ function libpredict:GetHotDuration(unit, spell)
|
|||||||
local start, duration, timeleft, rank, casterGuid = pfUI.api.libdebuff:GetBestAuraCast(guid, spellName)
|
local start, duration, timeleft, rank, casterGuid = pfUI.api.libdebuff:GetBestAuraCast(guid, spellName)
|
||||||
|
|
||||||
if start and duration and timeleft then
|
if start and duration and timeleft then
|
||||||
-- SUCCESS: libdebuff has accurate server-side data!
|
|
||||||
if libpredict.debug then
|
if libpredict.debug then
|
||||||
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[GetHotDuration]|r %s on %s via libdebuff: dur=%.1fs timeleft=%.1fs rank=%d",
|
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff00ff00[GetHotDuration]|r %s on %s via libdebuff: dur=%.1fs timeleft=%.1fs rank=%d",
|
||||||
spell, unit, duration, timeleft, rank or 0))
|
spell, unit, duration, timeleft, rank or 0))
|
||||||
@@ -1256,7 +1214,7 @@ function libpredict:GetHotDuration(unit, spell)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FALLBACK: Use old prediction system (for non-Nampower clients or no AURA_CAST data)
|
-- FALLBACK: the HealComm/cast-fed table, for HoTs C_UnitAuras has no timer for
|
||||||
local start, duration, timeleft
|
local start, duration, timeleft
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = pfUI.uf.now or GetTime()
|
||||||
|
|
||||||
@@ -1290,16 +1248,11 @@ _G.SlashCmdList.HOTDEBUG = function()
|
|||||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[HoT Tracking Debug]|r")
|
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[HoT Tracking Debug]|r")
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff========================================|r")
|
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff========================================|r")
|
||||||
|
|
||||||
-- Check libdebuff availability
|
if pfUI.api.libdebuff then
|
||||||
local libdebuff_now = (pfUI.api.libdebuff and pfUI.api.libdebuff.GetBestAuraCast) and true or false
|
|
||||||
|
|
||||||
if libdebuff_now then
|
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[PRIMARY]|r libdebuff integration: ACTIVE")
|
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[PRIMARY]|r libdebuff integration: ACTIVE")
|
||||||
DEFAULT_CHAT_FRAME:AddMessage(" Using AURA_CAST events for server-side tracking")
|
DEFAULT_CHAT_FRAME:AddMessage(" Using C_UnitAuras timers")
|
||||||
DEFAULT_CHAT_FRAME:AddMessage(" Rank protection: ENABLED")
|
|
||||||
else
|
else
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cffff9900[PRIMARY]|r libdebuff integration: NOT AVAILABLE")
|
DEFAULT_CHAT_FRAME:AddMessage("|cffff9900[PRIMARY]|r libdebuff integration: NOT AVAILABLE")
|
||||||
DEFAULT_CHAT_FRAME:AddMessage(" Reason: Nampower not enabled or libdebuff outdated")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[FALLBACK]|r Legacy prediction system: ACTIVE")
|
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[FALLBACK]|r Legacy prediction system: ACTIVE")
|
||||||
|
|||||||
+95
-49
@@ -81,6 +81,9 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
["ACTIONBAR_UPDATE_COOLDOWN"] = true,
|
["ACTIONBAR_UPDATE_COOLDOWN"] = true,
|
||||||
["ACTIONBAR_UPDATE_USABLE"] = true,
|
["ACTIONBAR_UPDATE_USABLE"] = true,
|
||||||
["ACTIONBAR_UPDATE_STATE"] = true,
|
["ACTIONBAR_UPDATE_STATE"] = true,
|
||||||
|
-- fires on every ammo shot / consumable use, but only counts, equipped
|
||||||
|
-- state, cooldowns and usability can change from it
|
||||||
|
["UNIT_INVENTORY_CHANGED"] = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- events that are shared across all buttons
|
-- events that are shared across all buttons
|
||||||
@@ -97,8 +100,6 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
["TRADE_SKILL_CLOSE"] = true,
|
["TRADE_SKILL_CLOSE"] = true,
|
||||||
["PLAYER_ENTER_COMBAT"] = true,
|
["PLAYER_ENTER_COMBAT"] = true,
|
||||||
["PLAYER_LEAVE_COMBAT"] = true,
|
["PLAYER_LEAVE_COMBAT"] = true,
|
||||||
-- cooldown updates
|
|
||||||
["UNIT_INVENTORY_CHANGED"] = true,
|
|
||||||
-- auto repeat action
|
-- auto repeat action
|
||||||
["START_AUTOREPEAT_SPELL"] = true,
|
["START_AUTOREPEAT_SPELL"] = true,
|
||||||
["STOP_AUTOREPEAT_SPELL"] = true,
|
["STOP_AUTOREPEAT_SPELL"] = true,
|
||||||
@@ -317,7 +318,7 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
-- handle button highlight
|
-- handle button highlight
|
||||||
if keystate == "down" then
|
if keystate == "down" then
|
||||||
self.highlight:Show()
|
self.highlight:Show()
|
||||||
elseif not MouseIsOver(self) then
|
elseif not MouseIsOverHitRect(self) then
|
||||||
self.highlight:Hide()
|
self.highlight:Hide()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -400,6 +401,28 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
GameTooltip:Hide()
|
GameTooltip:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- item counts and equipped border, the parts of a slot an inventory change touches
|
||||||
|
local function ButtonInventoryUpdate(self)
|
||||||
|
if self.bar == 11 or self.bar == 12 then return end
|
||||||
|
local sid = self.id
|
||||||
|
|
||||||
|
-- update consumables
|
||||||
|
if IsConsumableAction(sid) then
|
||||||
|
self.count:SetText(GetActionCount(sid))
|
||||||
|
elseif IsReagentAction and IsReagentAction(sid) then
|
||||||
|
self.count:SetText(GetReagentCount(sid))
|
||||||
|
else
|
||||||
|
self.count:SetText(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- equipped item
|
||||||
|
if IsEquippedAction(sid) and C.bars.showequipped == "1" then
|
||||||
|
self.equipped:Show()
|
||||||
|
else
|
||||||
|
self.equipped:Hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local start, duration, enable, castable, autocast, token
|
local start, duration, enable, castable, autocast, token
|
||||||
local grid, sid, id, bar, active, texture, _
|
local grid, sid, id, bar, active, texture, _
|
||||||
local function ButtonSlotUpdate(self)
|
local function ButtonSlotUpdate(self)
|
||||||
@@ -460,23 +483,9 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
self.active:Hide()
|
self.active:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ButtonInventoryUpdate(self)
|
||||||
|
|
||||||
if self.bar ~= 11 and self.bar ~= 12 then
|
if self.bar ~= 11 and self.bar ~= 12 then
|
||||||
-- update consumables
|
|
||||||
if IsConsumableAction(sid) then
|
|
||||||
self.count:SetText(GetActionCount(sid))
|
|
||||||
elseif IsReagentAction and IsReagentAction(sid) then
|
|
||||||
self.count:SetText(GetReagentCount(sid))
|
|
||||||
else
|
|
||||||
self.count:SetText(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- equipped item
|
|
||||||
if IsEquippedAction(sid) and C.bars.showequipped == "1" then
|
|
||||||
self.equipped:Show()
|
|
||||||
else
|
|
||||||
self.equipped:Hide()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update macro text
|
-- update macro text
|
||||||
if C.bars["bar"..self.bar] and C.bars["bar"..self.bar].showmacro == "1" then
|
if C.bars["bar"..self.bar] and C.bars["bar"..self.bar].showmacro == "1" then
|
||||||
self.macro:SetText(GetActionText(sid))
|
self.macro:SetText(GetActionText(sid))
|
||||||
@@ -696,11 +705,29 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- The cached passes below only touch visible buttons. Hidden ones (other
|
||||||
|
-- pages, hidden bars) are flagged stale and get a full update once the
|
||||||
|
-- range pass sees them visible again.
|
||||||
|
|
||||||
|
-- run cached inventory changes (ammo, reagents, consumables)
|
||||||
|
if eventcache["UNIT_INVENTORY_CHANGED"] then
|
||||||
|
eventcache["UNIT_INVENTORY_CHANGED"] = nil
|
||||||
|
for id, button in pairs(buttoncache) do
|
||||||
|
if button:IsVisible() then
|
||||||
|
ButtonInventoryUpdate(button)
|
||||||
|
ButtonCooldownUpdate(button)
|
||||||
|
ButtonUsableUpdate(button)
|
||||||
|
else
|
||||||
|
button.stale = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- run cached usable usable actions
|
-- run cached usable usable actions
|
||||||
if eventcache["ACTIONBAR_UPDATE_USABLE"] then
|
if eventcache["ACTIONBAR_UPDATE_USABLE"] then
|
||||||
eventcache["ACTIONBAR_UPDATE_USABLE"] = nil
|
eventcache["ACTIONBAR_UPDATE_USABLE"] = nil
|
||||||
for id, button in pairs(buttoncache) do
|
for id, button in pairs(buttoncache) do
|
||||||
ButtonUsableUpdate(button)
|
if button:IsVisible() then ButtonUsableUpdate(button) else button.stale = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -708,7 +735,7 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
if eventcache["ACTIONBAR_UPDATE_COOLDOWN"] then
|
if eventcache["ACTIONBAR_UPDATE_COOLDOWN"] then
|
||||||
eventcache["ACTIONBAR_UPDATE_COOLDOWN"] = nil
|
eventcache["ACTIONBAR_UPDATE_COOLDOWN"] = nil
|
||||||
for id, button in pairs(buttoncache) do
|
for id, button in pairs(buttoncache) do
|
||||||
ButtonCooldownUpdate(button)
|
if button:IsVisible() then ButtonCooldownUpdate(button) else button.stale = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -716,7 +743,7 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
if eventcache["ACTIONBAR_UPDATE_STATE"] then
|
if eventcache["ACTIONBAR_UPDATE_STATE"] then
|
||||||
eventcache["ACTIONBAR_UPDATE_STATE"] = nil
|
eventcache["ACTIONBAR_UPDATE_STATE"] = nil
|
||||||
for id, button in pairs(buttoncache) do
|
for id, button in pairs(buttoncache) do
|
||||||
ButtonIsActiveUpdate(button)
|
if button:IsVisible() then ButtonIsActiveUpdate(button) else button.stale = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -738,7 +765,13 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
if ( this.tick or .2) > GetTime() then return else this.tick = GetTime() + .2 end
|
if ( this.tick or .2) > GetTime() then return else this.tick = GetTime() + .2 end
|
||||||
|
|
||||||
for id, button in pairs(buttoncache) do
|
for id, button in pairs(buttoncache) do
|
||||||
if button:IsShown() then ButtonRangeUpdate(button) end
|
if button.stale and button:IsVisible() then
|
||||||
|
-- catch up on updates skipped while hidden
|
||||||
|
button.stale = nil
|
||||||
|
ButtonFullUpdate(button)
|
||||||
|
elseif button:IsShown() then
|
||||||
|
ButtonRangeUpdate(button)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -828,17 +861,28 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
do
|
do
|
||||||
local formpage, shift, ctrl, alt, default = 8, 6, 5, 3, 1
|
local formpage, shift, ctrl, alt, default = 8, 6, 5, 3, 1
|
||||||
|
|
||||||
-- set temporary pagemaster bindings keybinds
|
-- while a page modifier is held, MOD-key must run the main bar binding on
|
||||||
if C.bars.pagemaster == "1" then
|
-- that key so the switched page fires. Overrides do this without touching
|
||||||
local modifier = { "ALT", "SHIFT", "CTRL" }
|
-- the saved binding set.
|
||||||
local buttons = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "=", "´" }
|
local pagemods = {}
|
||||||
local current = CURRENT_ACTIONBAR_PAGE
|
if C.bars.pagemasteralt == "1" then table.insert(pagemods, "ALT") end
|
||||||
bars.pagemaster = bars.pagemaster or CreateFrame("Frame", "pfPageMaster", UIParent)
|
if C.bars.pagemasterctrl == "1" then table.insert(pagemods, "CTRL") end
|
||||||
bars.pagemaster:RegisterEvent("PLAYER_ENTERING_WORLD")
|
if C.bars.pagemastershift == "1" then table.insert(pagemods, "SHIFT") end
|
||||||
bars.pagemaster:SetScript("OnEvent", function()
|
|
||||||
for _,mod in pairs(modifier) do
|
if table.getn(pagemods) > 0 then
|
||||||
for _,but in pairs(buttons) do
|
local pagemaster = CreateFrame("Frame", "pfPageMaster", UIParent)
|
||||||
SetBinding(mod.."-"..but)
|
pagemaster:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
pagemaster:RegisterEvent("UPDATE_BINDINGS")
|
||||||
|
pagemaster:SetScript("OnEvent", function()
|
||||||
|
ClearOverrideBindings(this)
|
||||||
|
for i = 1, 12 do
|
||||||
|
for _, key in ipairs({ GetBindingKey("ACTIONBUTTON"..i) }) do
|
||||||
|
-- skip keys that already carry a modifier, e.g. "SHIFT-Q"
|
||||||
|
if not key:find("^%u+%-.") then
|
||||||
|
for _, mod in ipairs(pagemods) do
|
||||||
|
SetOverrideBinding(this, false, mod.."-"..key, "ACTIONBUTTON"..i)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -853,6 +897,10 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
pageswitch:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
|
pageswitch:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
|
||||||
pageswitch:RegisterEvent("PLAYER_AURAS_CHANGED")
|
pageswitch:RegisterEvent("PLAYER_AURAS_CHANGED")
|
||||||
pageswitch:RegisterEvent("PLAYER_LOGOUT")
|
pageswitch:RegisterEvent("PLAYER_LOGOUT")
|
||||||
|
local PROWL_IDS = { [5215] = true, [6783] = true, [9913] = true }
|
||||||
|
if class == "DRUID" then
|
||||||
|
pageswitch:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
|
||||||
|
end
|
||||||
pageswitch:SetScript("OnEvent", function()
|
pageswitch:SetScript("OnEvent", function()
|
||||||
if event == "PLAYER_LOGOUT" then
|
if event == "PLAYER_LOGOUT" then
|
||||||
this:UnregisterAllEvents()
|
this:UnregisterAllEvents()
|
||||||
@@ -875,6 +923,18 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Eager prowl detection on the cast itself — zero-latency vs.
|
||||||
|
-- PLAYER_AURAS_CHANGED, which can land a frame or two behind it.
|
||||||
|
-- arg3 = spellID
|
||||||
|
if event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||||
|
if PROWL_IDS[arg3] then
|
||||||
|
inCatForm = true
|
||||||
|
prowlActive = true
|
||||||
|
formpaging = true
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if event == "UPDATE_SHAPESHIFT_FORM" then
|
if event == "UPDATE_SHAPESHIFT_FORM" then
|
||||||
-- Authoritative form-change signal — recompute and short-circuit.
|
-- Authoritative form-change signal — recompute and short-circuit.
|
||||||
inCatForm = HasCatForm()
|
inCatForm = HasCatForm()
|
||||||
@@ -898,20 +958,6 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Eager prowl detection via Nampower SPELL_GO_SELF — zero-latency vs.
|
|
||||||
-- PLAYER_AURAS_CHANGED, which can land a frame or two behind the cast.
|
|
||||||
-- Form changes are no longer hooked here; UPDATE_SHAPESHIFT_FORM covers
|
|
||||||
-- those without needing a per-spellID watchlist.
|
|
||||||
local PROWL_IDS = { [5215] = true, [6783] = true, [9913] = true }
|
|
||||||
pfUI.libdebuff_spell_go_hooks = pfUI.libdebuff_spell_go_hooks or {}
|
|
||||||
pfUI.libdebuff_spell_go_hooks["actionbar_prowl"] = function(spellId)
|
|
||||||
if class ~= "DRUID" then return end
|
|
||||||
if PROWL_IDS[spellId] then
|
|
||||||
inCatForm = true
|
|
||||||
prowlActive = true
|
|
||||||
formpaging = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
pageswitch:SetScript("OnUpdate", function()
|
pageswitch:SetScript("OnUpdate", function()
|
||||||
-- switch actionbar page depending on meta key that is pressed
|
-- switch actionbar page depending on meta key that is pressed
|
||||||
if C.bars.pagemastershift == "1" and IsShiftKeyDown() then
|
if C.bars.pagemastershift == "1" and IsShiftKeyDown() then
|
||||||
@@ -997,7 +1043,7 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
f.slot = id
|
f.slot = id
|
||||||
|
|
||||||
-- cooldown
|
-- cooldown
|
||||||
f.cd = CreateFrame("Model", f:GetName() .. "Cooldown", f, "CooldownFrameTemplate")
|
f.cd = CreateFrame("Cooldown", f:GetName() .. "Cooldown", f, "CooldownFrameTemplate")
|
||||||
f.cd.pfCooldownStyleAnimation = 1
|
f.cd.pfCooldownStyleAnimation = 1
|
||||||
f.cd.pfCooldownType = "NOGCD"
|
f.cd.pfCooldownType = "NOGCD"
|
||||||
f.cd.pfCooldownSize = cd_size
|
f.cd.pfCooldownSize = cd_size
|
||||||
|
|||||||
@@ -399,15 +399,16 @@ pfUI:RegisterModule("addonbuttons", function ()
|
|||||||
|
|
||||||
-- Initial setup on the next frame, once other addons' minimap buttons exist
|
-- Initial setup on the next frame, once other addons' minimap buttons exist
|
||||||
RunNextFrame(function()
|
RunNextFrame(function()
|
||||||
-- check if the panel should be shown by default
|
-- rescan before deciding whether the panel should be shown by default
|
||||||
|
pfUI.addonbuttons:ProcessButtons()
|
||||||
|
|
||||||
if C.abuttons.showdefault == "1" and GetNumButtons() > 0 then
|
if C.abuttons.showdefault == "1" and GetNumButtons() > 0 then
|
||||||
pfUI.addonbuttons:Show()
|
pfUI.addonbuttons:Show()
|
||||||
else
|
else
|
||||||
pfUI.addonbuttons:Hide()
|
pfUI.addonbuttons:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update all buttons and apply workarounds
|
-- apply workarounds
|
||||||
pfUI.addonbuttons:ProcessButtons()
|
|
||||||
for k, v in pairs(pfUI.addonbuttons.overrides) do
|
for k, v in pairs(pfUI.addonbuttons.overrides) do
|
||||||
_G[k] = v
|
_G[k] = v
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ pfUI:RegisterModule("addons", function ()
|
|||||||
pfUI.addons:Show()
|
pfUI.addons:Show()
|
||||||
HideUIPanel(GameMenuFrame)
|
HideUIPanel(GameMenuFrame)
|
||||||
end)
|
end)
|
||||||
SkinButton(pfUIAddonButton)
|
|
||||||
|
|
||||||
local point, relativeTo, relativePoint, xOffset, yOffset = GameMenuButtonOptions:GetPoint()
|
local point, relativeTo, relativePoint, xOffset, yOffset = GameMenuButtonOptions:GetPoint()
|
||||||
GameMenuButtonOptions:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset - 22)
|
GameMenuButtonOptions:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset - 22)
|
||||||
|
|||||||
+3
-4
@@ -396,14 +396,13 @@ pfUI:RegisterModule("bags", function ()
|
|||||||
if tpl == "BankItemButtonGenericTemplate" then
|
if tpl == "BankItemButtonGenericTemplate" then
|
||||||
local bankslot = pfUI.bags[bag].slots[slot].frame
|
local bankslot = pfUI.bags[bag].slots[slot].frame
|
||||||
local name = "pfBag" .. bag .. "item" .. slot .. "Cooldown"
|
local name = "pfBag" .. bag .. "item" .. slot .. "Cooldown"
|
||||||
bankslot.cd = CreateFrame("Model", name, bankslot, "CooldownFrameTemplate")
|
bankslot.cd = CreateFrame("Cooldown", name, bankslot, "CooldownFrameTemplate")
|
||||||
bankslot.cd:SetAllPoints(bankslot)
|
|
||||||
bankslot.cd.pfCooldownStyleAnimation = 1
|
bankslot.cd.pfCooldownStyleAnimation = 1
|
||||||
bankslot.cd.pfCooldownType = "ALL"
|
bankslot.cd.pfCooldownType = "NOGCD"
|
||||||
else
|
else
|
||||||
local bagslot = pfUI.bags[bag].slots[slot].frame
|
local bagslot = pfUI.bags[bag].slots[slot].frame
|
||||||
bagslot.cd = _G[bagslot:GetName().."Cooldown"]
|
bagslot.cd = _G[bagslot:GetName().."Cooldown"]
|
||||||
bagslot.cd.pfCooldownType = "ALL"
|
bagslot.cd.pfCooldownType = "NOGCD"
|
||||||
end
|
end
|
||||||
|
|
||||||
if not pfUI.bags[bag].slots[slot].frame.backdrop then
|
if not pfUI.bags[bag].slots[slot].frame.backdrop then
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ pfUI:RegisterModule("buff", function ()
|
|||||||
local function RefreshBuffButton(buff)
|
local function RefreshBuffButton(buff)
|
||||||
if buff.btype == "HELPFUL" then
|
if buff.btype == "HELPFUL" then
|
||||||
if C.buffs.separateweapons == "1" then
|
if C.buffs.separateweapons == "1" then
|
||||||
buff.id = buff.gid - (buff.weapon ~= nill and buff.gid or 0)
|
buff.id = buff.gid - (buff.weapon ~= nil and buff.gid or 0)
|
||||||
else
|
else
|
||||||
buff.id = buff.gid - pfUI.buff.wepbuffs.count
|
buff.id = buff.gid - pfUI.buff.wepbuffs.count
|
||||||
end
|
end
|
||||||
|
|||||||
+3
-34
@@ -76,10 +76,6 @@ pfUI:RegisterModule("buffwatch", function ()
|
|||||||
-- reusable GetAuraSlots buffer, filled once per RefreshBuffBarFrame
|
-- reusable GetAuraSlots buffer, filled once per RefreshBuffBarFrame
|
||||||
local auraSlots = {}
|
local auraSlots = {}
|
||||||
|
|
||||||
-- Separate buffer for the tooltip handler: OnEnter can fire while a refresh
|
|
||||||
-- is showing/hiding bars under the cursor, so it must not share the above.
|
|
||||||
local tooltipSlots = {}
|
|
||||||
|
|
||||||
-- Reads one aura by the slot id GetAuraSlots returned (nil slot -> nil).
|
-- Reads one aura by the slot id GetAuraSlots returned (nil slot -> nil).
|
||||||
local function GetBuffData(unit, slot)
|
local function GetBuffData(unit, slot)
|
||||||
local name, icon, count, dispelType, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unit, slot)
|
local name, icon, count, dispelType, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unit, slot)
|
||||||
@@ -116,36 +112,9 @@ pfUI:RegisterModule("buffwatch", function ()
|
|||||||
local function StatusBarOnEnter()
|
local function StatusBarOnEnter()
|
||||||
GameTooltip:SetOwner(this, "NONE")
|
GameTooltip:SetOwner(this, "NONE")
|
||||||
|
|
||||||
if this.unit == "player" then
|
-- C_UnitAuras lists the player's own auras first, so the selfdebuff
|
||||||
GameTooltip:SetUnitAura("player", this.id, this.type)
|
-- (HARMFUL|PLAYER) list is a prefix of the HARMFUL list: same index.
|
||||||
elseif this.type == "HARMFUL" then
|
GameTooltip:SetUnitAura(this.unit, this.id, this.type)
|
||||||
-- selfdebuff filters the displayed list to player-cast harmful auras, but
|
|
||||||
-- SetUnitAura's index has to be into the unfiltered HARMFUL list. Look up
|
|
||||||
-- the displayed aura via the PLAYER filter, then find its position in the
|
|
||||||
-- unfiltered list by name + sourceGUID.
|
|
||||||
--
|
|
||||||
-- The unfiltered list is NOT capped at 16: once a unit's 16 debuff slots
|
|
||||||
-- are full the server parks further debuffs in buff slots, and
|
|
||||||
-- C_UnitAuras reports those as harmful too. So enumerate what it has.
|
|
||||||
local config = this.parent and this.parent.config
|
|
||||||
if config and config.selfdebuff == "1" then
|
|
||||||
local ownAura = C_UnitAuras.GetAuraDataByIndex(this.unit, this.id, "HARMFUL|PLAYER")
|
|
||||||
if ownAura then
|
|
||||||
local n = ScanAuraSlots(this.unit, "HARMFUL", tooltipSlots)
|
|
||||||
for i = 1, n do
|
|
||||||
local check = C_UnitAuras.GetAuraDataBySlot(this.unit, tooltipSlots[i])
|
|
||||||
if check and check.name == ownAura.name and check.sourceGUID == ownAura.sourceGUID then
|
|
||||||
GameTooltip:SetUnitAura(this.unit, i, "HARMFUL")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
GameTooltip:SetUnitAura(this.unit, this.id, "HARMFUL")
|
|
||||||
end
|
|
||||||
elseif this.type == "HELPFUL" then
|
|
||||||
GameTooltip:SetUnitAura(this.unit, this.id, "HELPFUL")
|
|
||||||
end
|
|
||||||
|
|
||||||
if IsShiftKeyDown() then
|
if IsShiftKeyDown() then
|
||||||
GameTooltip:AddLine(" ")
|
GameTooltip:AddLine(" ")
|
||||||
|
|||||||
+30
-14
@@ -36,7 +36,7 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
cb.bar:SetValue(1)
|
cb.bar:SetValue(1)
|
||||||
end
|
end
|
||||||
if cb.bar.spark then cb.bar.spark:Hide() end
|
if cb.bar.spark then cb.bar.spark:Hide() end
|
||||||
cb.fadeout = 1
|
if cb:GetAlpha() > 0 and not cb.fade:IsPlaying() then cb.fade:Play() end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- "Spellname (N)" label for an active tradeskill merge — N is the number
|
-- "Spellname (N)" label for an active tradeskill merge — N is the number
|
||||||
@@ -86,7 +86,7 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
|
|
||||||
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
||||||
-- then animates the fill from this state without touching C_Spell.
|
-- then animates the fill from this state without touching C_Spell.
|
||||||
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank)
|
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank, noInterrupt)
|
||||||
cb.startTime = startMs
|
cb.startTime = startMs
|
||||||
cb.endTime = endMs
|
cb.endTime = endMs
|
||||||
cb.isChannel = isChannel
|
cb.isChannel = isChannel
|
||||||
@@ -94,10 +94,13 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
cb.activeName = name
|
cb.activeName = name
|
||||||
cb.isTradeskill = isTradeskill
|
cb.isTradeskill = isTradeskill
|
||||||
cb.delay = (delayMs or 0) / 1000
|
cb.delay = (delayMs or 0) / 1000
|
||||||
|
cb.fade:Stop()
|
||||||
cb:SetAlpha(1)
|
cb:SetAlpha(1)
|
||||||
cb.fadeout = nil
|
|
||||||
|
|
||||||
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
|
-- Shield an uninterruptible cast. Not on the player's own bar: the flag is
|
||||||
|
-- measured against the reader's own interrupts and silences, so on your own
|
||||||
|
-- cast it answers a question nobody asked.
|
||||||
|
SetCastbarShield(cb.bar, cb.icon, noInterrupt and cb.unitstr ~= "player", isChannel)
|
||||||
|
|
||||||
-- Rank: prefer the value the UNIT_SPELLCAST_* event delivered (arg5, passed
|
-- Rank: prefer the value the UNIT_SPELLCAST_* event delivered (arg5, passed
|
||||||
-- through by RefreshBar). Only the retarget re-poll has no event in hand, so
|
-- through by RefreshBar). Only the retarget re-poll has no event in hand, so
|
||||||
@@ -152,10 +155,10 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
ClearBar(cb)
|
ClearBar(cb)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local name, _, tex, startMs, endMs, isTradeskill, _, _, spellID, _, delayMs = C_Spell.UnitCastingInfo(query)
|
local name, _, tex, startMs, endMs, isTradeskill, _, noInterrupt, spellID, _, delayMs = C_Spell.UnitCastingInfo(query)
|
||||||
local isChan
|
local isChan
|
||||||
if not name then
|
if not name then
|
||||||
name, _, tex, startMs, endMs, _, _, spellID = C_Spell.UnitChannelInfo(query)
|
name, _, tex, startMs, endMs, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(query)
|
||||||
isChan = true
|
isChan = true
|
||||||
end
|
end
|
||||||
-- Synthetic fallback for abilities the engine treats as instant-cast but
|
-- Synthetic fallback for abilities the engine treats as instant-cast but
|
||||||
@@ -169,7 +172,7 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if name and startMs and endMs then
|
if name and startMs and endMs then
|
||||||
StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank)
|
StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank, noInterrupt)
|
||||||
else
|
else
|
||||||
ClearBar(cb)
|
ClearBar(cb)
|
||||||
end
|
end
|
||||||
@@ -245,8 +248,14 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
cb.bar.spark:SetPoint("BOTTOM", cb.bar, "BOTTOMLEFT", 0, 0)
|
cb.bar.spark:SetPoint("BOTTOM", cb.bar, "BOTTOMLEFT", 0, 0)
|
||||||
cb.bar.spark:Hide()
|
cb.bar.spark:Hide()
|
||||||
|
|
||||||
-- OnUpdate animates the bar fill and fades it out on completion. All
|
-- Fade-out after a cast ends. The bar stays at alpha 0 while idle.
|
||||||
-- state transitions (cast start/stop/interrupt, channel start/stop,
|
cb.fade = cb:CreateAnimationGroup()
|
||||||
|
local fade = cb.fade:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-1)
|
||||||
|
fade:SetDuration(.4)
|
||||||
|
cb.fade:SetScript("OnFinished", function() cb:SetAlpha(0) end)
|
||||||
|
|
||||||
|
-- OnUpdate animates the bar fill. All state transitions (cast start/stop/interrupt, channel start/stop,
|
||||||
-- pushback) come from the event handler below — we never poll C_Spell
|
-- pushback) come from the event handler below — we never poll C_Spell
|
||||||
-- here.
|
-- here.
|
||||||
cb:SetScript("OnUpdate", function()
|
cb:SetScript("OnUpdate", function()
|
||||||
@@ -254,15 +263,12 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
this.tick = GetTime() + 0.020 -- ~50 FPS
|
this.tick = GetTime() + 0.020 -- ~50 FPS
|
||||||
|
|
||||||
if this.drag and this.drag:IsShown() then
|
if this.drag and this.drag:IsShown() then
|
||||||
|
this.fade:Stop()
|
||||||
this:SetAlpha(1)
|
this:SetAlpha(1)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.fadeout and this:GetAlpha() > 0 then
|
if this.fade:IsPlaying() then return end
|
||||||
this:SetAlpha(this:GetAlpha() - 0.05)
|
|
||||||
if this:GetAlpha() <= 0 then this.fadeout = nil end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not this.endTime then
|
if not this.endTime then
|
||||||
if this:GetAlpha() ~= 0 then this:SetAlpha(0) end
|
if this:GetAlpha() ~= 0 then this:SetAlpha(0) end
|
||||||
@@ -342,6 +348,12 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
elseif unitstr == "focus" then
|
elseif unitstr == "focus" then
|
||||||
cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
|
cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
|
||||||
end
|
end
|
||||||
|
-- The shield can flip mid-cast (the caster gains or loses an aura that
|
||||||
|
-- blocks interrupts). These only fire for target and focus.
|
||||||
|
if unitstr == "target" or unitstr == "focus" then
|
||||||
|
cb:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTIBLE", unitstr)
|
||||||
|
cb:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", unitstr)
|
||||||
|
end
|
||||||
|
|
||||||
cb:SetScript("OnEvent", function()
|
cb:SetScript("OnEvent", function()
|
||||||
local unit = this.unitstr
|
local unit = this.unitstr
|
||||||
@@ -397,6 +409,10 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
if not this.tradeskillTotal then ClearBar(this) end
|
if not this.tradeskillTotal then ClearBar(this) end
|
||||||
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||||
ClearBar(this, true)
|
ClearBar(this, true)
|
||||||
|
elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" or event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
|
||||||
|
if this.endTime then
|
||||||
|
SetCastbarShield(this.bar, this.icon, event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE", this.isChannel)
|
||||||
|
end
|
||||||
elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
||||||
-- Pushback: a cast delayed later or a channel shortened. Following
|
-- Pushback: a cast delayed later or a channel shortened. Following
|
||||||
-- Quartz, re-poll just the times and accumulate the shift into a running
|
-- Quartz, re-poll just the times and accumulate the shift into a running
|
||||||
|
|||||||
+52
-61
@@ -526,10 +526,10 @@ pfUI:RegisterModule("chat", function ()
|
|||||||
|
|
||||||
if pfUI.chat.hideLock then return end
|
if pfUI.chat.hideLock then return end
|
||||||
|
|
||||||
if MouseIsOver(pfUI.chat.left, 10, -10, -10, 10) then
|
if pfUI.chat.left:IsMouseOver(10, -10, -10, 10) then
|
||||||
pfUI.chat.left.panelTop:Show()
|
pfUI.chat.left.panelTop:Show()
|
||||||
FCF_DockUpdate()
|
FCF_DockUpdate()
|
||||||
elseif MouseIsOver(pfUI.chat.right, 10, -10, -10, 10) then
|
elseif pfUI.chat.right:IsMouseOver(10, -10, -10, 10) then
|
||||||
-- disable while dock is active
|
-- disable while dock is active
|
||||||
if pfUI.chat.right:GetAlpha() == 0 then return end
|
if pfUI.chat.right:GetAlpha() == 0 then return end
|
||||||
|
|
||||||
@@ -782,16 +782,6 @@ pfUI:RegisterModule("chat", function ()
|
|||||||
local r,g,b = GetStringColor(C.chat.text.unknowncolor)
|
local r,g,b = GetStringColor(C.chat.text.unknowncolor)
|
||||||
local unknowncolorhex = rgbhex(r,g,b)
|
local unknowncolorhex = rgbhex(r,g,b)
|
||||||
|
|
||||||
-- Suppress FriendsFrame's WHO_LIST_UPDATE handling for our DLL-issued
|
|
||||||
-- name lookups so they don't pop the friends panel. User-issued /who
|
|
||||||
-- still works because IsWhoQueryPending only reports true for queries
|
|
||||||
-- issued via C_FriendList.SendWhoQueryByName.
|
|
||||||
local original_FriendsFrame_OnEvent = FriendsFrame_OnEvent
|
|
||||||
_G.FriendsFrame_OnEvent = function()
|
|
||||||
if _G.event == "WHO_LIST_UPDATE" and C_FriendList.IsWhoQueryPending() then return end
|
|
||||||
return original_FriendsFrame_OnEvent()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GetPlayerLevel(name)
|
local function GetPlayerLevel(name)
|
||||||
if not pfUI_playerDB then return nil end
|
if not pfUI_playerDB then return nil end
|
||||||
if not pfUI_playerDB[name] then return nil end
|
if not pfUI_playerDB[name] then return nil end
|
||||||
@@ -806,6 +796,10 @@ pfUI:RegisterModule("chat", function ()
|
|||||||
return frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
|
return frame:HookAddMessage(text, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- payload of the CHAT_MSG event printing this line; nil for lines
|
||||||
|
-- that don't come from one (system text, addon output, history)
|
||||||
|
local event, _, sender, _, _, _, _, _, _, _, _, _, guid = GetCurrentChatEvent()
|
||||||
|
|
||||||
-- Remove prat CLINKs
|
-- Remove prat CLINKs
|
||||||
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- tbc
|
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- tbc
|
||||||
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- vanilla
|
text = gsub(text, "{CLINK:(%x+):([%d-]-:[%d-]-:[%d-]-:[%d-]-):([^}]-)}", "|c%1|Hitem:%2|h[%3]|h|r") -- vanilla
|
||||||
@@ -821,67 +815,64 @@ pfUI:RegisterModule("chat", function ()
|
|||||||
text = pfUI.chat:HandleLink(text)
|
text = pfUI.chat:HandleLink(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- display class colors if already indexed
|
-- display class colors and player levels if already indexed
|
||||||
if C.chat.text.classcolor == "1" then
|
local classcolor = C.chat.text.classcolor == "1"
|
||||||
for name in gfind(text, "|Hplayer:(.-)|h") do
|
local playerlevel = C.chat.text.playerlevel == "1"
|
||||||
local real, _ = strsplit(":", name)
|
if classcolor or playerlevel then
|
||||||
local color = unknowncolorhex
|
-- the engine name-queries a chat sender before the event fires,
|
||||||
local match = false
|
-- so the sender's GUID always resolves; other names in the text
|
||||||
local _, class, _, raceKey, sex = C_PlayerCache.GetPlayerInfoByName(real)
|
-- fall back to the name-keyed lookups
|
||||||
-- local guid = GetCurrentChatGUID()
|
local _, senderClass, senderRace, senderSex
|
||||||
-- if guid then
|
if classcolor and guid and guid ~= "" then
|
||||||
-- _, class = GetPlayerInfoByGUID(guid)
|
_, senderClass, _, senderRace, senderSex = GetPlayerInfoByGUID(guid)
|
||||||
-- end
|
|
||||||
if not class then
|
|
||||||
class = GetUnitInfo(real)
|
|
||||||
end
|
|
||||||
if class then
|
|
||||||
if class ~= UNKNOWN then
|
|
||||||
color = "|c" .. PFUI_CLASS_COLORS[class].colorStr
|
|
||||||
match = true
|
|
||||||
end
|
|
||||||
elseif C.chat.text.whosearchunknown == "1" then
|
|
||||||
C_FriendList.SendWhoQueryByName(name) -- cooldown + state managed by DLL
|
|
||||||
end
|
|
||||||
|
|
||||||
if C.chat.text.tintunknown == "1" or match then
|
|
||||||
local icon = ""
|
|
||||||
if match and C.chat.text.playericons == "1" then
|
|
||||||
icon = GetFactionIcon(raceKey) .. GetRaceIcon(raceKey, sex)
|
|
||||||
end
|
|
||||||
text = string.gsub(text, "|Hplayer:"..name.."|h%["..real.."%]|h(.-:-)",
|
|
||||||
left..icon..color.."|Hplayer:"..name.."|h" .. color .. real .. "|h|r"..right.."%1")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- display player levels if available
|
|
||||||
if C.chat.text.playerlevel == "1" then
|
|
||||||
for name in gfind(text, "|Hplayer:(.-)|h") do
|
for name in gfind(text, "|Hplayer:(.-)|h") do
|
||||||
local real, _ = strsplit(":", name)
|
local real, _ = strsplit(":", name)
|
||||||
local level = GetPlayerLevel(real)
|
local color, icon = "", ""
|
||||||
|
|
||||||
|
if classcolor then
|
||||||
|
local class, raceKey, sex
|
||||||
|
if senderClass and real == sender then
|
||||||
|
class, raceKey, sex = senderClass, senderRace, senderSex
|
||||||
|
else
|
||||||
|
_, class, _, raceKey, sex = C_PlayerCache.GetPlayerInfoByName(real)
|
||||||
|
end
|
||||||
|
if not class then
|
||||||
|
class = GetUnitInfo(real)
|
||||||
|
end
|
||||||
|
if class and class ~= UNKNOWN then
|
||||||
|
color = "|c" .. PFUI_CLASS_COLORS[class].colorStr
|
||||||
|
if C.chat.text.factionicons == "1" then
|
||||||
|
icon = GetFactionIcon(raceKey)
|
||||||
|
end
|
||||||
|
if C.chat.text.raceicons == "1" then
|
||||||
|
icon = icon .. GetRaceIcon(raceKey, sex)
|
||||||
|
end
|
||||||
|
elseif C.chat.text.tintunknown == "1" then
|
||||||
|
color = unknowncolorhex
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local suffix = ""
|
||||||
|
local level = playerlevel and GetPlayerLevel(real)
|
||||||
if level and level > 0 then
|
if level and level > 0 then
|
||||||
local levelcolor = rgbhex(GetDifficultyColor(level))
|
suffix = " " .. rgbhex(GetDifficultyColor(level)) .. level .. "|r"
|
||||||
-- Add level after the player name, before the closing bracket
|
elseif level then
|
||||||
text = string.gsub(text, "(|Hplayer:" .. name .. "|h.-|h|r)" .. right,
|
|
||||||
"%1 " .. levelcolor .. level .. "|r" .. right)
|
|
||||||
elseif level and level <= 0 then
|
|
||||||
-- Show ?? for unknown levels (e.g. -1 from UnitLevel)
|
-- Show ?? for unknown levels (e.g. -1 from UnitLevel)
|
||||||
text = string.gsub(text, "(|Hplayer:" .. name .. "|h.-|h|r)" .. right,
|
suffix = " |cffff0000??|r"
|
||||||
"%1 |cffff0000??|r" .. right)
|
end
|
||||||
|
|
||||||
|
if color ~= "" or suffix ~= "" then
|
||||||
|
text = string.gsub(text, "|Hplayer:"..name.."|h%["..real.."%]|h(.-:-)",
|
||||||
|
left..icon..color.."|Hplayer:"..name.."|h" .. color .. real .. "|h|r"..suffix..right.."%1")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- reduce channel name to number
|
-- reduce channel name to number
|
||||||
if C.chat.text.channelnumonly == "1" then
|
if C.chat.text.channelnumonly == "1" and event == "CHAT_MSG_CHANNEL" then
|
||||||
local channel = string.gsub(text, ".*%[(.-)%]%s+(.*|Hplayer).+", "%1")
|
text = string.gsub(text, "%[(%d+)%..-%] ", left .. "%1" .. right .. " ", 1)
|
||||||
if string.find(channel, "%d+%. ") then
|
|
||||||
channel = string.gsub(channel, "(%d+)%..*", "channel%1")
|
|
||||||
channel = string.gsub(channel, "channel", "")
|
|
||||||
text = string.gsub(text, "%[%d+%..-%]%s+(.*|Hplayer)", left .. channel .. right .. " %1")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- detect the whisper prefix BEFORE prepending a timestamp; the timestamp
|
-- detect the whisper prefix BEFORE prepending a timestamp; the timestamp
|
||||||
|
|||||||
@@ -104,8 +104,10 @@ pfUI:RegisterModule("cooldown", function ()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- realign cooldown frames
|
-- realign the indicator Models that stock buttons build; the model is
|
||||||
local parent = this.GetParent and this:GetParent()
|
-- drawn at 36px and needs scaling to its button. A Cooldown draws its
|
||||||
|
-- sweep to its own rect.
|
||||||
|
local parent = this.GetParent and not this:IsObjectType("Cooldown") and this:GetParent()
|
||||||
if parent and parent:GetWidth() / 36 > 0 then
|
if parent and parent:GetWidth() / 36 > 0 then
|
||||||
this:SetScale(parent:GetWidth() / 36)
|
this:SetScale(parent:GetWidth() / 36)
|
||||||
this:SetPoint("TOPLEFT", parent, "TOPLEFT", -1, 1)
|
this:SetPoint("TOPLEFT", parent, "TOPLEFT", -1, 1)
|
||||||
@@ -144,7 +146,7 @@ pfUI:RegisterModule("cooldown", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- vanilla does not have a cooldown frame type, so we hook the
|
-- hook the SetTimer function that every cooldown, Cooldown frame or
|
||||||
-- regular SetTimer function that each one is calling.
|
-- stock indicator Model, is driven through.
|
||||||
hooksecurefunc("CooldownFrame_SetTimer", SetCooldown)
|
hooksecurefunc("CooldownFrame_SetTimer", SetCooldown)
|
||||||
end)
|
end)
|
||||||
+44
-7
@@ -89,6 +89,13 @@ pfUI:RegisterModule("energytick", function()
|
|||||||
return C.unitframes.player.pwidth ~= "-1" and C.unitframes.player.pwidth or C.unitframes.player.width
|
return C.unitframes.player.pwidth ~= "-1" and C.unitframes.player.pwidth or C.unitframes.player.width
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local rawborder, default_border = GetBorderSize("unitframes")
|
||||||
|
local cbtexture = pfUI.media[C.appearance.castbar.texture]
|
||||||
|
|
||||||
|
-- style is read once: switching it in the GUI needs a /reload, same as the
|
||||||
|
-- other structural (not cosmetic) toggles in this file
|
||||||
|
local fsrOverlay = C.unitframes.player.fsrstyle == "1"
|
||||||
|
|
||||||
-- was this gain the regen tick? if so, re-anchor the sweep on it
|
-- was this gain the regen tick? if so, re-anchor the sweep on it
|
||||||
local function lockTick(frame)
|
local function lockTick(frame)
|
||||||
local now, period = GetTime(), getAdjustedTickTimer()
|
local now, period = GetTime(), getAdjustedTickTimer()
|
||||||
@@ -199,11 +206,21 @@ pfUI:RegisterModule("energytick", function()
|
|||||||
end
|
end
|
||||||
this.tick = GetTime() + 0.020 -- ~50 FPS
|
this.tick = GetTime() + 0.020 -- ~50 FPS
|
||||||
|
|
||||||
-- five-second rule drains to nothing
|
-- five-second rule drains to nothing. The display is cosmetic and can be
|
||||||
|
-- hidden on its own; the window itself (fsrEnd/fsrGain) keeps running
|
||||||
|
-- either way -- it still dims the sweep spark below.
|
||||||
local remaining = this.fsrEnd and (this.fsrEnd - GetTime()) or 0
|
local remaining = this.fsrEnd and (this.fsrEnd - GetTime()) or 0
|
||||||
if this.mode == "MANA" and remaining > 0 then
|
if this.mode == "MANA" and remaining > 0 then
|
||||||
this.fsrbar:SetWidth(getBarWidth() * remaining / FIVE_SECOND_RULE)
|
if C.unitframes.player.showfsr == "1" then
|
||||||
this.fsrbar:Show()
|
if fsrOverlay then
|
||||||
|
this.fsrbar:SetWidth(getBarWidth() * remaining / FIVE_SECOND_RULE)
|
||||||
|
else
|
||||||
|
this.fsrbar:SetValue(remaining)
|
||||||
|
end
|
||||||
|
this.fsrbar:Show()
|
||||||
|
else
|
||||||
|
this.fsrbar:Hide()
|
||||||
|
end
|
||||||
else
|
else
|
||||||
this.fsrSpell, this.fsrEnd, this.fsrGain = nil, nil, nil
|
this.fsrSpell, this.fsrEnd, this.fsrGain = nil, nil, nil
|
||||||
this.fsrbar:Hide()
|
this.fsrbar:Hide()
|
||||||
@@ -240,10 +257,26 @@ pfUI:RegisterModule("energytick", function()
|
|||||||
this.spark:SetPoint("LEFT", pos - ((C.unitframes.player.pheight + 5) / 2), 0)
|
this.spark:SetPoint("LEFT", pos - ((C.unitframes.player.pheight + 5) / 2), 0)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
energytick.fsrbar = energytick:CreateTexture(nil, "ARTWORK")
|
if fsrOverlay then
|
||||||
energytick.fsrbar:SetTexture(1, 1, 1, .15)
|
-- classic style: a translucent shade on top of the power bar's own fill
|
||||||
energytick.fsrbar:SetPoint("TOPLEFT", 0, 0)
|
energytick.fsrbar = energytick:CreateTexture(nil, "ARTWORK")
|
||||||
energytick.fsrbar:SetPoint("BOTTOMLEFT", 0, 0)
|
energytick.fsrbar:SetTexture(1, 1, 1, .15)
|
||||||
|
energytick.fsrbar:SetPoint("TOPLEFT", 0, 0)
|
||||||
|
energytick.fsrbar:SetPoint("BOTTOMLEFT", 0, 0)
|
||||||
|
else
|
||||||
|
-- a real bar below the power bar, not an overlay on top of it -- the same
|
||||||
|
-- treatment nameplate castbars get relative to the health bar, so the
|
||||||
|
-- window can't be mistaken for missing mana
|
||||||
|
energytick.fsrbar = CreateFrame("StatusBar", nil, pfUI.uf.player)
|
||||||
|
energytick.fsrbar:SetStatusBarTexture(cbtexture)
|
||||||
|
energytick.fsrbar:SetMinMaxValues(0, FIVE_SECOND_RULE)
|
||||||
|
energytick.fsrbar:SetPoint("TOPLEFT", pfUI.uf.player.power.bar, "BOTTOMLEFT", 0, -default_border * 2)
|
||||||
|
energytick.fsrbar:SetPoint("TOPRIGHT", pfUI.uf.player.power.bar, "BOTTOMRIGHT", 0, -default_border * 2)
|
||||||
|
energytick.fsrbar:SetHeight(tonumber(C.unitframes.player.fsrheight) or 4)
|
||||||
|
energytick.fsrbar:SetStatusBarColor(GetStringColor(C.appearance.castbar.fsrcolor))
|
||||||
|
CreateBackdrop(energytick.fsrbar, default_border)
|
||||||
|
CreateBackdropShadow(energytick.fsrbar)
|
||||||
|
end
|
||||||
energytick.fsrbar:Hide()
|
energytick.fsrbar:Hide()
|
||||||
|
|
||||||
energytick.spark = energytick:CreateTexture(nil, "OVERLAY")
|
energytick.spark = energytick:CreateTexture(nil, "OVERLAY")
|
||||||
@@ -256,6 +289,10 @@ pfUI:RegisterModule("energytick", function()
|
|||||||
function pfUI.uf.player.UpdateConfig()
|
function pfUI.uf.player.UpdateConfig()
|
||||||
energytick.spark:SetHeight(C.unitframes.player.pheight + 15)
|
energytick.spark:SetHeight(C.unitframes.player.pheight + 15)
|
||||||
energytick.spark:SetWidth(C.unitframes.player.pheight + 5)
|
energytick.spark:SetWidth(C.unitframes.player.pheight + 5)
|
||||||
|
if not fsrOverlay then
|
||||||
|
energytick.fsrbar:SetHeight(tonumber(C.unitframes.player.fsrheight) or 4)
|
||||||
|
energytick.fsrbar:SetStatusBarColor(GetStringColor(C.appearance.castbar.fsrcolor))
|
||||||
|
end
|
||||||
hookUpdateConfig(pfUI.uf.player)
|
hookUpdateConfig(pfUI.uf.player)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -176,8 +176,8 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
rowMenu:RegisterEvent("GLOBAL_MOUSE_DOWN")
|
rowMenu:RegisterEvent("GLOBAL_MOUSE_DOWN")
|
||||||
rowMenu:SetScript("OnEvent", function()
|
rowMenu:SetScript("OnEvent", function()
|
||||||
if not this:IsShown() then return end
|
if not this:IsShown() then return end
|
||||||
if MouseIsOver(this) then return end
|
if MouseIsOverHitRect(this) then return end
|
||||||
if this.anchorBtn and MouseIsOver(this.anchorBtn) then return end
|
if this.anchorBtn and MouseIsOverHitRect(this.anchorBtn) then return end
|
||||||
this:Hide()
|
this:Hide()
|
||||||
end)
|
end)
|
||||||
tinsert(UISpecialFrames, "pfEqMgrRowMenu") -- Escape closes it
|
tinsert(UISpecialFrames, "pfEqMgrRowMenu") -- Escape closes it
|
||||||
@@ -301,12 +301,22 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
pfUI.equipmentmanager.Refresh()
|
pfUI.equipmentmanager.Refresh()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Drag a set onto an action bar. PickupEquipmentSet is newer than
|
||||||
|
-- the rest of C_EquipmentSet, so dragging stays inert on ClassicAPI
|
||||||
|
-- builds that don't ship it yet.
|
||||||
|
if C_EquipmentSet.PickupEquipmentSet then
|
||||||
|
row:RegisterForDrag("LeftButton")
|
||||||
|
row:SetScript("OnDragStart", function()
|
||||||
|
if row.setID then C_EquipmentSet.PickupEquipmentSet(row.setID) end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- Show the gear and tooltip while the cursor is over the row or its
|
-- Show the gear and tooltip while the cursor is over the row or its
|
||||||
-- gear child. The gear sits inside the row's rectangle, so a single
|
-- gear child. The gear sits inside the row's rectangle, so a single
|
||||||
-- MouseIsOver(row) check covers both. OnLeave on the row and the gear
|
-- MouseIsOverHitRect(row) check covers both. OnLeave on the row and the
|
||||||
-- catches every exit path, so no OnUpdate poll is needed.
|
-- gear catches every exit path, so no OnUpdate poll is needed.
|
||||||
local function HideRowHover()
|
local function HideRowHover()
|
||||||
if MouseIsOver(row) then return end
|
if MouseIsOverHitRect(row) then return end
|
||||||
GameTooltip:Hide()
|
GameTooltip:Hide()
|
||||||
row.gear:Hide()
|
row.gear:Hide()
|
||||||
end
|
end
|
||||||
@@ -586,6 +596,7 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
if i <= num then
|
if i <= num then
|
||||||
local location = ordered[i]
|
local location = ordered[i]
|
||||||
b.specialAction = nil; b.bag = nil; b.slot = nil; b.invSlot = nil
|
b.specialAction = nil; b.bag = nil; b.slot = nil; b.invSlot = nil
|
||||||
|
local quality
|
||||||
if location == PLACEINBAGS_LOCATION then
|
if location == PLACEINBAGS_LOCATION then
|
||||||
b.specialAction = "placeInBags"
|
b.specialAction = "placeInBags"
|
||||||
b.texture:SetTexture(pfUI.path.."\\img\\UI-GearManager-ItemIntoBag")
|
b.texture:SetTexture(pfUI.path.."\\img\\UI-GearManager-ItemIntoBag")
|
||||||
@@ -602,15 +613,23 @@ pfUI:RegisterModule("equipmentmanager", function()
|
|||||||
local loc = EquipmentManager_GetLocationData(location)
|
local loc = EquipmentManager_GetLocationData(location)
|
||||||
if loc.isBags then
|
if loc.isBags then
|
||||||
b.bag = loc.bag; b.slot = loc.slot
|
b.bag = loc.bag; b.slot = loc.slot
|
||||||
local tex, count = GetContainerItemInfo(loc.bag, loc.slot)
|
local tex, count, _, q = GetContainerItemInfo(loc.bag, loc.slot)
|
||||||
|
quality = q
|
||||||
b.texture:SetTexture(tex)
|
b.texture:SetTexture(tex)
|
||||||
if count and count > 1 then b.count:SetText(count) else b.count:SetText("") end
|
if count and count > 1 then b.count:SetText(count) else b.count:SetText("") end
|
||||||
else -- isPlayer (equipped in some other slot)
|
else -- isPlayer (equipped in some other slot)
|
||||||
b.invSlot = loc.slot
|
b.invSlot = loc.slot
|
||||||
b.texture:SetTexture(GetInventoryItemTexture("player", loc.slot))
|
b.texture:SetTexture(GetInventoryItemTexture("player", loc.slot))
|
||||||
b.count:SetText("")
|
b.count:SetText("")
|
||||||
|
quality = GetInventoryItemQuality("player", loc.slot)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Quality border, matching the character slots
|
||||||
|
if quality and quality > 0 then
|
||||||
|
b.backdrop:SetBackdropBorderColor(GetItemQualityColor(quality))
|
||||||
|
else
|
||||||
|
b.backdrop:SetBackdropBorderColor(pfUI.cache.er, pfUI.cache.eg, pfUI.cache.eb, pfUI.cache.ea)
|
||||||
|
end
|
||||||
local col = math.mod(i - 1, FLYOUT_COLS)
|
local col = math.mod(i - 1, FLYOUT_COLS)
|
||||||
local row = math.floor((i - 1) / FLYOUT_COLS)
|
local row = math.floor((i - 1) / FLYOUT_COLS)
|
||||||
b:ClearAllPoints()
|
b:ClearAllPoints()
|
||||||
|
|||||||
+23
-7
@@ -58,10 +58,11 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if MouseIsOver(this) and not this.over then
|
local over = MouseIsOverHitRect(this)
|
||||||
|
if over and not this.over then
|
||||||
this.tex:Show()
|
this.tex:Show()
|
||||||
this.over = true
|
this.over = true
|
||||||
elseif not MouseIsOver(this) and this.over then
|
elseif not over and this.over then
|
||||||
this.tex:Hide()
|
this.tex:Hide()
|
||||||
this.over = nil
|
this.over = nil
|
||||||
end
|
end
|
||||||
@@ -2072,9 +2073,6 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(nil, T["Combopoint Width"], C.unitframes, "combowidth")
|
CreateConfig(nil, T["Combopoint Width"], C.unitframes, "combowidth")
|
||||||
CreateConfig(nil, T["Combopoint Height"], C.unitframes, "comboheight")
|
CreateConfig(nil, T["Combopoint Height"], C.unitframes, "comboheight")
|
||||||
CreateConfig(nil, T["Show Resting"], C.unitframes.player, "showRest", "checkbox")
|
CreateConfig(nil, T["Show Resting"], C.unitframes.player, "showRest", "checkbox")
|
||||||
CreateConfig(nil, T["Enable Energy Ticks"], C.unitframes.player, "energy", "checkbox")
|
|
||||||
CreateConfig(nil, T["Enable Mana Ticks"], C.unitframes.player, "manatick", "checkbox")
|
|
||||||
CreateConfig(nil, T["Detect Enemy Buffs"], C.unitframes, "buffdetect", "checkbox", nil, nil, nil, nil)
|
|
||||||
CreateConfig(nil, T["Raid Mark Icon Style"], C.unitframes, "blizzard_raidicons", "dropdown", function() return {"1:Original Blizzard", "0:pfUI Design"} end)
|
CreateConfig(nil, T["Raid Mark Icon Style"], C.unitframes, "blizzard_raidicons", "dropdown", function() return {"1:Original Blizzard", "0:pfUI Design"} end)
|
||||||
|
|
||||||
CreateConfig(nil, T["Swing Timer"], nil, nil, "header")
|
CreateConfig(nil, T["Swing Timer"], nil, nil, "header")
|
||||||
@@ -2320,6 +2318,15 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(U[c], T["Right Text Y Offset"], C.unitframes[c], "txtpowerrightoffy")
|
CreateConfig(U[c], T["Right Text Y Offset"], C.unitframes[c], "txtpowerrightoffy")
|
||||||
CreateConfig(U[c], T["Power Bar Anchor"], C.unitframes[c], "panchor", "dropdown", pfUI.gui.dropdowns.uf_powerbar_position)
|
CreateConfig(U[c], T["Power Bar Anchor"], C.unitframes[c], "panchor", "dropdown", pfUI.gui.dropdowns.uf_powerbar_position)
|
||||||
|
|
||||||
|
if c == "player" then
|
||||||
|
CreateConfig(nil, T["Energy/Mana Ticks"], nil, nil, "header")
|
||||||
|
CreateConfig(nil, T["Enable Energy Ticks"], C.unitframes[c], "energy", "checkbox")
|
||||||
|
CreateConfig(nil, T["Enable Mana Ticks"], C.unitframes[c], "manatick", "checkbox")
|
||||||
|
CreateConfig(nil, T["Show Five Second Rule"], C.unitframes[c], "showfsr", "checkbox")
|
||||||
|
CreateConfig(nil, T["Five Second Rule Style"], C.unitframes[c], "fsrstyle", "dropdown", function() return {"0:Separate Bar", "1:Overlay"} end)
|
||||||
|
CreateConfig(nil, T["Five Second Rule Height"], C.unitframes[c], "fsrheight")
|
||||||
|
end
|
||||||
|
|
||||||
CreateConfig(U[c], T["Combat Text"], nil, nil, "header")
|
CreateConfig(U[c], T["Combat Text"], nil, nil, "header")
|
||||||
CreateConfig(U[c], T["Show Combat Text"], C.unitframes[c], "hitindicator", "checkbox")
|
CreateConfig(U[c], T["Show Combat Text"], C.unitframes[c], "hitindicator", "checkbox")
|
||||||
CreateConfig(U[c], T["Combat Text Font"], C.unitframes[c], "hitindicatorfont", "dropdown", pfUI.gui.dropdowns.fonts)
|
CreateConfig(U[c], T["Combat Text Font"], C.unitframes[c], "hitindicatorfont", "dropdown", pfUI.gui.dropdowns.fonts)
|
||||||
@@ -2340,12 +2347,18 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(U[c], T["Buff Size"], C.unitframes[c], "buffsize")
|
CreateConfig(U[c], T["Buff Size"], C.unitframes[c], "buffsize")
|
||||||
CreateConfig(U[c], T["Buff Limit"], C.unitframes[c], "bufflimit")
|
CreateConfig(U[c], T["Buff Limit"], C.unitframes[c], "bufflimit")
|
||||||
CreateConfig(U[c], T["Buffs Per Row"], C.unitframes[c], "buffperrow")
|
CreateConfig(U[c], T["Buffs Per Row"], C.unitframes[c], "buffperrow")
|
||||||
|
CreateConfig(U[c], T["Own Buff Size"], C.unitframes[c], "ownbuffsize")
|
||||||
|
CreateConfig(U[c], T["Buff X-Spacing"], C.unitframes[c], "buffspacingx")
|
||||||
|
CreateConfig(U[c], T["Buff Y-Spacing"], C.unitframes[c], "buffspacingy")
|
||||||
|
|
||||||
CreateConfig(U[c], T["Debuffs"], nil, nil, "header")
|
CreateConfig(U[c], T["Debuffs"], nil, nil, "header")
|
||||||
CreateConfig(U[c], T["Debuff Position"], C.unitframes[c], "debuffs", "dropdown", pfUI.gui.dropdowns.uf_buff_position)
|
CreateConfig(U[c], T["Debuff Position"], C.unitframes[c], "debuffs", "dropdown", pfUI.gui.dropdowns.uf_buff_position)
|
||||||
CreateConfig(U[c], T["Debuff Size"], C.unitframes[c], "debuffsize")
|
CreateConfig(U[c], T["Debuff Size"], C.unitframes[c], "debuffsize")
|
||||||
CreateConfig(U[c], T["Debuff Limit"], C.unitframes[c], "debufflimit")
|
CreateConfig(U[c], T["Debuff Limit"], C.unitframes[c], "debufflimit")
|
||||||
CreateConfig(U[c], T["Debuffs Per Row"], C.unitframes[c], "debuffperrow")
|
CreateConfig(U[c], T["Debuffs Per Row"], C.unitframes[c], "debuffperrow")
|
||||||
|
CreateConfig(U[c], T["Own Debuff Size"], C.unitframes[c], "owndebuffsize")
|
||||||
|
CreateConfig(U[c], T["Debuff X-Spacing"], C.unitframes[c], "debuffspacingx")
|
||||||
|
CreateConfig(U[c], T["Debuff Y-Spacing"], C.unitframes[c], "debuffspacingy")
|
||||||
|
|
||||||
if c ~= "player" then
|
if c ~= "player" then
|
||||||
end
|
end
|
||||||
@@ -2792,6 +2805,8 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(nil, T["Use Unit Fonts"], C.castbar, "use_unitfonts", "checkbox")
|
CreateConfig(nil, T["Use Unit Fonts"], C.castbar, "use_unitfonts", "checkbox")
|
||||||
CreateConfig(nil, T["Casting Color"], C.appearance.castbar, "castbarcolor", "color")
|
CreateConfig(nil, T["Casting Color"], C.appearance.castbar, "castbarcolor", "color")
|
||||||
CreateConfig(nil, T["Channeling Color"], C.appearance.castbar, "channelcolor", "color")
|
CreateConfig(nil, T["Channeling Color"], C.appearance.castbar, "channelcolor", "color")
|
||||||
|
CreateConfig(nil, T["Uninterruptible Color"], C.appearance.castbar, "shieldcolor", "color")
|
||||||
|
CreateConfig(nil, T["Five Second Rule Color"], C.appearance.castbar, "fsrcolor", "color")
|
||||||
CreateConfig(nil, T["Castbar Texture"], C.appearance.castbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture)
|
CreateConfig(nil, T["Castbar Texture"], C.appearance.castbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture)
|
||||||
CreateConfig(nil, T["Disable Blizzard Castbar"], C.castbar.player, "hide_blizz", "checkbox")
|
CreateConfig(nil, T["Disable Blizzard Castbar"], C.castbar.player, "hide_blizz", "checkbox")
|
||||||
end)
|
end)
|
||||||
@@ -2864,9 +2879,10 @@ pfUI:RegisterModule("gui", function ()
|
|||||||
CreateConfig(nil, T["Generate Playerlinks"], C.chat.text, "playerlinks", "checkbox")
|
CreateConfig(nil, T["Generate Playerlinks"], C.chat.text, "playerlinks", "checkbox")
|
||||||
CreateConfig(nil, T["Enable URL Detection"], C.chat.text, "detecturl", "checkbox")
|
CreateConfig(nil, T["Enable URL Detection"], C.chat.text, "detecturl", "checkbox")
|
||||||
CreateConfig(nil, T["Enable Class Colors"], C.chat.text, "classcolor", "checkbox")
|
CreateConfig(nil, T["Enable Class Colors"], C.chat.text, "classcolor", "checkbox")
|
||||||
CreateConfig(nil, T["Show Faction & Race Icons"] .. " " .. GetPlayerRaceIcons(), C.chat.text, "playericons", "checkbox")
|
local _, playerRace = UnitRace("player")
|
||||||
|
CreateConfig(nil, T["Show Faction Icons"] .. " " .. GetFactionIcon(playerRace), C.chat.text, "factionicons", "checkbox")
|
||||||
|
CreateConfig(nil, T["Show Race Icons"] .. " " .. GetRaceIcon(playerRace, UnitSex("player")), C.chat.text, "raceicons", "checkbox")
|
||||||
CreateConfig(nil, T["Enable Player Levels"], C.chat.text, "playerlevel", "checkbox")
|
CreateConfig(nil, T["Enable Player Levels"], C.chat.text, "playerlevel", "checkbox")
|
||||||
CreateConfig(nil, T["Who Search Unknown Classes (|cffffaaaaExperimental|r)"], C.chat.text, "whosearchunknown", "checkbox")
|
|
||||||
CreateConfig(nil, T["Colorize Unknown Classes"], C.chat.text, "tintunknown", "checkbox")
|
CreateConfig(nil, T["Colorize Unknown Classes"], C.chat.text, "tintunknown", "checkbox")
|
||||||
CreateConfig(nil, T["Unknown Class Color"], C.chat.text, "unknowncolor", "color")
|
CreateConfig(nil, T["Unknown Class Color"], C.chat.text, "unknowncolor", "color")
|
||||||
CreateConfig(nil, T["Left Chat Width"], C.chat.left, "width")
|
CreateConfig(nil, T["Left Chat Width"], C.chat.left, "width")
|
||||||
|
|||||||
+21
-5
@@ -105,6 +105,10 @@ pfUI:RegisterModule("hoverbind", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function BindingName(command)
|
||||||
|
return _G["BINDING_NAME_" .. command] or command
|
||||||
|
end
|
||||||
|
|
||||||
function pfUI.hoverbind:GetPrefix()
|
function pfUI.hoverbind:GetPrefix()
|
||||||
return string.format("%s%s%s",
|
return string.format("%s%s%s",
|
||||||
(IsAltKeyDown() and modifiers.ALT or ""),
|
(IsAltKeyDown() and modifiers.ALT or ""),
|
||||||
@@ -157,17 +161,29 @@ pfUI:RegisterModule("hoverbind", function ()
|
|||||||
if arg1 == "ESCAPE" and not binding then pfUI.hoverbind:Hide() return end
|
if arg1 == "ESCAPE" and not binding then pfUI.hoverbind:Hide() return end
|
||||||
if binding then
|
if binding then
|
||||||
if arg1 == "ESCAPE" then
|
if arg1 == "ESCAPE" then
|
||||||
-- Remove existing binding
|
-- Remove all existing bindings
|
||||||
local key = (GetBindingKey(binding))
|
local keys = { GetBindingKey(binding) }
|
||||||
if (key) then
|
for _, key in ipairs(keys) do
|
||||||
SetBinding(key)
|
SetBinding(key)
|
||||||
|
end
|
||||||
|
if keys[1] then
|
||||||
SaveBindings(GetCurrentBindingSet())
|
SaveBindings(GetCurrentBindingSet())
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Create new binding
|
-- Create new binding
|
||||||
local key = map and map[arg1] or arg1
|
local key = prefix .. (map and map[arg1] or arg1)
|
||||||
if (SetBinding(prefix..key, binding)) then
|
local previous = GetBindingAction(key)
|
||||||
|
if (SetBinding(key, binding)) then
|
||||||
SaveBindings(GetCurrentBindingSet())
|
SaveBindings(GetCurrentBindingSet())
|
||||||
|
|
||||||
|
if previous and previous ~= "" and previous ~= binding then
|
||||||
|
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffcc" .. key .. "|r " .. T["was unbound from"] .. " " .. BindingName(previous))
|
||||||
|
end
|
||||||
|
|
||||||
|
local active = GetBindingAction(key, true)
|
||||||
|
if active ~= binding then
|
||||||
|
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffcc" .. key .. "|r " .. T["is currently overridden by"] .. " " .. BindingName(active))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+38
-58
@@ -1,25 +1,13 @@
|
|||||||
-- Innervate Callout Module
|
-- Innervate Callout Module
|
||||||
-- Announces Innervate casts via raid/party/battleground chat
|
-- Announces Innervate casts via raid/party/battleground chat
|
||||||
-- Registers AURA_CAST events directly - zero polling, pure event-driven
|
-- Listens to COMBAT_LOG_EVENT_UNFILTERED - zero polling, pure event-driven
|
||||||
|
|
||||||
pfUI:RegisterModule("innervatecall", function ()
|
pfUI:RegisterModule("innervatecall", function ()
|
||||||
-- Requires Nampower for AURA_CAST events
|
|
||||||
if not GetNampowerVersion then return end
|
|
||||||
|
|
||||||
-- Only load for druids
|
-- Only load for druids
|
||||||
if UnitClassBase("player") ~= "DRUID" then return end
|
if UnitClassBase("player") ~= "DRUID" then return end
|
||||||
|
|
||||||
local INNERVATE_SPELLID = 29166
|
local INNERVATE_SPELLID = 29166
|
||||||
|
local GCD_DURATION = 1.5
|
||||||
-- GUID → name resolution for the target. UnitTokenFromGUID walks the
|
|
||||||
-- engine's known unit tokens (player, party, raid, target, ...) and
|
|
||||||
-- returns the first one currently bound to the GUID, so we don't have
|
|
||||||
-- to manually iterate party/raid here.
|
|
||||||
local function ResolveTargetName(targetGuid)
|
|
||||||
if not targetGuid then return nil end
|
|
||||||
local token = UnitTokenFromGUID(targetGuid)
|
|
||||||
return token and UnitName(token) or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Determine chat channel based on group context
|
-- Determine chat channel based on group context
|
||||||
local function GetAnnounceChannel()
|
local function GetAnnounceChannel()
|
||||||
@@ -39,57 +27,49 @@ pfUI:RegisterModule("innervatecall", function ()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Event frame - registers AURA_CAST directly (bypasses libdebuff hooks
|
-- Set on our cast, cleared once the "ready" timer is scheduled
|
||||||
-- which are gated behind ownDebuffs/pendingCasts checks meant for debuffs)
|
local pending = false
|
||||||
local frame = CreateFrame("Frame")
|
|
||||||
-- AURA_CAST_ON_SELF fires when a buff lands ON the player
|
|
||||||
-- AURA_CAST_ON_OTHER fires when a buff lands on someone else
|
|
||||||
-- Both needed: self-innervate = ON_SELF, innervate on others = ON_OTHER
|
|
||||||
-- casterGuid check prevents announcing other druids' innervates
|
|
||||||
frame:RegisterEvent("AURA_CAST_ON_SELF")
|
|
||||||
frame:RegisterEvent("AURA_CAST_ON_OTHER")
|
|
||||||
frame:RegisterEvent("PLAYER_LOGOUT")
|
|
||||||
frame:SetScript("OnEvent", function()
|
|
||||||
if event == "PLAYER_LOGOUT" then
|
|
||||||
this:UnregisterAllEvents()
|
|
||||||
this:SetScript("OnEvent", nil)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- AURA_CAST args: arg1=spellId, arg2=casterGuid, arg3=targetGuid
|
-- Schedule the "ready" announcement once Innervate's own cooldown is in
|
||||||
local spellId = arg1
|
-- the spell history. Until then GetSpellCooldown reports only the GCD,
|
||||||
local casterGuid = arg2
|
-- which has no isOnGCD flag here, so tell them apart by duration.
|
||||||
local targetGuid = arg3
|
local function ScheduleReady()
|
||||||
|
|
||||||
if spellId ~= INNERVATE_SPELLID then return end
|
|
||||||
|
|
||||||
-- Only announce our own casts
|
|
||||||
if not IsPlayerGuid(casterGuid) then return end
|
|
||||||
|
|
||||||
-- Resolve target name from GUID
|
|
||||||
local targetName = ResolveTargetName(targetGuid) or "Unknown"
|
|
||||||
|
|
||||||
-- Determine channel
|
|
||||||
local channel = GetAnnounceChannel()
|
|
||||||
if not channel then return end -- solo, no announcement
|
|
||||||
|
|
||||||
SendChatMessage(">> Innervate casted on " .. targetName .. " <<", channel)
|
|
||||||
|
|
||||||
-- Schedule "ready" announcement when the cooldown expires. Read the
|
|
||||||
-- precise remaining time from C_Spell.GetSpellCooldown (startTime and
|
|
||||||
-- duration are seconds from the GetTime epoch); fall back to 360s.
|
|
||||||
local cdRemaining = 360
|
|
||||||
local cd = C_Spell.GetSpellCooldown(INNERVATE_SPELLID)
|
local cd = C_Spell.GetSpellCooldown(INNERVATE_SPELLID)
|
||||||
if cd and cd.duration and cd.duration > 0 then
|
if not cd or cd.duration <= GCD_DURATION then return end
|
||||||
local remaining = cd.startTime + cd.duration - GetTime()
|
|
||||||
if remaining > 0 then cdRemaining = remaining end
|
|
||||||
end
|
|
||||||
|
|
||||||
C_Timer.After(cdRemaining, function()
|
pending = false
|
||||||
|
C_Timer.After(cd.startTime + cd.duration - GetTime(), function()
|
||||||
local ch = GetAnnounceChannel()
|
local ch = GetAnnounceChannel()
|
||||||
if ch then
|
if ch then
|
||||||
SendChatMessage(">> Innervate is ready <<", ch)
|
SendChatMessage(">> Innervate is ready <<", ch)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local frame = CreateFrame("Frame")
|
||||||
|
frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
|
||||||
|
frame:RegisterEvent("SPELL_UPDATE_COOLDOWN")
|
||||||
|
frame:SetScript("OnEvent", function()
|
||||||
|
if event == "SPELL_UPDATE_COOLDOWN" then
|
||||||
|
if pending then ScheduleReady() end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Innervate is instant, so it logs SPELL_CAST_SUCCESS with its target
|
||||||
|
-- arg2=subevent, arg4=sourceGUID, arg9=destName, arg12=spellId
|
||||||
|
if arg2 ~= "SPELL_CAST_SUCCESS" or arg12 ~= INNERVATE_SPELLID then return end
|
||||||
|
|
||||||
|
-- Only announce our own casts
|
||||||
|
if not IsPlayerGuid(arg4) then return end
|
||||||
|
local destName = arg9
|
||||||
|
|
||||||
|
-- Determine channel
|
||||||
|
local channel = GetAnnounceChannel()
|
||||||
|
if not channel then return end -- solo, no announcement
|
||||||
|
|
||||||
|
SendChatMessage(">> Innervate cast on " .. (destName or "Unknown") .. " <<", channel)
|
||||||
|
|
||||||
|
pending = true
|
||||||
|
ScheduleReady()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
+1
-1
@@ -180,7 +180,7 @@ pfUI:RegisterModule("map", function ()
|
|||||||
my = (( my + height / 2 ) - ( y / scale )) / height * 100
|
my = (( my + height / 2 ) - ( y / scale )) / height * 100
|
||||||
end
|
end
|
||||||
|
|
||||||
if mx and my and MouseIsOver(WorldMapButton) then
|
if mx and my and WorldMapButton:IsMouseOver() then
|
||||||
WorldMapButton.coords.text:SetFormattedText('%.1f / %.1f', mx, my)
|
WorldMapButton.coords.text:SetFormattedText('%.1f / %.1f', mx, my)
|
||||||
else
|
else
|
||||||
WorldMapButton.coords.text:SetText("")
|
WorldMapButton.coords.text:SetText("")
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ pfUI:RegisterModule("mapcolors", function ()
|
|||||||
local tooltipText = ""
|
local tooltipText = ""
|
||||||
if unit_button_name == 'WorldMap' then
|
if unit_button_name == 'WorldMap' then
|
||||||
-- check player
|
-- check player
|
||||||
if MouseIsOver(WorldMapPlayer) then
|
if WorldMapPlayer:IsMouseOver() then
|
||||||
ColorizeName(WorldMapPlayer)
|
ColorizeName(WorldMapPlayer)
|
||||||
tooltipText = WorldMapPlayer.name
|
tooltipText = WorldMapPlayer.name
|
||||||
end
|
end
|
||||||
@@ -104,7 +104,7 @@ pfUI:RegisterModule("mapcolors", function ()
|
|||||||
-- check party
|
-- check party
|
||||||
for i=1, MAX_PARTY_MEMBERS do
|
for i=1, MAX_PARTY_MEMBERS do
|
||||||
local frame = _G[unit_button_name.."Party"..i]
|
local frame = _G[unit_button_name.."Party"..i]
|
||||||
if frame:IsVisible() and MouseIsOver(frame) then
|
if frame:IsVisible() and frame:IsMouseOver() then
|
||||||
ColorizeName(frame)
|
ColorizeName(frame)
|
||||||
tooltipText = tooltipText.."\n"..frame.name
|
tooltipText = tooltipText.."\n"..frame.name
|
||||||
end
|
end
|
||||||
@@ -113,7 +113,7 @@ pfUI:RegisterModule("mapcolors", function ()
|
|||||||
--check Raid
|
--check Raid
|
||||||
for i=1, MAX_RAID_MEMBERS do
|
for i=1, MAX_RAID_MEMBERS do
|
||||||
local frame = _G[unit_button_name.."Raid"..i]
|
local frame = _G[unit_button_name.."Raid"..i]
|
||||||
if frame:IsVisible() and MouseIsOver(frame) then
|
if frame:IsVisible() and frame:IsMouseOver() then
|
||||||
ColorizeName(frame)
|
ColorizeName(frame)
|
||||||
tooltipText = tooltipText.."\n"..frame.name
|
tooltipText = tooltipText.."\n"..frame.name
|
||||||
end
|
end
|
||||||
|
|||||||
+17
-15
@@ -109,24 +109,26 @@ pfUI:RegisterModule("minimap", function ()
|
|||||||
this.highlight.tex:SetPoint("BOTTOMRIGHT", MiniMapMailIcon, "BOTTOMRIGHT", 2, -2)
|
this.highlight.tex:SetPoint("BOTTOMRIGHT", MiniMapMailIcon, "BOTTOMRIGHT", 2, -2)
|
||||||
this.highlight.tex:SetVertexColor(1,.5,.5)
|
this.highlight.tex:SetVertexColor(1,.5,.5)
|
||||||
|
|
||||||
this.highlight:SetScript("OnUpdate", function()
|
-- Blink ten times between .9 and .1, then hide
|
||||||
if not this.count then this.count = 0 end
|
local highlight = this.highlight
|
||||||
if not this.modifier then this.modifier = 1 end
|
highlight:SetAlpha(.9)
|
||||||
if this.count >= 10 then this:Hide() end
|
highlight.blink = highlight:CreateAnimationGroup()
|
||||||
|
for i = 1, 10 do
|
||||||
this:SetAlpha(this:GetAlpha() + this.modifier)
|
local down = highlight.blink:CreateAnimation("Alpha")
|
||||||
|
down:SetChange(-.8)
|
||||||
if this:GetAlpha() <= 0.1 then
|
down:SetDuration(.3)
|
||||||
this.modifier = 0.05
|
down:SetOrder(i * 2 - 1)
|
||||||
this.count = this.count + 1
|
local up = highlight.blink:CreateAnimation("Alpha")
|
||||||
elseif this:GetAlpha() >= 0.9 then
|
up:SetChange(.8)
|
||||||
this.modifier = -0.05
|
up:SetDuration(.3)
|
||||||
end
|
up:SetOrder(i * 2)
|
||||||
end)
|
end
|
||||||
|
highlight.blink:SetScript("OnFinished", function() highlight:Hide() end)
|
||||||
end
|
end
|
||||||
|
|
||||||
this.highlight.count = 0
|
|
||||||
this.highlight:Show()
|
this.highlight:Show()
|
||||||
|
this.highlight.blink:Stop()
|
||||||
|
this.highlight.blink:Play()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Create coordinates text frame with location configurable
|
-- Create coordinates text frame with location configurable
|
||||||
|
|||||||
+40
-35
@@ -77,10 +77,10 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
-- vs channel itself. Never called per frame.
|
-- vs channel itself. Never called per frame.
|
||||||
local function PollCastInfo(unit)
|
local function PollCastInfo(unit)
|
||||||
if not unit then return nil end
|
if not unit then return nil end
|
||||||
local name, _, texture, startMs, endMs, _, _, _, spellID = C_Spell.UnitCastingInfo(unit)
|
local name, _, texture, startMs, endMs, _, _, noInterrupt, spellID = C_Spell.UnitCastingInfo(unit)
|
||||||
local isChannel
|
local isChannel
|
||||||
if not name then
|
if not name then
|
||||||
name, _, texture, startMs, endMs, _, _, spellID = C_Spell.UnitChannelInfo(unit)
|
name, _, texture, startMs, endMs, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(unit)
|
||||||
isChannel = true
|
isChannel = true
|
||||||
end
|
end
|
||||||
if not name or not startMs or not endMs then return nil end
|
if not name or not startMs or not endMs then return nil end
|
||||||
@@ -92,6 +92,7 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
endTime = endMs / 1000,
|
endTime = endMs / 1000,
|
||||||
duration = (endMs - startMs) / 1000,
|
duration = (endMs - startMs) / 1000,
|
||||||
isChannel = isChannel,
|
isChannel = isChannel,
|
||||||
|
noInterrupt = noInterrupt,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -279,10 +280,6 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
return color
|
return color
|
||||||
end
|
end
|
||||||
|
|
||||||
local function DoNothing()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local function DisableObject(object)
|
local function DisableObject(object)
|
||||||
if not object then return end
|
if not object then return end
|
||||||
if not object.GetObjectType then return end
|
if not object.GetObjectType then return end
|
||||||
@@ -380,16 +377,23 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function GetUnitType(red, green, blue)
|
-- UnitSelectionType: 0 hostile, 1 unfriendly, 2 neutral, 3 friendly (or a
|
||||||
if red > .9 and green < .2 and blue < .2 then
|
-- PvP-flagged player), 4 unflagged player. Type 3 is ambiguous, so callers
|
||||||
return "ENEMY_NPC"
|
-- still promote *_NPC to *_PLAYER from their own player check.
|
||||||
elseif red > .9 and green > .9 and blue < .2 then
|
local selectionTypes = {
|
||||||
return "NEUTRAL_NPC"
|
[0] = "ENEMY_NPC",
|
||||||
elseif red < .2 and green < .2 and blue > 0.9 then
|
[1] = "ENEMY_NPC",
|
||||||
return "FRIENDLY_PLAYER"
|
[2] = "NEUTRAL_NPC",
|
||||||
elseif red < .2 and green > .9 and blue < .2 then
|
[3] = "FRIENDLY_NPC",
|
||||||
return "FRIENDLY_NPC"
|
[4] = "FRIENDLY_PLAYER",
|
||||||
end
|
}
|
||||||
|
|
||||||
|
local function GetUnitType(plate)
|
||||||
|
-- an unresolved token reads as the player's own type (4), so never ask
|
||||||
|
-- without a GUID
|
||||||
|
local guid = plate.cachedGuid
|
||||||
|
if not guid or guid == "" then return "ENEMY_NPC" end
|
||||||
|
return selectionTypes[UnitSelectionType(guid)]
|
||||||
end
|
end
|
||||||
|
|
||||||
local filter, list, cache
|
local filter, list, cache
|
||||||
@@ -436,22 +440,8 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
plate.debuffs[index].stacks:SetJustifyV("BOTTOM")
|
plate.debuffs[index].stacks:SetJustifyV("BOTTOM")
|
||||||
plate.debuffs[index].stacks:SetTextColor(1,1,0)
|
plate.debuffs[index].stacks:SetTextColor(1,1,0)
|
||||||
|
|
||||||
-- PERF: Use lightweight fake cooldown frame when animation disabled
|
plate.debuffs[index].cd = CreateFrame("Cooldown", plate.platename.."Debuff"..index.."Cooldown", plate.debuffs[index], "CooldownFrameTemplate")
|
||||||
-- The Model-based CooldownFrameTemplate causes major lag with many nameplates
|
plate.debuffs[index].cd:SetFrameLevel(6)
|
||||||
if cfg.debuffanim ~= 1 then
|
|
||||||
plate.debuffs[index].cd = CreateFrame("Frame", plate.platename.."Debuff"..index.."Cooldown", plate.debuffs[index])
|
|
||||||
plate.debuffs[index].cd:SetAllPoints(plate.debuffs[index])
|
|
||||||
plate.debuffs[index].cd:SetFrameLevel(6)
|
|
||||||
plate.debuffs[index].cd:SetScript("OnUpdate", CooldownFrame_OnUpdateModel)
|
|
||||||
plate.debuffs[index].cd.AdvanceTime = DoNothing
|
|
||||||
plate.debuffs[index].cd.SetSequence = DoNothing
|
|
||||||
plate.debuffs[index].cd.SetSequenceTime = DoNothing
|
|
||||||
else
|
|
||||||
-- Use CooldownFrameTemplate for animation
|
|
||||||
plate.debuffs[index].cd = CreateFrame("Model", plate.platename.."Debuff"..index.."Cooldown", plate.debuffs[index], "CooldownFrameTemplate")
|
|
||||||
plate.debuffs[index].cd:SetAllPoints(plate.debuffs[index])
|
|
||||||
plate.debuffs[index].cd:SetFrameLevel(6)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set initial config flags (will be cached per-cooldown later)
|
-- Set initial config flags (will be cached per-cooldown later)
|
||||||
plate.debuffs[index].cd.pfCooldownStyleAnimation = cfg.debuffanim
|
plate.debuffs[index].cd.pfCooldownStyleAnimation = cfg.debuffanim
|
||||||
@@ -518,6 +508,10 @@ nameplates:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
|
|||||||
-- plate's own frame, against its own token -- see OnCreate and
|
-- plate's own frame, against its own token -- see OnCreate and
|
||||||
-- NAME_PLATE_UNIT_ADDED.
|
-- NAME_PLATE_UNIT_ADDED.
|
||||||
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||||
|
-- The interruptible flips only fire for target and focus, not nameplate
|
||||||
|
-- tokens. castState is keyed by GUID, so they still reach those units' plates.
|
||||||
|
nameplates:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTIBLE", "target", "focus")
|
||||||
|
nameplates:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "target", "focus")
|
||||||
|
|
||||||
nameplates:SetScript("OnEvent", function()
|
nameplates:SetScript("OnEvent", function()
|
||||||
-- Stop event handling during logout to prevent crash 132
|
-- Stop event handling during logout to prevent crash 132
|
||||||
@@ -679,6 +673,17 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
|||||||
-- Also propagate to all plates for alpha/strata updates
|
-- Also propagate to all plates for alpha/strata updates
|
||||||
this.eventcache = true
|
this.eventcache = true
|
||||||
|
|
||||||
|
elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" or event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
|
||||||
|
local guid = UnitGUID(arg1)
|
||||||
|
local info = guid and castState[guid]
|
||||||
|
local plate = info and plateByGuid[guid]
|
||||||
|
if plate and plate.castbar then
|
||||||
|
info.noInterrupt = event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE"
|
||||||
|
-- UpdateCastbar only restyles on a new cast; force it
|
||||||
|
plate.castbar.lastEndTime = nil
|
||||||
|
plate.castUpdate = true
|
||||||
|
end
|
||||||
|
|
||||||
elseif event == "PLAYER_COMBO_POINTS" or event == "UNIT_COMBO_POINTS" then
|
elseif event == "PLAYER_COMBO_POINTS" or event == "UNIT_COMBO_POINTS" then
|
||||||
-- Only flag the target's plate for combo point update
|
-- Only flag the target's plate for combo point update
|
||||||
local plate = C_NamePlate.GetNamePlateForUnit("target")
|
local plate = C_NamePlate.GetNamePlateForUnit("target")
|
||||||
@@ -959,6 +964,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
|||||||
nameplate.name:SetJustifyH(nameTextPos)
|
nameplate.name:SetJustifyH(nameTextPos)
|
||||||
|
|
||||||
nameplate.health:SetOrientation(orientation)
|
nameplate.health:SetOrientation(orientation)
|
||||||
|
nameplate.health:SetRotatesTexture(orientation == "VERTICAL")
|
||||||
-- Bar anchors to the plate directly so the name's JustifyH (configurable
|
-- Bar anchors to the plate directly so the name's JustifyH (configurable
|
||||||
-- below) can shift left/right without dragging the bar with it.
|
-- below) can shift left/right without dragging the bar with it.
|
||||||
nameplate.health:ClearAllPoints()
|
nameplate.health:ClearAllPoints()
|
||||||
@@ -1081,8 +1087,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
|||||||
levelFromDB = true
|
levelFromDB = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local red, green, blue = plate.original.healthbar:GetStatusBarColor()
|
local unittype = GetUnitType(plate)
|
||||||
local unittype = GetUnitType(red, green, blue) or "ENEMY_NPC"
|
|
||||||
local font_size = C.nameplates.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size
|
local font_size = C.nameplates.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size
|
||||||
|
|
||||||
-- ignore players with npc names if plate level is lower than player level
|
-- ignore players with npc names if plate level is lower than player level
|
||||||
@@ -1751,7 +1756,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
|||||||
-- Relative 0..duration range to avoid float precision loss with large
|
-- Relative 0..duration range to avoid float precision loss with large
|
||||||
-- absolute timestamps.
|
-- absolute timestamps.
|
||||||
nameplate.castbar:SetMinMaxValues(0, duration)
|
nameplate.castbar:SetMinMaxValues(0, duration)
|
||||||
nameplate.castbar:SetStatusBarColor(GetStringColor(C.appearance.castbar[(isChannel and "channelcolor" or "castbarcolor")]))
|
SetCastbarShield(nameplate.castbar, nameplate.castbar.icon, castInfo.noInterrupt, isChannel)
|
||||||
if castInfo.icon then
|
if castInfo.icon then
|
||||||
nameplate.castbar.icon.tex:SetTexture(castInfo.icon)
|
nameplate.castbar.icon.tex:SetTexture(castInfo.icon)
|
||||||
nameplate.castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
|
nameplate.castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
|
||||||
|
|||||||
+2
-1
@@ -122,6 +122,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
local gcmb = gckb and gckb > 0 and round((gckb or 0)/1000, 2) .. " MB" or UNAVAILABLE
|
local gcmb = gckb and gckb > 0 and round((gckb or 0)/1000, 2) .. " MB" or UNAVAILABLE
|
||||||
|
|
||||||
local nin, nout, nping = GetNetStats()
|
local nin, nout, nping = GetNetStats()
|
||||||
|
local screenWidth, screenHeight = GetPhysicalScreenSize()
|
||||||
|
|
||||||
GameTooltip:AddDoubleLine(T["Active Addons"], "|cffffffff" .. active .. "|cff555555 / |cffffffff" .. GetNumAddOns())
|
GameTooltip:AddDoubleLine(T["Active Addons"], "|cffffffff" .. active .. "|cff555555 / |cffffffff" .. GetNumAddOns())
|
||||||
GameTooltip:AddLine(" ")
|
GameTooltip:AddLine(" ")
|
||||||
@@ -133,7 +134,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
GameTooltip:AddDoubleLine(T["Network Latency"], "|cffffffff" .. nping .. "ms")
|
GameTooltip:AddDoubleLine(T["Network Latency"], "|cffffffff" .. nping .. "ms")
|
||||||
GameTooltip:AddLine(" ")
|
GameTooltip:AddLine(" ")
|
||||||
GameTooltip:AddDoubleLine(T["Graphic Renderer"], "|cffffffff" .. GetCVar("gxApi"))
|
GameTooltip:AddDoubleLine(T["Graphic Renderer"], "|cffffffff" .. GetCVar("gxApi"))
|
||||||
GameTooltip:AddDoubleLine(T["Screen Resolution"], "|cffffffff" .. GetCVar("gxResolution"))
|
GameTooltip:AddDoubleLine(T["Screen Resolution"], "|cffffffff" .. screenWidth .. 'x' .. screenHeight)
|
||||||
GameTooltip:AddDoubleLine(T["UI-Scale"], "|cffffffff" .. round(UIParent:GetEffectiveScale(),2))
|
GameTooltip:AddDoubleLine(T["UI-Scale"], "|cffffffff" .. round(UIParent:GetEffectiveScale(),2))
|
||||||
GameTooltip:Show()
|
GameTooltip:Show()
|
||||||
end
|
end
|
||||||
|
|||||||
+1
-36
@@ -1,39 +1,4 @@
|
|||||||
pfUI:RegisterModule("skin", function ()
|
pfUI:RegisterModule("skin", function ()
|
||||||
-- align UIParent panels
|
|
||||||
pfUI.panelalign = CreateFrame("Frame", "pfUIParentPanelAlign", UIParent)
|
|
||||||
pfUI.panelalign:SetScript("OnUpdate", function()
|
|
||||||
-- throttle to 5 updates per second instead of every frame
|
|
||||||
if (this.tick or 0.2) > GetTime() then return else this.tick = GetTime() + 0.2 end
|
|
||||||
|
|
||||||
local left = UIParent.left
|
|
||||||
local center = UIParent.center
|
|
||||||
local rbpos, ropos
|
|
||||||
|
|
||||||
-- detect outer frame backdrops
|
|
||||||
if left and not left.rightObj then
|
|
||||||
left.rightObj = left.backdrop or left
|
|
||||||
for _, frame in pairs({left:GetChildren()}) do
|
|
||||||
rbpos = frame.backdrop and frame.backdrop.GetRight and frame.backdrop:GetRight()
|
|
||||||
ropos = left.rightObj and left.rightObj.GetRight and left.rightObj:GetRight()
|
|
||||||
if rbpos and ropos and rbpos > ropos then
|
|
||||||
left.rightObj = frame.backdrop
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- reset anchors
|
|
||||||
if not left or not left:IsShown() or not center or not center:IsShown() then
|
|
||||||
UIParent.pfLeftAligned = nil
|
|
||||||
return
|
|
||||||
elseif center and center:IsShown() and left and left:IsShown() then
|
|
||||||
local width = left.rightObj:GetRight()
|
|
||||||
if width and width ~= UIParent.pfLeftAligned then
|
|
||||||
center:SetPoint("TOPLEFT", "UIParent", "TOPLEFT", width + 10, -104)
|
|
||||||
UIParent.pfLeftAligned = width
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- durability frame
|
-- durability frame
|
||||||
pfUI.durability = CreateFrame("Frame", "pfDurability", UIParent)
|
pfUI.durability = CreateFrame("Frame", "pfDurability", UIParent)
|
||||||
if pfUI.minimap then
|
if pfUI.minimap then
|
||||||
@@ -79,4 +44,4 @@ pfUI:RegisterModule("skin", function ()
|
|||||||
else
|
else
|
||||||
UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE")
|
UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
+59
-266
@@ -1,10 +1,6 @@
|
|||||||
pfUI:RegisterModule("swingtimer", function ()
|
pfUI:RegisterModule("swingtimer", function ()
|
||||||
local rawborder, border = GetBorderSize()
|
local rawborder, border = GetBorderSize()
|
||||||
|
|
||||||
-- HitInfo flags (EVENTS.md)
|
|
||||||
local HITINFO_LEFTSWING = 4 -- 4: Off-hand attack
|
|
||||||
local HITINFO_NOACTION = 65536 -- 65536: server did not advance the swing clock
|
|
||||||
|
|
||||||
-- SPELL_QUEUE_EVENT codes (EVENTS.md)
|
-- SPELL_QUEUE_EVENT codes (EVENTS.md)
|
||||||
local ON_SWING_QUEUED = 0
|
local ON_SWING_QUEUED = 0
|
||||||
local ON_SWING_QUEUE_POPPED = 1
|
local ON_SWING_QUEUE_POPPED = 1
|
||||||
@@ -19,8 +15,6 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
lastMhMarkerX = -1, lastOhMarkerX = -1, lastRaMarkerX = -1,
|
lastMhMarkerX = -1, lastOhMarkerX = -1, lastRaMarkerX = -1,
|
||||||
autoAttackActive = false,
|
autoAttackActive = false,
|
||||||
inCombat = false,
|
inCombat = false,
|
||||||
pendingCastSpellId = nil,
|
|
||||||
mhFrozenAt = nil,
|
|
||||||
hsQueued = false, cleaveQueued = false, maulQueued = false,
|
hsQueued = false, cleaveQueued = false, maulQueued = false,
|
||||||
hsSeenCurrent = false, cleaveSeenCurrent = false, maulSeenCurrent = false,
|
hsSeenCurrent = false, cleaveSeenCurrent = false, maulSeenCurrent = false,
|
||||||
isWarrior = false,
|
isWarrior = false,
|
||||||
@@ -31,13 +25,6 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
onSwingCache = {},
|
onSwingCache = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Wand "Shoot" runs on the ranged bar but is INDEPENDENT of the melee
|
|
||||||
-- swing clock — casters melee-weave between mainhand swings and wand
|
|
||||||
-- fires, both timers tick concurrently. Every other ranged-auto-attack
|
|
||||||
-- (Hunter Auto Shot, any future auto-repeat ranged spell) replaces MH.
|
|
||||||
local WAND_SHOOT_SPELLID = 5019
|
|
||||||
local THROW_SPELLID = 2764 -- one-shot ranged, not auto-repeat
|
|
||||||
|
|
||||||
-- On-next-swing spells replace the next auto-attack swing.
|
-- On-next-swing spells replace the next auto-attack swing.
|
||||||
-- Covers Raptor Strike, Maul, Mongoose Bite, Holy Strike, etc. automatically.
|
-- Covers Raptor Strike, Maul, Mongoose Bite, Holy Strike, etc. automatically.
|
||||||
local function IsOnSwingSpell(spellId)
|
local function IsOnSwingSpell(spellId)
|
||||||
@@ -203,36 +190,19 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
CreateBackdropShadow(pfUI.swingtimer.offhand)
|
CreateBackdropShadow(pfUI.swingtimer.offhand)
|
||||||
|
|
||||||
-- Ranged bar
|
-- Ranged bar
|
||||||
pfUI.swingtimer.ranged = CreateFrame("Frame", "pfSwingTimerRanged", UIParent)
|
-- Hunters fill from the center: the bar drains toward the middle during
|
||||||
|
-- the reload, then the auto shot deadzone grows back out in the warn color.
|
||||||
|
pfUI.swingtimer.ranged = CreateFrame("StatusBar", "pfSwingTimerRanged", UIParent)
|
||||||
pfUI.swingtimer.ranged:SetPoint("BOTTOM", UIParent, "CENTER", -189, 83)
|
pfUI.swingtimer.ranged:SetPoint("BOTTOM", UIParent, "CENTER", -189, 83)
|
||||||
pfUI.swingtimer.ranged:SetWidth(sw_width)
|
pfUI.swingtimer.ranged:SetWidth(sw_width)
|
||||||
pfUI.swingtimer.ranged:SetHeight(sw_height)
|
pfUI.swingtimer.ranged:SetHeight(sw_height)
|
||||||
|
pfUI.swingtimer.ranged:SetMinMaxValues(0, 1)
|
||||||
|
pfUI.swingtimer.ranged:SetValue(0)
|
||||||
|
pfUI.swingtimer.ranged:SetStatusBarTexture(sw_texture)
|
||||||
|
pfUI.swingtimer.ranged:SetStatusBarColor(raR, raG, raB, raA)
|
||||||
|
pfUI.swingtimer.ranged:SetFillStyle(isHunter and "CENTER" or "STANDARD")
|
||||||
pfUI.swingtimer.ranged:Hide()
|
pfUI.swingtimer.ranged:Hide()
|
||||||
|
|
||||||
pfUI.swingtimer.ranged.left = pfUI.swingtimer.ranged:CreateTexture(nil, "ARTWORK")
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexture(sw_texture)
|
|
||||||
pfUI.swingtimer.ranged.left:SetPoint("RIGHT", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
|
||||||
pfUI.swingtimer.ranged.left:SetHeight(sw_height)
|
|
||||||
pfUI.swingtimer.ranged.left:SetWidth(sw_width / 2)
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexCoord(0, 0.5, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.left:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
|
|
||||||
pfUI.swingtimer.ranged.right = pfUI.swingtimer.ranged:CreateTexture(nil, "ARTWORK")
|
|
||||||
pfUI.swingtimer.ranged.right:SetTexture(sw_texture)
|
|
||||||
pfUI.swingtimer.ranged.right:SetPoint("LEFT", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
|
||||||
pfUI.swingtimer.ranged.right:SetHeight(sw_height)
|
|
||||||
pfUI.swingtimer.ranged.right:SetWidth(sw_width / 2)
|
|
||||||
pfUI.swingtimer.ranged.right:SetTexCoord(0.5, 1, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.right:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
|
|
||||||
pfUI.swingtimer.ranged.warn = pfUI.swingtimer.ranged:CreateTexture(nil, "ARTWORK")
|
|
||||||
pfUI.swingtimer.ranged.warn:SetTexture(sw_texture)
|
|
||||||
pfUI.swingtimer.ranged.warn:SetPoint("CENTER", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
|
||||||
pfUI.swingtimer.ranged.warn:SetHeight(sw_height)
|
|
||||||
pfUI.swingtimer.ranged.warn:SetWidth(1)
|
|
||||||
pfUI.swingtimer.ranged.warn:SetVertexColor(rwR, rwG, rwB, rwA)
|
|
||||||
pfUI.swingtimer.ranged.warn:Hide()
|
|
||||||
|
|
||||||
pfUI.swingtimer.ranged.text = pfUI.swingtimer.ranged:CreateFontString("Status", "DIALOG", "GameFontNormal")
|
pfUI.swingtimer.ranged.text = pfUI.swingtimer.ranged:CreateFontString("Status", "DIALOG", "GameFontNormal")
|
||||||
pfUI.swingtimer.ranged.text:SetPoint("CENTER", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
pfUI.swingtimer.ranged.text:SetPoint("CENTER", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
||||||
pfUI.swingtimer.ranged.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
|
pfUI.swingtimer.ranged.text:SetFont(pfUI.font_default, sw_fontsize, "OUTLINE")
|
||||||
@@ -304,67 +274,41 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
S.raSpeed = (rs and rs > 0) and rs or 0
|
S.raSpeed = (rs and rs > 0) and rs or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset MH countdown to full speed (server confirmed swing)
|
-- Start* restart a countdown from a PLAYER_SWING reset. `remaining` can be
|
||||||
local function ResetMH()
|
-- shorter than the weapon speed (parry haste, ranged wind-up), so the bar
|
||||||
if S.mhFrozenAt then
|
-- length stays the full swing and the fill starts part-way along.
|
||||||
S.mhFrozenAt = nil
|
local function StartMH(remaining)
|
||||||
end
|
|
||||||
UpdateWeaponSpeeds()
|
UpdateWeaponSpeeds()
|
||||||
pfUI.swingtimer.mhGraceAt = nil -- cancel any pending hide
|
pfUI.swingtimer.mhGraceAt = nil -- cancel any pending hide
|
||||||
S.mhTimerMax = S.mhSpeed
|
S.mhTimerMax = math.max(S.mhSpeed, remaining)
|
||||||
S.mhTimer = S.mhSpeed
|
S.mhTimer = remaining
|
||||||
S.mhActive = true
|
S.mhActive = true
|
||||||
pfUI.swingtimer.mainhand:Show()
|
pfUI.swingtimer.mainhand:Show()
|
||||||
pfUI.swingtimer:Show()
|
pfUI.swingtimer:Show()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset OH countdown to full speed
|
local function StartOH(remaining)
|
||||||
local function ResetOH()
|
|
||||||
UpdateWeaponSpeeds()
|
UpdateWeaponSpeeds()
|
||||||
|
-- The off-hand attack time stays set with a shield equipped
|
||||||
if S.ohSpeed <= 0 then return end
|
if S.ohSpeed <= 0 then return end
|
||||||
pfUI.swingtimer.ohGraceAt = nil -- cancel any pending hide
|
pfUI.swingtimer.ohGraceAt = nil -- cancel any pending hide
|
||||||
S.ohTimerMax = S.ohSpeed
|
S.ohTimerMax = math.max(S.ohSpeed, remaining)
|
||||||
S.ohTimer = S.ohSpeed
|
S.ohTimer = remaining
|
||||||
S.ohActive = true
|
S.ohActive = true
|
||||||
if sw_showoh then pfUI.swingtimer.offhand:Show() end
|
if sw_showoh then pfUI.swingtimer.offhand:Show() end
|
||||||
pfUI.swingtimer:Show()
|
pfUI.swingtimer:Show()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset ranged countdown. replaceMH=true (Hunter Auto Shot, Throw) stops
|
local function StartRanged(remaining)
|
||||||
-- the melee swing clock while ranged ticks; replaceMH=false (wand Shoot)
|
|
||||||
-- leaves it running for melee weaving.
|
|
||||||
local function ResetRanged(replaceMH)
|
|
||||||
if not sw_showranged then return end
|
if not sw_showranged then return end
|
||||||
UpdateWeaponSpeeds()
|
UpdateWeaponSpeeds()
|
||||||
if S.raSpeed <= 0 then return end
|
if S.raSpeed <= 0 then return end
|
||||||
if replaceMH then
|
S.raTimerMax = math.max(S.raSpeed, remaining)
|
||||||
S.mhActive = false
|
S.raTimer = remaining
|
||||||
pfUI.swingtimer.mainhand:Hide()
|
|
||||||
end
|
|
||||||
S.raTimerMax = S.raSpeed
|
|
||||||
S.raTimer = S.raSpeed
|
|
||||||
S.raActive = true
|
S.raActive = true
|
||||||
|
|
||||||
if isHunter then
|
pfUI.swingtimer.ranged:SetStatusBarColor(raR, raG, raB, raA)
|
||||||
pfUI.swingtimer.ranged.left:ClearAllPoints()
|
pfUI.swingtimer.ranged:SetValue(isHunter and 1 or 0)
|
||||||
pfUI.swingtimer.ranged.left:SetPoint("RIGHT", pfUI.swingtimer.ranged, "CENTER", 0, 0)
|
|
||||||
pfUI.swingtimer.ranged.left:SetWidth(sw_width / 2)
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexCoord(0, 0.5, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.right:SetWidth(sw_width / 2)
|
|
||||||
pfUI.swingtimer.ranged.right:SetTexCoord(0.5, 1, 0, 1)
|
|
||||||
else
|
|
||||||
pfUI.swingtimer.ranged.left:ClearAllPoints()
|
|
||||||
pfUI.swingtimer.ranged.left:SetPoint("TOPLEFT", pfUI.swingtimer.ranged, "TOPLEFT", 0, 0)
|
|
||||||
pfUI.swingtimer.ranged.left:SetWidth(0.1)
|
|
||||||
pfUI.swingtimer.ranged.left:Hide()
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexCoord(0, 0, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.right:SetWidth(0.1)
|
|
||||||
pfUI.swingtimer.ranged.right:Hide()
|
|
||||||
end
|
|
||||||
pfUI.swingtimer.ranged.left:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
pfUI.swingtimer.ranged.right:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
pfUI.swingtimer.ranged.warn:SetWidth(1)
|
|
||||||
pfUI.swingtimer.ranged.warn:Hide()
|
|
||||||
pfUI.swingtimer.ranged:Show()
|
pfUI.swingtimer.ranged:Show()
|
||||||
pfUI.swingtimer:Show()
|
pfUI.swingtimer:Show()
|
||||||
end
|
end
|
||||||
@@ -486,23 +430,17 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
local anyActive = false
|
local anyActive = false
|
||||||
|
|
||||||
-- Tick timers down. When a timer expires we give a short grace period before
|
-- Tick timers down. When a timer expires we give a short grace period before
|
||||||
-- hiding the bar, to bridge the 1-2 frame gap until AUTO_ATTACK_SELF arrives.
|
-- hiding the bar, to bridge the 1-2 frame gap until PLAYER_SWING arrives.
|
||||||
-- If AUTO_ATTACK_SELF arrives during the grace period it resets the timer
|
-- If PLAYER_SWING arrives during the grace period it resets the timer
|
||||||
-- normally and the grace timer is cleared. If not (e.g. auto-attack was
|
-- normally and the grace timer is cleared. If not (e.g. auto-attack was
|
||||||
-- turned off), the bar hides after the grace period ends.
|
-- turned off), the bar hides after the grace period ends.
|
||||||
local GRACE = 0.15 -- seconds to wait after timer hits 0 before hiding
|
local GRACE = 0.15 -- seconds to wait after timer hits 0 before hiding
|
||||||
|
|
||||||
if S.mhActive then
|
if S.mhActive then
|
||||||
-- Don't tick while frozen (swing-delay spell like Slam is being cast)
|
S.mhTimer = S.mhTimer - delta
|
||||||
if not S.mhFrozenAt then
|
|
||||||
S.mhTimer = S.mhTimer - delta
|
|
||||||
end
|
|
||||||
if S.mhTimer <= 0 then
|
if S.mhTimer <= 0 then
|
||||||
S.mhTimer = 0
|
S.mhTimer = 0
|
||||||
if S.mhFrozenAt then
|
if not pfUI.swingtimer.mhGraceAt then
|
||||||
-- Swing-delay spell cast in progress: bar holds at 0, skip grace/hide.
|
|
||||||
-- SPELL_GO handler will unfreeze and add cast duration to timer.
|
|
||||||
elseif not pfUI.swingtimer.mhGraceAt then
|
|
||||||
pfUI.swingtimer.mhGraceAt = GetTime() + GRACE
|
pfUI.swingtimer.mhGraceAt = GetTime() + GRACE
|
||||||
elseif GetTime() >= pfUI.swingtimer.mhGraceAt then
|
elseif GetTime() >= pfUI.swingtimer.mhGraceAt then
|
||||||
pfUI.swingtimer.mhGraceAt = nil
|
pfUI.swingtimer.mhGraceAt = nil
|
||||||
@@ -641,30 +579,12 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
local remaining = S.raTimer
|
local remaining = S.raTimer
|
||||||
if isHunter then
|
if isHunter then
|
||||||
local DEADZONE = 0.5
|
local DEADZONE = 0.5
|
||||||
local halfW = sw_width / 2
|
|
||||||
if remaining > DEADZONE then
|
if remaining > DEADZONE then
|
||||||
local elapsed = S.raTimerMax - remaining
|
pfUI.swingtimer.ranged:SetStatusBarColor(raR, raG, raB, raA)
|
||||||
local phase1dur = S.raTimerMax - DEADZONE
|
pfUI.swingtimer.ranged:SetValue((remaining - DEADZONE) / (S.raTimerMax - DEADZONE))
|
||||||
local p = elapsed / phase1dur
|
|
||||||
local w = halfW * (1 - p)
|
|
||||||
if w < 1 then w = 1 end
|
|
||||||
pfUI.swingtimer.ranged.left:Show()
|
|
||||||
pfUI.swingtimer.ranged.left:SetWidth(w)
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexCoord(0, (1 - p) * 0.5, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.left:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
pfUI.swingtimer.ranged.right:Show()
|
|
||||||
pfUI.swingtimer.ranged.right:SetWidth(w)
|
|
||||||
pfUI.swingtimer.ranged.right:SetTexCoord(1 - (1 - p) * 0.5, 1, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.right:SetVertexColor(raR, raG, raB, raA)
|
|
||||||
pfUI.swingtimer.ranged.warn:Hide()
|
|
||||||
else
|
else
|
||||||
local p = 1 - (remaining / DEADZONE)
|
pfUI.swingtimer.ranged:SetStatusBarColor(rwR, rwG, rwB, rwA)
|
||||||
local w = sw_width * p
|
pfUI.swingtimer.ranged:SetValue(1 - (remaining / DEADZONE))
|
||||||
if w < 1 then w = 1 end
|
|
||||||
pfUI.swingtimer.ranged.left:Hide()
|
|
||||||
pfUI.swingtimer.ranged.right:Hide()
|
|
||||||
pfUI.swingtimer.ranged.warn:SetWidth(w)
|
|
||||||
pfUI.swingtimer.ranged.warn:Show()
|
|
||||||
end
|
end
|
||||||
if sw_showtext then
|
if sw_showtext then
|
||||||
if remaining <= 0.5 then
|
if remaining <= 0.5 then
|
||||||
@@ -674,14 +594,7 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local progress = 1 - (remaining / S.raTimerMax)
|
pfUI.swingtimer.ranged:SetValue(1 - (remaining / S.raTimerMax))
|
||||||
local w = sw_width * progress
|
|
||||||
if w < 1 then w = 1 end
|
|
||||||
pfUI.swingtimer.ranged.left:Show()
|
|
||||||
pfUI.swingtimer.ranged.left:SetWidth(w)
|
|
||||||
pfUI.swingtimer.ranged.left:SetTexCoord(0, progress, 0, 1)
|
|
||||||
pfUI.swingtimer.ranged.right:Hide()
|
|
||||||
pfUI.swingtimer.ranged.warn:Hide()
|
|
||||||
if sw_showtext then
|
if sw_showtext then
|
||||||
pfUI.swingtimer.ranged.text:SetFormattedText("%.1f", math.floor(remaining * 10) / 10)
|
pfUI.swingtimer.ranged.text:SetFormattedText("%.1f", math.floor(remaining * 10) / 10)
|
||||||
end
|
end
|
||||||
@@ -722,164 +635,46 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- SPELL_START_SELF: fires only for cast-time spells, never instants
|
|
||||||
local spellStartFrame = CreateFrame("Frame")
|
|
||||||
spellStartFrame:RegisterEvent("SPELL_START_SELF")
|
|
||||||
spellStartFrame:SetScript("OnEvent", function()
|
|
||||||
if not (arg1 and arg1 > 0) then return end
|
|
||||||
S.pendingCastSpellId = arg1
|
|
||||||
-- Freeze the swing timer for cast-time spells that DON'T reset auto-
|
|
||||||
-- attack on completion (Slam, Hammer of Wrath on Turtle, etc.) — those
|
|
||||||
-- let the swing resume from where it paused. C_Spell.ResetsMeleeSwing
|
|
||||||
-- mirrors the server rule; spells that reset don't need freezing (they
|
|
||||||
-- reset on SPELL_GO_SELF). Subsumes the old hardcoded swingDelaySpells
|
|
||||||
-- list (no list maintenance for new Slam-style spells).
|
|
||||||
if S.mhActive then
|
|
||||||
if not C_Spell.ResetsMeleeSwing(arg1) then
|
|
||||||
S.mhFrozenAt = GetTime()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Cast cancel/fail/interrupt: unfreeze swing timer if a delay spell was interrupted
|
|
||||||
local spellFailFrame = CreateFrame("Frame")
|
|
||||||
spellFailFrame:RegisterEvent("SPELLCAST_FAILED")
|
|
||||||
spellFailFrame:RegisterEvent("SPELLCAST_INTERRUPTED")
|
|
||||||
spellFailFrame:SetScript("OnEvent", function()
|
|
||||||
if S.mhFrozenAt then
|
|
||||||
S.mhFrozenAt = nil
|
|
||||||
end
|
|
||||||
S.pendingCastSpellId = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- SPELL_GO hook via libdebuff
|
|
||||||
pfUI.libdebuff_spell_go_hooks = pfUI.libdebuff_spell_go_hooks or {}
|
|
||||||
pfUI.libdebuff_spell_go_hooks["swingtimer"] = function(spellId)
|
|
||||||
-- C_Spell.IsRangedAutoAttackSpell catches both Auto Shot (75) and
|
|
||||||
-- wand Shoot (5019) via Spell.dbc's AUTO_REPEAT attribute (covers
|
|
||||||
-- any future auto-repeat ranged spell automatically). Wand is the
|
|
||||||
-- one independent of the MH swing — everything else replaces it.
|
|
||||||
-- Throw isn't auto-repeat (single-shot) so it's handled explicitly.
|
|
||||||
if C_Spell.IsRangedAutoAttackSpell(spellId) then
|
|
||||||
ResetRanged(spellId ~= WAND_SHOOT_SPELLID)
|
|
||||||
return
|
|
||||||
elseif spellId == THROW_SPELLID then
|
|
||||||
ResetRanged(true)
|
|
||||||
return
|
|
||||||
elseif IsOnSwingSpell(spellId) then
|
|
||||||
-- On-next-swing ability (HS / Cleave / Maul / Raptor Strike / etc.)
|
|
||||||
-- — the swing fires as the spell consumes it. Drop the queued color.
|
|
||||||
S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false
|
|
||||||
ResetMH()
|
|
||||||
else
|
|
||||||
-- C_Spell.ResetsMeleeSwing mirrors the server rule (Turtle's
|
|
||||||
-- Spell::IsMeleeAttackResetSpell): InterruptFlags has AUTOATTACK and
|
|
||||||
-- AttributesEx2 lacks NOT_RESET_AUTO_ACTIONS. When the spell resets the
|
|
||||||
-- swing, snap the timers to full. Otherwise (elseif) a frozen-swing-
|
|
||||||
-- during-cast is a Slam-style cast — push the timer forward by the cast
|
|
||||||
-- duration so the bar resumes from where it paused.
|
|
||||||
if C_Spell.ResetsMeleeSwing(spellId) then
|
|
||||||
if S.mhActive and S.mhSpeed > 0 then
|
|
||||||
UpdateWeaponSpeeds()
|
|
||||||
S.mhTimerMax = S.mhSpeed
|
|
||||||
S.mhTimer = S.mhSpeed
|
|
||||||
end
|
|
||||||
if S.ohActive and S.ohSpeed > 0 then
|
|
||||||
S.ohTimerMax = S.ohSpeed
|
|
||||||
S.ohTimer = S.ohSpeed
|
|
||||||
end
|
|
||||||
elseif S.mhFrozenAt then
|
|
||||||
local castDuration = GetTime() - S.mhFrozenAt
|
|
||||||
S.mhTimer = S.mhTimer + castDuration
|
|
||||||
S.mhTimerMax = S.mhTimerMax + castDuration
|
|
||||||
S.mhFrozenAt = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
S.pendingCastSpellId = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- SPELL_CAST_EVENT hook: HS/Cleave/Maul queue tracking
|
|
||||||
pfUI.libdebuff_spell_cast_hooks = pfUI.libdebuff_spell_cast_hooks or {}
|
|
||||||
pfUI.libdebuff_spell_cast_hooks["swingtimer"] = function(success, spellId)
|
|
||||||
local kind = ClassifyOnSwingSpell(spellId)
|
|
||||||
if not kind then return end
|
|
||||||
S.useSpellQueueEvent = true
|
|
||||||
SetQueuedKind(kind)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local events = CreateFrame("Frame")
|
local events = CreateFrame("Frame")
|
||||||
events:RegisterEvent("AUTO_ATTACK_SELF")
|
events:RegisterEvent("PLAYER_SWING")
|
||||||
events:RegisterEvent("AUTO_ATTACK_OTHER")
|
|
||||||
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
events:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
events:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- ClassicAPI: per-slot, equipment-only
|
events:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- ClassicAPI: per-slot, equipment-only
|
||||||
events:RegisterEvent("PLAYER_REGEN_DISABLED")
|
events:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||||
events:RegisterEvent("PLAYER_REGEN_ENABLED")
|
events:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||||
events:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
|
events:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
|
||||||
events:RegisterUnitEvent("UNIT_DIED", UnitGUID("player"))
|
events:RegisterEvent("PLAYER_DEAD")
|
||||||
|
events:RegisterUnitEvent("UNIT_SPELLCAST_SENT", "player")
|
||||||
|
events:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
|
||||||
events:RegisterEvent("SPELL_QUEUE_EVENT")
|
events:RegisterEvent("SPELL_QUEUE_EVENT")
|
||||||
events:RegisterEvent("START_AUTOATTACK")
|
events:RegisterEvent("START_AUTOATTACK")
|
||||||
events:RegisterEvent("STOP_AUTOATTACK")
|
events:RegisterEvent("STOP_AUTOATTACK")
|
||||||
|
|
||||||
events:SetScript("OnEvent", function()
|
events:SetScript("OnEvent", function()
|
||||||
if event == "AUTO_ATTACK_SELF" then
|
if event == "PLAYER_SWING" then
|
||||||
local hitInfo = arg4 or 0
|
-- ClassicAPI tracks the server's swing clock (white hits, on-next-swing
|
||||||
local isOffhand = bit.band(hitInfo, HITINFO_LEFTSWING) ~= 0
|
-- abilities, swing-reset casts, parry haste, extra attacks, weapon
|
||||||
local noAction = bit.band(hitInfo, HITINFO_NOACTION) ~= 0
|
-- swaps) and hands over the seconds left until the next swing.
|
||||||
-- NOACTION means server did not advance swing clock (dodge/parry/miss).
|
if arg2 == Enum.PlayerSwingType.MainHand then
|
||||||
-- Only skip if the timer is already running - if it's not active yet
|
StartMH(arg1)
|
||||||
-- (first swing ever), we still want to start it so the bar appears.
|
elseif arg2 == Enum.PlayerSwingType.OffHand then
|
||||||
if noAction then
|
StartOH(arg1)
|
||||||
if isOffhand and S.ohActive then return end
|
elseif arg2 == Enum.PlayerSwingType.Ranged then
|
||||||
if not isOffhand and S.mhActive then return end
|
StartRanged(arg1)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Extra attack detection: if timer still has >20% remaining for that hand,
|
elseif event == "UNIT_SPELLCAST_SENT" then
|
||||||
-- the server did NOT reset the swing clock -> this is an extra attack, skip.
|
-- arg4 = spellID: an on-next-swing ability (HS / Cleave / Maul) queued
|
||||||
-- Use 20% here (SP_SwingTimer's ShouldResetTimer threshold).
|
local kind = ClassifyOnSwingSpell(arg4)
|
||||||
-- Exception: if timer is already at 0 (expired), always accept.
|
if kind then
|
||||||
if isOffhand then
|
S.useSpellQueueEvent = true
|
||||||
local pct = S.ohActive and (S.ohTimer / S.ohTimerMax) or 0
|
SetQueuedKind(kind)
|
||||||
if S.ohActive and S.ohTimer > 0 and pct > 0.20 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
ResetOH()
|
|
||||||
else
|
|
||||||
local pct = S.mhActive and (S.mhTimer / S.mhTimerMax) or 0
|
|
||||||
if S.mhActive and S.mhTimer > 0 and pct > 0.20 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
ResetMH()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "AUTO_ATTACK_OTHER" then
|
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||||
-- Parry haste: enemy attacked the player and player parried
|
-- arg3 = spellID: the on-next-swing ability resolved, which consumes
|
||||||
local targetGuid = arg2
|
-- the queue, so drop the queued color
|
||||||
if not targetGuid or not IsPlayerGuid(targetGuid) then return end
|
if IsOnSwingSpell(arg3) then
|
||||||
local victimState = arg5 or 0
|
S.hsQueued = false; S.cleaveQueued = false; S.maulQueued = false
|
||||||
-- VICTIMSTATE_PARRY = 3
|
|
||||||
-- Vanilla: parry reduces the NEXT swing timer by 40% of weapon speed,
|
|
||||||
-- minimum 20% of weapon speed remaining (SP_SwingTimer approach)
|
|
||||||
if victimState == 3 then
|
|
||||||
-- Apply to whichever swing comes next (smallest % remaining = closest to firing)
|
|
||||||
if S.ohActive and S.ohSpeed > 0 and (S.ohTimer / S.ohTimerMax) < (S.mhTimer / S.mhTimerMax) then
|
|
||||||
local minimum = S.ohSpeed * 0.20
|
|
||||||
if S.ohTimer > minimum then
|
|
||||||
local reduct = S.ohSpeed * 0.40
|
|
||||||
local before = S.ohTimer
|
|
||||||
S.ohTimer = S.ohTimer - reduct
|
|
||||||
if S.ohTimer < minimum then S.ohTimer = minimum end
|
|
||||||
end
|
|
||||||
elseif S.mhActive and S.mhSpeed > 0 then
|
|
||||||
local minimum = S.mhSpeed * 0.20
|
|
||||||
if S.mhTimer > minimum then
|
|
||||||
local reduct = S.mhSpeed * 0.40
|
|
||||||
local before = S.mhTimer
|
|
||||||
S.mhTimer = S.mhTimer - reduct
|
|
||||||
if S.mhTimer < minimum then S.mhTimer = minimum end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "SPELL_QUEUE_EVENT" then
|
elseif event == "SPELL_QUEUE_EVENT" then
|
||||||
@@ -931,10 +726,8 @@ pfUI:RegisterModule("swingtimer", function ()
|
|||||||
S.cleaveQueued = false
|
S.cleaveQueued = false
|
||||||
S.maulQueued = false
|
S.maulQueued = false
|
||||||
|
|
||||||
elseif event == "UNIT_DIED" then
|
elseif event == "PLAYER_DEAD" then
|
||||||
if IsPlayerGuid(arg1) then
|
ResetAll()
|
||||||
ResetAll()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
@@ -866,9 +866,6 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
|
|||||||
if C.thirdparty.supermacro.enable == "0" then return end
|
if C.thirdparty.supermacro.enable == "0" then return end
|
||||||
if not pfUI.bars then return end
|
if not pfUI.bars then return end
|
||||||
|
|
||||||
-- skin game menu button
|
|
||||||
SkinButton(GameMenuButtonSuperMacro)
|
|
||||||
|
|
||||||
-- hook events to include SuperMacro refreshs
|
-- hook events to include SuperMacro refreshs
|
||||||
local ButtonFullUpdate = pfUI.bars.ButtonFullUpdate
|
local ButtonFullUpdate = pfUI.bars.ButtonFullUpdate
|
||||||
pfUI.bars.ButtonFullUpdate = function(button)
|
pfUI.bars.ButtonFullUpdate = function(button)
|
||||||
@@ -1197,16 +1194,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
|
|||||||
HookAddonOrVariable("LunaUnitFrames", EnableHealComm)
|
HookAddonOrVariable("LunaUnitFrames", EnableHealComm)
|
||||||
HookAddonOrVariable("NotGrid", EnableHealComm)
|
HookAddonOrVariable("NotGrid", EnableHealComm)
|
||||||
|
|
||||||
HookAddonOrVariable("MoveAnything", function()
|
|
||||||
SkinButton(GameMenuButtonMoveAnything)
|
|
||||||
end)
|
|
||||||
|
|
||||||
HookAddonOrVariable("MCP", function()
|
|
||||||
SkinButton(GameMenuButtonAddOns)
|
|
||||||
end)
|
|
||||||
|
|
||||||
HookAddonOrVariable("HardcoreDeath", function()
|
HookAddonOrVariable("HardcoreDeath", function()
|
||||||
SkinButton(GameMenuButtonHardcoreDeathLogGUI)
|
|
||||||
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + 20)
|
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + 20)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -113,7 +113,7 @@ pfUI:RegisterModule("totems", function ()
|
|||||||
self.bar[i].cdbg = self.bar[i].cdbg or CreateFrame("Frame", nil, self.bar[i])
|
self.bar[i].cdbg = self.bar[i].cdbg or CreateFrame("Frame", nil, self.bar[i])
|
||||||
self.bar[i].cdbg:SetSize(self.iconsize - 3, self.iconsize - 3)
|
self.bar[i].cdbg:SetSize(self.iconsize - 3, self.iconsize - 3)
|
||||||
self.bar[i].cdbg:SetPoint("CENTER", self.bar[i], "CENTER", 0, 0)
|
self.bar[i].cdbg:SetPoint("CENTER", self.bar[i], "CENTER", 0, 0)
|
||||||
self.bar[i].cd = self.bar[i].cd or CreateFrame("Model", "pfTotemsBar"..i.."Cooldown", self.bar[i].cdbg, "CooldownFrameTemplate")
|
self.bar[i].cd = self.bar[i].cd or CreateFrame("Cooldown", "pfTotemsBar"..i.."Cooldown", self.bar[i].cdbg, "CooldownFrameTemplate")
|
||||||
self.bar[i].cd.pfCooldownStyleAnimation = 1
|
self.bar[i].cd.pfCooldownStyleAnimation = 1
|
||||||
self.bar[i].cd.pfCooldownType = "ALL"
|
self.bar[i].cd.pfCooldownType = "ALL"
|
||||||
|
|
||||||
|
|||||||
+11
-18
@@ -34,6 +34,14 @@ pfUI:RegisterModule("tracking", function ()
|
|||||||
pfUI.tracking.icon:SetTexCoord(.08, .92, .08, .92)
|
pfUI.tracking.icon:SetTexCoord(.08, .92, .08, .92)
|
||||||
pfUI.tracking.icon:SetAllPoints(pfUI.tracking)
|
pfUI.tracking.icon:SetAllPoints(pfUI.tracking)
|
||||||
|
|
||||||
|
-- Pulses the icon while no tracking spell is active
|
||||||
|
pfUI.tracking.pulse = pfUI.tracking.icon:CreateAnimationGroup()
|
||||||
|
pfUI.tracking.pulse:SetLooping("BOUNCE")
|
||||||
|
local fade = pfUI.tracking.pulse:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-.5)
|
||||||
|
fade:SetDuration(.5)
|
||||||
|
fade:SetSmoothing("IN_OUT")
|
||||||
|
|
||||||
pfUI.tracking.menu = CreateFrame("Frame", "pfUIDropDownMenuTracking", nil, "UIDropDownMenuTemplate")
|
pfUI.tracking.menu = CreateFrame("Frame", "pfUIDropDownMenuTracking", nil, "UIDropDownMenuTemplate")
|
||||||
|
|
||||||
pfUI.tracking:RegisterEvent("PLAYER_ENTERING_WORLD")
|
pfUI.tracking:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
@@ -48,19 +56,6 @@ pfUI:RegisterModule("tracking", function ()
|
|||||||
this:RefreshMenu()
|
this:RefreshMenu()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
pfUI.tracking:SetScript("OnUpdate", function()
|
|
||||||
if this.pulse then
|
|
||||||
local _,_,_,alpha = this.icon:GetVertexColor()
|
|
||||||
local fpsmod = GetFramerate() / 30
|
|
||||||
if not alpha or alpha >= 0.9 then
|
|
||||||
this.modifier = -0.03 / fpsmod
|
|
||||||
elseif alpha <= .5 then
|
|
||||||
this.modifier = 0.03 / fpsmod
|
|
||||||
end
|
|
||||||
this.icon:SetVertexColor(1,1,1,alpha + this.modifier)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
pfUI.tracking:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
pfUI.tracking:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||||
pfUI.tracking:SetScript("OnClick", function()
|
pfUI.tracking:SetScript("OnClick", function()
|
||||||
if arg1 == "RightButton" then
|
if arg1 == "RightButton" then
|
||||||
@@ -113,20 +108,18 @@ pfUI:RegisterModule("tracking", function ()
|
|||||||
local texture = GetTrackingTexture()
|
local texture = GetTrackingTexture()
|
||||||
if texture and texture ~= state.texture then
|
if texture and texture ~= state.texture then
|
||||||
state.texture = texture
|
state.texture = texture
|
||||||
pfUI.tracking.pulse = nil
|
pfUI.tracking.pulse:Stop()
|
||||||
pfUI.tracking.icon:SetTexture(texture)
|
pfUI.tracking.icon:SetTexture(texture)
|
||||||
pfUI.tracking.icon:SetVertexColor(1,1,1,1)
|
|
||||||
pfUI.tracking:Show()
|
pfUI.tracking:Show()
|
||||||
elseif not texture then
|
elseif not texture then
|
||||||
state.texture = nil
|
state.texture = nil
|
||||||
|
|
||||||
if pulse and next(state.spells) ~= nil 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:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||||
pfUI.tracking.icon:SetVertexColor(1,1,1,1)
|
if not pfUI.tracking.pulse:IsPlaying() then pfUI.tracking.pulse:Play() end
|
||||||
pfUI.tracking:Show()
|
pfUI.tracking:Show()
|
||||||
else
|
else
|
||||||
pfUI.tracking.pulse = nil
|
pfUI.tracking.pulse:Stop()
|
||||||
pfUI.tracking:Hide()
|
pfUI.tracking:Hide()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -98,11 +98,9 @@ pfUI:RegisterModule("turtle-wow", function ()
|
|||||||
GameMenuButtonOptions:ClearAllPoints()
|
GameMenuButtonOptions:ClearAllPoints()
|
||||||
GameMenuButtonOptions:SetPoint("TOP", GameMenuButtonShop, "BOTTOM", 0, -16)
|
GameMenuButtonOptions:SetPoint("TOP", GameMenuButtonShop, "BOTTOM", 0, -16)
|
||||||
|
|
||||||
-- apply pfUI skin to the new shop button
|
-- match the shop button's text to the other skinned menu buttons
|
||||||
if pfUI.skin["Game Menu"] and pfUI_config["disabled"]["skin_Game Menu"] ~= "1" then
|
if pfUI.skin["Game Menu"] and pfUI_config["disabled"]["skin_Game Menu"] ~= "1" then
|
||||||
local font = GameMenuButtonShop:GetFontString()
|
GameMenuButtonShop:GetFontString():SetTextColor(1,1,1,1)
|
||||||
font:SetTextColor(1,1,1,1)
|
|
||||||
SkinButton(GameMenuButtonShop)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+11
-12
@@ -130,15 +130,6 @@ pfUI:RegisterModule("unlock", function ()
|
|||||||
return frames
|
return frames
|
||||||
end
|
end
|
||||||
|
|
||||||
local function DraggerOnUpdate()
|
|
||||||
this.text:SetAlpha(this.text:GetAlpha() -0.05)
|
|
||||||
if this.text:GetAlpha() < 0.1 then
|
|
||||||
this.text:SetText(strsub(this:GetParent():GetName(),3))
|
|
||||||
this.text:SetAlpha(1)
|
|
||||||
this:SetScript("OnUpdate", function() return end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SaveScale(frame, scale)
|
local function SaveScale(frame, scale)
|
||||||
frame:SetScale(scale)
|
frame:SetScale(scale)
|
||||||
|
|
||||||
@@ -148,9 +139,8 @@ pfUI:RegisterModule("unlock", function ()
|
|||||||
C.position[frame:GetName()]["scale"] = scale
|
C.position[frame:GetName()]["scale"] = scale
|
||||||
|
|
||||||
frame.drag.text:SetText(T["Scale"] .. ": " .. scale)
|
frame.drag.text:SetText(T["Scale"] .. ": " .. scale)
|
||||||
frame.drag.text:SetAlpha(1)
|
frame.drag.fade:Stop()
|
||||||
|
frame.drag.fade:Play()
|
||||||
frame.drag:SetScript("OnUpdate", DraggerOnUpdate)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function SavePosition(frame)
|
local function SavePosition(frame)
|
||||||
@@ -455,6 +445,15 @@ pfUI:RegisterModule("unlock", function ()
|
|||||||
d.text:SetPoint("CENTER", 0, 0)
|
d.text:SetPoint("CENTER", 0, 0)
|
||||||
d.text:SetFontObject(GameFontWhite)
|
d.text:SetFontObject(GameFontWhite)
|
||||||
|
|
||||||
|
-- Fades out the scale readout, then puts the frame name back
|
||||||
|
d.fade = d.text:CreateAnimationGroup()
|
||||||
|
local fade = d.fade:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-1)
|
||||||
|
fade:SetDuration(.3)
|
||||||
|
d.fade:SetScript("OnFinished", function()
|
||||||
|
d.text:SetText(strsub(f:GetName(),3))
|
||||||
|
end)
|
||||||
|
|
||||||
d.frame = f
|
d.frame = f
|
||||||
d.fname = fname
|
d.fname = fname
|
||||||
d.label = label
|
d.label = label
|
||||||
|
|||||||
@@ -34,4 +34,25 @@ pfUI:RegisterModule("unusable", function ()
|
|||||||
hooksecurefunc("BankFrameItemButton_UpdateLock", function()
|
hooksecurefunc("BankFrameItemButton_UpdateLock", function()
|
||||||
pfUI.unusable:UpdateSlot(-1, this:GetID())
|
pfUI.unusable:UpdateSlot(-1, this:GetID())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- requirement changes (level, proficiency/skill, required spell, reputation,
|
||||||
|
-- honor rank) don't touch the bags; queue a full rebag through pfUI.bag's
|
||||||
|
-- coalesced delay, whose UpdateSlot resets the tint before we reapply it
|
||||||
|
local refresh = CreateFrame("Frame")
|
||||||
|
refresh:RegisterEvent("PLAYER_LEVEL_UP")
|
||||||
|
refresh:RegisterEvent("SKILL_LINES_CHANGED")
|
||||||
|
refresh:RegisterEvent("SPELLS_CHANGED")
|
||||||
|
refresh:RegisterEvent("FACTION_STANDING_CHANGED")
|
||||||
|
refresh:RegisterEvent("PLAYER_PVP_RANK_CHANGED")
|
||||||
|
refresh:SetScript("OnEvent", function()
|
||||||
|
for _, bag in pairs(pfUI.BACKPACK) do
|
||||||
|
pfUI.bag.delay.UpdateBag[bag] = true
|
||||||
|
end
|
||||||
|
-- the bank frame is only created on first bank visit
|
||||||
|
if pfUI.bag.left and pfUI.bag.left:IsShown() then
|
||||||
|
for _, bag in pairs(pfUI.BANK) do
|
||||||
|
pfUI.bag.delay.UpdateBag[bag] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
+29
-9
@@ -63,9 +63,16 @@ pfUI:RegisterModule("xpbar", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Cancel a running fade-out and show the bar at full alpha
|
||||||
|
local function Reveal(self)
|
||||||
|
self.fade:Stop()
|
||||||
|
self:SetAlpha(1)
|
||||||
|
end
|
||||||
|
|
||||||
local function OnLeave(self)
|
local function OnLeave(self)
|
||||||
local self = self or this
|
local self = self or this
|
||||||
|
|
||||||
|
self.hover = nil
|
||||||
self.tick = GetTime() + 3.00
|
self.tick = GetTime() + 3.00
|
||||||
GameTooltip:Hide()
|
GameTooltip:Hide()
|
||||||
end
|
end
|
||||||
@@ -82,7 +89,8 @@ local function OnEnter(self)
|
|||||||
mode = "REP"
|
mode = "REP"
|
||||||
end
|
end
|
||||||
|
|
||||||
self:SetAlpha(1)
|
self.hover = true
|
||||||
|
Reveal(self)
|
||||||
|
|
||||||
if mode == "XP" then
|
if mode == "XP" then
|
||||||
local xp, xpmax, exh = UnitXP("player"), UnitXPMax("player"), GetXPExhaustion()
|
local xp, xpmax, exh = UnitXP("player"), UnitXPMax("player"), GetXPExhaustion()
|
||||||
@@ -183,13 +191,15 @@ end
|
|||||||
local self = self or this
|
local self = self or this
|
||||||
|
|
||||||
if self.text_mouse == "1" then
|
if self.text_mouse == "1" then
|
||||||
self.bar.text:SetShown(MouseIsOver(self))
|
self.bar.text:SetShown(self.hover)
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.always then return end
|
if self.always then return end
|
||||||
if self:GetAlpha() == 0 or MouseIsOver(self) then return end
|
-- Hover comes from OnEnter/OnLeave, the same mouse focus that reveals the
|
||||||
if ( self.tick or 1) > GetTime() then return else self.tick = GetTime() + .01 end
|
-- bar, so the fade can't restart under the cursor
|
||||||
self:SetAlpha(self:GetAlpha() - .05)
|
if self:GetAlpha() == 0 or self.hover or self.fade:IsPlaying() then return end
|
||||||
|
if ( self.tick or 1) > GetTime() then return end
|
||||||
|
self.fade:Play()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function OnEvent(self)
|
local function OnEvent(self)
|
||||||
@@ -210,7 +220,7 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self.always then
|
if self.always then
|
||||||
self:SetAlpha(1)
|
Reveal(self)
|
||||||
self:Show()
|
self:Show()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -220,7 +230,7 @@ end
|
|||||||
|
|
||||||
if mode == "XP" then
|
if mode == "XP" then
|
||||||
self.enabled = true
|
self.enabled = true
|
||||||
self:SetAlpha(1)
|
Reveal(self)
|
||||||
self.bar:SetMinMaxValues(0, UnitXPMax("player"))
|
self.bar:SetMinMaxValues(0, UnitXPMax("player"))
|
||||||
self.bar:SetValue(UnitXP("player"))
|
self.bar:SetValue(UnitXP("player"))
|
||||||
if GetXPExhaustion() then
|
if GetXPExhaustion() then
|
||||||
@@ -246,7 +256,7 @@ end
|
|||||||
elseif mode == "PETXP" then
|
elseif mode == "PETXP" then
|
||||||
self.restedbar:Hide()
|
self.restedbar:Hide()
|
||||||
self.enabled = true
|
self.enabled = true
|
||||||
self:SetAlpha(1)
|
Reveal(self)
|
||||||
|
|
||||||
local currXP, nextXP = GetPetExperience()
|
local currXP, nextXP = GetPetExperience()
|
||||||
self.bar:SetMinMaxValues(min(0, currXP), nextXP)
|
self.bar:SetMinMaxValues(min(0, currXP), nextXP)
|
||||||
@@ -264,7 +274,7 @@ end
|
|||||||
local name, standingID, barMin, barMax, barValue = GetRepDisplay(self.factionID)
|
local name, standingID, barMin, barMax, barValue = GetRepDisplay(self.factionID)
|
||||||
if name then
|
if name then
|
||||||
self.enabled = true
|
self.enabled = true
|
||||||
self:SetAlpha(1)
|
Reveal(self)
|
||||||
|
|
||||||
barMax = barMax - barMin
|
barMax = barMax - barMin
|
||||||
barValue = barValue - barMin
|
barValue = barValue - barMin
|
||||||
@@ -342,6 +352,7 @@ end
|
|||||||
local cr, cg, cb, ca = pfUI.api.GetStringColor(b.xp_color)
|
local cr, cg, cb, ca = pfUI.api.GetStringColor(b.xp_color)
|
||||||
b.bar:SetStatusBarColor(cr,cg,cb,ca)
|
b.bar:SetStatusBarColor(cr,cg,cb,ca)
|
||||||
b.bar:SetOrientation(b.mode)
|
b.bar:SetOrientation(b.mode)
|
||||||
|
b.bar:SetRotatesTexture(b.mode == "VERTICAL")
|
||||||
|
|
||||||
b.bar.text = b.bar.text or b.bar:CreateFontString()
|
b.bar.text = b.bar.text or b.bar:CreateFontString()
|
||||||
b.bar.text:SetPoint("CENTER", b, "CENTER", 0, b.text_off_y)
|
b.bar.text:SetPoint("CENTER", b, "CENTER", 0, b.text_off_y)
|
||||||
@@ -358,10 +369,19 @@ end
|
|||||||
local cr, cg, cb, ca = pfUI.api.GetStringColor(b.rest_color)
|
local cr, cg, cb, ca = pfUI.api.GetStringColor(b.rest_color)
|
||||||
b.restedbar:SetStatusBarColor(cr,cg,cb,ca)
|
b.restedbar:SetStatusBarColor(cr,cg,cb,ca)
|
||||||
b.restedbar:SetOrientation(b.mode)
|
b.restedbar:SetOrientation(b.mode)
|
||||||
|
b.restedbar:SetRotatesTexture(b.mode == "VERTICAL")
|
||||||
|
|
||||||
-- auto hide
|
-- auto hide
|
||||||
b:EnableMouse(true)
|
b:EnableMouse(true)
|
||||||
|
|
||||||
|
if not b.fade then
|
||||||
|
b.fade = b:CreateAnimationGroup()
|
||||||
|
local fade = b.fade:CreateAnimation("Alpha")
|
||||||
|
fade:SetChange(-1)
|
||||||
|
fade:SetDuration(.3)
|
||||||
|
b.fade:SetScript("OnFinished", function() b:SetAlpha(0) end)
|
||||||
|
end
|
||||||
|
|
||||||
b:RegisterEvent("FACTION_STANDING_CHANGED")
|
b:RegisterEvent("FACTION_STANDING_CHANGED")
|
||||||
b:RegisterUnitEvent("UNIT_PET", "player")
|
b:RegisterUnitEvent("UNIT_PET", "player")
|
||||||
b:RegisterUnitEvent("UNIT_LEVEL", "player")
|
b:RegisterUnitEvent("UNIT_LEVEL", "player")
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ pfUI:RegisterSkin("Friends", function ()
|
|||||||
CreateBackdropShadow(FriendsFrame)
|
CreateBackdropShadow(FriendsFrame)
|
||||||
|
|
||||||
FriendsFrame.backdrop:SetPoint("TOPLEFT", 8, -10)
|
FriendsFrame.backdrop:SetPoint("TOPLEFT", 8, -10)
|
||||||
FriendsFrame.backdrop:SetPoint("BOTTOMRIGHT", -32, 74)
|
FriendsFrame.backdrop:SetPoint("BOTTOMRIGHT", -32, 72)
|
||||||
FriendsFrame:SetHitRectInsets(8,32,10,74)
|
FriendsFrame:SetHitRectInsets(8,32,10,72)
|
||||||
EnableMovable("FriendsFrame")
|
EnableMovable("FriendsFrame")
|
||||||
|
|
||||||
SkinCloseButton(FriendsFrameCloseButton, FriendsFrame.backdrop, -6, -6)
|
SkinCloseButton(FriendsFrameCloseButton, FriendsFrame.backdrop, -6, -6)
|
||||||
|
|||||||
@@ -19,24 +19,20 @@ pfUI:RegisterSkin("Game Menu", function ()
|
|||||||
pfUI.gui:Show()
|
pfUI.gui:Show()
|
||||||
HideUIPanel(GameMenuFrame)
|
HideUIPanel(GameMenuFrame)
|
||||||
end)
|
end)
|
||||||
SkinButton(pfUIButton)
|
|
||||||
|
|
||||||
local point, relativeTo, relativePoint, xOffset, yOffset = GameMenuButtonOptions:GetPoint()
|
local point, relativeTo, relativePoint, xOffset, yOffset = GameMenuButtonOptions:GetPoint()
|
||||||
GameMenuButtonOptions:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset - 22)
|
GameMenuButtonOptions:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset - 22)
|
||||||
|
|
||||||
local buttons = {
|
-- skin every button on the menu, including ones other addons add later
|
||||||
GameMenuButtonOptions,
|
local function SkinMenuButtons()
|
||||||
GameMenuButtonSoundOptions,
|
for _, child in pairs({GameMenuFrame:GetChildren()}) do
|
||||||
GameMenuButtonUIOptions,
|
if child:GetFrameType() == "Button" and not child._pfMenuSkinned then
|
||||||
GameMenuButtonKeybindings,
|
SkinButton(child)
|
||||||
GameMenuButtonMacros,
|
child._pfMenuSkinned = true
|
||||||
GameMenuButtonRatings,
|
end
|
||||||
GameMenuButtonLogout,
|
end
|
||||||
GameMenuButtonQuit,
|
|
||||||
GameMenuButtonContinue,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, button in pairs(buttons) do
|
|
||||||
if button then SkinButton(button) end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
SkinMenuButtons()
|
||||||
|
GameMenuFrame:HookScript("OnShow", SkinMenuButtons)
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
pfUI:RegisterSkin("Options - Interface", function ()
|
||||||
|
local rawborder, border = GetBorderSize()
|
||||||
|
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
|
||||||
|
local cr, cg, cb = PFUI_CLASS_COLORS[UnitClassBase("player")]:GetRGB()
|
||||||
|
|
||||||
|
StripTextures(InterfaceOptionsFrame)
|
||||||
|
CreateBackdrop(InterfaceOptionsFrame, nil, nil, .75)
|
||||||
|
CreateBackdropShadow(InterfaceOptionsFrame)
|
||||||
|
|
||||||
|
local title = GetNoNameObject(InterfaceOptionsFrame, "FontString", "ARTWORK", ADDON_OPTIONS)
|
||||||
|
title:ClearAllPoints()
|
||||||
|
title:SetPoint("TOP", InterfaceOptionsFrame, "TOP", 0, -10)
|
||||||
|
|
||||||
|
CreateBackdrop(InterfaceOptionsFrameAddOns, nil, true, .75)
|
||||||
|
CreateBackdrop(InterfaceOptionsFramePanelContainer, nil, true, .75)
|
||||||
|
SkinScrollbar(InterfaceOptionsFrameAddOnsListScrollBar)
|
||||||
|
|
||||||
|
for _, button in ipairs(InterfaceOptionsFrameAddOns.buttons) do
|
||||||
|
button:GetHighlightTexture():SetTexture(cr, cg, cb, .25)
|
||||||
|
|
||||||
|
-- the list update swaps plus/minus textures on the toggle by path
|
||||||
|
local toggle = _G[button:GetName() .. "Toggle"]
|
||||||
|
SkinCollapseButton(toggle)
|
||||||
|
toggle:SetPushedTexture("")
|
||||||
|
toggle:SetHighlightTexture("")
|
||||||
|
toggle.SetPushedTexture = function() end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ClassicAPI's own pages (Options\Panel.lua) number their controls
|
||||||
|
local i = 1
|
||||||
|
while _G["ClassicAPIOptionsControl" .. i] do
|
||||||
|
local control = _G["ClassicAPIOptionsControl" .. i]
|
||||||
|
local ctype = control:GetFrameType()
|
||||||
|
if ctype == "CheckButton" then
|
||||||
|
SkinCheckbox(control)
|
||||||
|
elseif ctype == "Slider" then
|
||||||
|
SkinSlider(control)
|
||||||
|
else
|
||||||
|
SkinDropDown(control, nil, nil, nil, true)
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
SkinButton(InterfaceOptionsFrameDefaults)
|
||||||
|
SkinButton(InterfaceOptionsFrameCancel)
|
||||||
|
SkinButton(InterfaceOptionsFrameOkay)
|
||||||
|
InterfaceOptionsFrameOkay:ClearAllPoints()
|
||||||
|
InterfaceOptionsFrameOkay:SetPoint("RIGHT", InterfaceOptionsFrameCancel, "LEFT", -2*bpad, 0)
|
||||||
|
end)
|
||||||
@@ -2,19 +2,19 @@ pfUI:RegisterSkin("Quest Log", function ()
|
|||||||
local rawborder, border = GetBorderSize()
|
local rawborder, border = GetBorderSize()
|
||||||
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
|
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
|
||||||
|
|
||||||
_G.QUESTS_DISPLAYED = 23
|
_G.QUESTS_DISPLAYED = 22
|
||||||
_G.MAX_WATCHABLE_QUESTS = 20 -- TODO
|
_G.MAX_WATCHABLE_QUESTS = 20 -- TODO
|
||||||
|
|
||||||
do -- quest log frame
|
do -- quest log frame
|
||||||
QuestLogQuestCount:ClearAllPoints()
|
QuestLogQuestCount:ClearAllPoints()
|
||||||
QuestLogQuestCount:SetPoint("TOPRIGHT", -10, -30)
|
QuestLogQuestCount:SetPoint("TOPRIGHT", -10, -30)
|
||||||
|
|
||||||
hooksecurefunc("QuestLog_OnShow", function()
|
-- let the panel manager anchor this doublewide panel at 10, -114
|
||||||
QuestLogFrame:ClearAllPoints()
|
UIPanelWindows["QuestLogFrame"].xoffset = 10
|
||||||
QuestLogFrame:SetPoint("TOPLEFT", 10, -104)
|
UIPanelWindows["QuestLogFrame"].yoffset = -10
|
||||||
end)
|
|
||||||
|
|
||||||
QuestLogFrame:SetSize(676, 440)
|
-- match the 430px height and top edge of the other skinned panels
|
||||||
|
QuestLogFrame:SetSize(676, 430)
|
||||||
QuestLogFrame:DisableDrawLayer("BACKGROUND")
|
QuestLogFrame:DisableDrawLayer("BACKGROUND")
|
||||||
|
|
||||||
StripTextures(QuestLogFrame, true)
|
StripTextures(QuestLogFrame, true)
|
||||||
@@ -144,7 +144,7 @@ pfUI:RegisterSkin("Quest Log", function ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
QuestLogListScrollFrame:SetPoint("TOPLEFT", 10, -54)
|
QuestLogListScrollFrame:SetPoint("TOPLEFT", 10, -54)
|
||||||
QuestLogListScrollFrame:SetHeight(350)
|
QuestLogListScrollFrame:SetHeight(340)
|
||||||
|
|
||||||
hooksecurefunc("QuestLog_Update", function()
|
hooksecurefunc("QuestLog_Update", function()
|
||||||
local numEntries = GetNumQuestLogEntries()
|
local numEntries = GetNumQuestLogEntries()
|
||||||
@@ -181,8 +181,8 @@ pfUI:RegisterSkin("Quest Log", function ()
|
|||||||
|
|
||||||
QuestLogDetailScrollFrame:ClearAllPoints()
|
QuestLogDetailScrollFrame:ClearAllPoints()
|
||||||
QuestLogDetailScrollFrame:SetPoint("TOPLEFT", QuestLogListScrollFrame, "TOPRIGHT", 35, 0)
|
QuestLogDetailScrollFrame:SetPoint("TOPLEFT", QuestLogListScrollFrame, "TOPRIGHT", 35, 0)
|
||||||
QuestLogDetailScrollFrame:SetHeight(376)
|
QuestLogDetailScrollFrame:SetHeight(366)
|
||||||
QuestLogDetailScrollChildFrame:SetHeight(376)
|
QuestLogDetailScrollChildFrame:SetHeight(366)
|
||||||
|
|
||||||
local bg = QuestLogDetailScrollFrame:CreateTexture(nil, "BACKGROUND")
|
local bg = QuestLogDetailScrollFrame:CreateTexture(nil, "BACKGROUND")
|
||||||
bg:SetAllPoints()
|
bg:SetAllPoints()
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ pfUI:RegisterSkin("Spellbook", function ()
|
|||||||
CreateBackdrop(SpellBookFrame, nil, nil, .75)
|
CreateBackdrop(SpellBookFrame, nil, nil, .75)
|
||||||
CreateBackdropShadow(SpellBookFrame)
|
CreateBackdropShadow(SpellBookFrame)
|
||||||
|
|
||||||
SpellBookFrame.backdrop:SetPoint("TOPLEFT", 12, -12)
|
SpellBookFrame.backdrop:SetPoint("TOPLEFT", 10, -10)
|
||||||
SpellBookFrame.backdrop:SetPoint("BOTTOMRIGHT", -30, 72)
|
SpellBookFrame.backdrop:SetPoint("BOTTOMRIGHT", -30, 72)
|
||||||
SpellBookFrame:SetHitRectInsets(12,30,12,72)
|
SpellBookFrame:SetHitRectInsets(10,30,10,72)
|
||||||
EnableMovable(SpellBookFrame)
|
EnableMovable(SpellBookFrame)
|
||||||
|
|
||||||
SpellBookTitleText:ClearAllPoints()
|
SpellBookTitleText:ClearAllPoints()
|
||||||
|
|||||||
@@ -22,9 +22,16 @@ pfUI:RegisterSkin("Pet Stable Master", function ()
|
|||||||
PetStablePetInfo:ClearAllPoints()
|
PetStablePetInfo:ClearAllPoints()
|
||||||
PetStablePetInfo:SetPoint("TOPLEFT", PetStableModel, "TOPLEFT", 10, 0)
|
PetStablePetInfo:SetPoint("TOPLEFT", PetStableModel, "TOPLEFT", 10, 0)
|
||||||
|
|
||||||
local buttons = {"PetStableCurrentPet", "PetStableStabledPet1", "PetStableStabledPet2"}
|
-- Servers differ in stable size (Turtle WoW has 4 slots), so collect
|
||||||
for _,v in pairs(buttons) do
|
-- every PetStableStabledPetN the client created.
|
||||||
local button = _G[v]
|
local buttons = { PetStableCurrentPet }
|
||||||
|
local i = 1
|
||||||
|
while _G["PetStableStabledPet"..i] do
|
||||||
|
table.insert(buttons, _G["PetStableStabledPet"..i])
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, button in pairs(buttons) do
|
||||||
StripTextures(button)
|
StripTextures(button)
|
||||||
SkinButton(button, nil, nil, nil, _G[button:GetName().."IconTexture"])
|
SkinButton(button, nil, nil, nil, _G[button:GetName().."IconTexture"])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user