mirror of
https://github.com/brues-code/pfUI.git
synced 2026-09-22 15:46:56 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1108746949 | |||
| 38b4100353 | |||
| f497c71523 | |||
| 8e109a585a | |||
| 83f89be14a | |||
| e59158764c |
+1
-1
@@ -13,7 +13,7 @@ do
|
||||
-- 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
|
||||
-- errors aren't a mystery.
|
||||
local PFUI_CLASSIC_API_MIN = 11304 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_MIN = 11500 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
# pfUI - ClassicAPI Edition
|
||||
|
||||
[](https://octowow.st/)
|
||||
[](https://github.com/brues-code/ClassicAPI)
|
||||
[](https://github.com/brues-code/nampower)
|
||||
[](https://github.com/balakethelock/SuperWoW)
|
||||
[](https://github.com/brues-code/UnitXP_SP3)
|
||||
|
||||
**A pfUI fork specifically optimized for ClassicAPI on [Octo WoW](https://octowow.st/)**
|
||||
|
||||
This version includes significant performance improvements and DLL-enhanced features.
|
||||
|
||||
## Installation
|
||||
@@ -18,7 +15,7 @@ This version includes significant performance improvements and DLL-enhanced feat
|
||||
|
||||
## DLL Enhancements
|
||||
|
||||
Since pfUI 6.0.0 includes integrations with client-side DLLs for enhanced functionality. These DLLs are permitted on Octo WoW:
|
||||
Since pfUI 6.0.0 includes integrations with client-side DLLs for enhanced functionality:
|
||||
|
||||
### [ClassicAPI](https://github.com/brues-code/ClassicAPI)
|
||||
|
||||
|
||||
+26
@@ -1333,6 +1333,32 @@ function pfUI.api.CreateBackdropShadow(f)
|
||||
f.backdrop_shadow:SetBackdropBorderColor(0, 0, 0, tonumber(pfUI_config.appearance.border.shadow_intensity))
|
||||
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 ] --
|
||||
-- 'barsize' size of bar in number of buttons
|
||||
-- returns: array of options as strings for pfUI.gui.bar
|
||||
|
||||
+1
-1
@@ -156,6 +156,7 @@ function pfUI:LoadConfig()
|
||||
pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8")
|
||||
pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8")
|
||||
pfUI:UpdateConfig("appearance", "castbar", "failcolor", "1,.2,.2,.8")
|
||||
pfUI:UpdateConfig("appearance", "castbar", "shieldcolor", ".8,.45,.45,.8")
|
||||
pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar")
|
||||
pfUI:UpdateConfig("appearance", "infight", "screen", "0")
|
||||
pfUI:UpdateConfig("appearance", "infight", "aggro", "0")
|
||||
@@ -645,7 +646,6 @@ function pfUI:LoadConfig()
|
||||
pfUI:UpdateConfig("bars", nil, "animation", "zoomfade")
|
||||
pfUI:UpdateConfig("bars", nil, "animmode", "keypress")
|
||||
pfUI:UpdateConfig("bars", nil, "animalways", "0")
|
||||
pfUI:UpdateConfig("bars", nil, "macroscan", "1")
|
||||
pfUI:UpdateConfig("bars", nil, "reagents", "1")
|
||||
pfUI:UpdateConfig("bars", nil, "hunterbar", "0")
|
||||
pfUI:UpdateConfig("bars", nil, "pagemasteralt", "0")
|
||||
|
||||
+193
-168
@@ -35,14 +35,38 @@ pfUI.api.RegisterSlashCommand("PFTEST", { "/pftest", "/pfuftest" }, function()
|
||||
if pfUI.uf.raid and pfUI.uf.raid.LayoutPets then pfUI.uf.raid:LayoutPets() end
|
||||
end, true)
|
||||
|
||||
-- HoT buff indicators that need name verification because their icons are
|
||||
-- reused by other spells. Maps icon (lowercased) → expected aura name +
|
||||
-- libpredict key for the prediction integration.
|
||||
local HOT_INDICATORS = {
|
||||
[strlower(C_Spell.GetSpellTexture(774))] = { name = strlower(C_Spell.GetSpellName(774)), predict = "Reju" },
|
||||
[strlower(C_Spell.GetSpellTexture(139))] = { name = strlower(C_Spell.GetSpellName(139)), predict = "Renew" },
|
||||
[strlower(C_Spell.GetSpellTexture(8936))] = { name = strlower(C_Spell.GetSpellName(8936)), predict = "Regr" },
|
||||
}
|
||||
-- Buff indicators are identified by a spell id, resolved once into the aura's
|
||||
-- localized name plus its icon. A match needs both to agree.
|
||||
--
|
||||
-- Icon alone is ambiguous: Spell.dbc reuses icons across unrelated spells, so
|
||||
-- an icon-only filter lights the indicator for the wrong buff (Blessing of
|
||||
-- Sanctuary shares its icon with Lightning Shield and Shadowguard, Blessing of
|
||||
-- Kings with Mage Armor and Commanding Shout, Totemic Power with the Blessed
|
||||
-- Sunfruit food buff). Name alone is ambiguous too -- creature and item auras
|
||||
-- reuse player spell names ("Renew", "Rejuvenation", "Fire Resistance").
|
||||
--
|
||||
-- Every rank of a spell carries the same name and icon, so one id per buff
|
||||
-- covers the whole rank ladder. Ids missing from this client resolve to nil and
|
||||
-- drop out of the list. 'predict' names the libpredict key of a HoT.
|
||||
--
|
||||
-- Both fields are stored raw, and RefreshUnit compares them raw. The aura's
|
||||
-- name and icon and these come out of the same DBC records byte for byte --
|
||||
-- Spell.dbc's localized name, SpellIcon.dbc's path -- so case folding either
|
||||
-- side would only burn a string per aura per scan. Feed this ids, never
|
||||
-- hand-written names or icon paths, or that equality quietly stops holding.
|
||||
local indicator_cache = {}
|
||||
local function AddIndicator(indicators, spellId, predict)
|
||||
local record = indicator_cache[spellId]
|
||||
if record == nil then
|
||||
local name = C_Spell.GetSpellName(spellId)
|
||||
local icon = name and C_Spell.GetSpellTexture(spellId)
|
||||
-- cache misses as false, so an absent spell is only looked up once
|
||||
record = icon and { name = name, icon = icon, predict = predict } or false
|
||||
indicator_cache[spellId] = record
|
||||
end
|
||||
|
||||
if record then table.insert(indicators, record) end
|
||||
end
|
||||
|
||||
local glow = {
|
||||
edgeFile = pfUI.media["img:glow"], edgeSize = 8,
|
||||
@@ -289,9 +313,10 @@ function pfUI.uf:UpdateVisibility()
|
||||
self._label, self._id = nil, nil
|
||||
end
|
||||
|
||||
local unitstr = string.format("%s%s", self.label or "", self.id or "")
|
||||
self:SetAttribute("unit", unitstr ~= "" and unitstr or nil)
|
||||
local visibility = string.format("[target=%s,exists] show; hide", unitstr)
|
||||
local unitstr = ("%s%s"):format(self.label or "", self.id or "")
|
||||
self.unitstr = unitstr ~= "" and unitstr or nil
|
||||
self:SetAttribute("unit", self.unitstr)
|
||||
local visibility = ("[target=%s,exists] show; hide"):format(unitstr)
|
||||
|
||||
-- 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
|
||||
@@ -320,6 +345,15 @@ function pfUI.uf:UpdateVisibility()
|
||||
self.visible = nil
|
||||
end
|
||||
|
||||
-- This is the single place a frame's unit is ever assigned, so it is also the
|
||||
-- place its subscriptions follow it to: the engine then delivers only this
|
||||
-- unit's events, and OnEvent compares against the cached string instead of
|
||||
-- rebuilding label..id -- and calling UnitGUID -- for every unit event fired
|
||||
-- by anything, anywhere. A frame that is not in use drops them entirely; the
|
||||
-- roster events that would bring it back are registered plainly, and
|
||||
-- visibilityscan re-runs this every 0.2s regardless, so it recovers on its own.
|
||||
self:RegisterUnitEvents(visibility ~= "hide" and self.unitstr or nil)
|
||||
|
||||
-- vanilla visibility
|
||||
if self.unitname then
|
||||
self:Show()
|
||||
@@ -600,11 +634,14 @@ function pfUI.uf:UpdateConfig()
|
||||
f.feedbackText:ClearAllPoints()
|
||||
f.feedbackText:SetPoint("CENTER", f.portrait, "CENTER")
|
||||
end
|
||||
f:RegisterEvent("UNIT_COMBAT")
|
||||
f.combatfeedback = true
|
||||
else
|
||||
f.feedbackText:Hide()
|
||||
f:UnregisterEvent("UNIT_COMBAT")
|
||||
f.combatfeedback = nil
|
||||
end
|
||||
-- RegisterUnitEvents owns UNIT_COMBAT; clearing the cached unit makes the
|
||||
-- next UpdateVisibility re-run it against the new combatfeedback state.
|
||||
f.eventunit = nil
|
||||
|
||||
f.hpLeftText:SetFontObject(GameFontWhite)
|
||||
f.hpLeftText:SetFont(fontname, fontsize, fontstyle)
|
||||
@@ -894,6 +931,9 @@ function pfUI.uf:UpdateConfig()
|
||||
f:UpdateFrameSize()
|
||||
else
|
||||
f:UnregisterAllEvents()
|
||||
-- that dropped the unit filters along with the registrations, so the cache
|
||||
-- has to go too or the next UpdateVisibility believes they are still set
|
||||
f.eventunit = nil
|
||||
f:Hide()
|
||||
end
|
||||
end
|
||||
@@ -935,6 +975,10 @@ function pfUI.uf.OnEvent()
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
this:SetScript("OnUpdate", nil)
|
||||
-- visibilityscan is a separate frame and keeps ticking, so leaving this one
|
||||
-- on its list would have UpdateVisibility re-register the unit events we
|
||||
-- just dropped -- straight back into the crash 132 this branch prevents
|
||||
visibilityscan.frames[this] = nil
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1001,8 +1045,12 @@ function pfUI.uf.OnEvent()
|
||||
this.update_aura = true
|
||||
elseif this.label == "pet" and event == "UNIT_HAPPINESS" then
|
||||
this.update_full = true
|
||||
-- UNIT_XXX Events
|
||||
elseif arg1 and (arg1 == this.label .. this.id or (UnitGUID and arg1 == UnitGUID(this.label .. this.id))) then
|
||||
-- UNIT_XXX Events. RegisterUnitEvents means arg1 can only be this frame's own
|
||||
-- unit; the compare is kept for the case the filter sits out, which is when
|
||||
-- arg1 is not a string. The old GUID alternative is gone: these events fire
|
||||
-- once per token that resolves to the unit AND once with the raw GUID, so the
|
||||
-- token form always arrives and the GUID form was only ever a duplicate wake.
|
||||
elseif arg1 and arg1 == this.unitstr then
|
||||
if event == "UNIT_PORTRAIT_UPDATE" or event == "UNIT_MODEL_CHANGED" then
|
||||
this.update_portrait = true
|
||||
elseif event == "UNIT_AURA" then
|
||||
@@ -1227,25 +1275,56 @@ function pfUI.uf.OnUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
-- The unit events whose arg1 is the frame's OWN unit -- everything the OnEvent
|
||||
-- routes through its "UNIT_XXX Events" branch. These are not registered here:
|
||||
-- UpdateVisibility owns them, because it owns the frame's unit (below).
|
||||
--
|
||||
-- UNIT_PET and UNIT_HAPPINESS are deliberately absent. Their branches key on
|
||||
-- the frame's label, and UNIT_PET's arg1 is the pet's OWNER ("player" for a
|
||||
-- "pet" frame), so filtering them by the frame's own unit would drop them.
|
||||
local UNIT_EVENTS = {
|
||||
"UNIT_DISPLAYPOWER",
|
||||
"UNIT_HEALTH", "UNIT_MAXHEALTH",
|
||||
"UNIT_MANA", "UNIT_MAXMANA",
|
||||
"UNIT_RAGE", "UNIT_MAXRAGE",
|
||||
"UNIT_ENERGY", "UNIT_MAXENERGY",
|
||||
"UNIT_FOCUS",
|
||||
"UNIT_PORTRAIT_UPDATE", "UNIT_MODEL_CHANGED",
|
||||
"UNIT_FACTION",
|
||||
"UNIT_AURA", -- frame=buff, frame=debuff
|
||||
}
|
||||
|
||||
-- Point this frame's unit-event subscriptions at `unitstr`, or drop them when
|
||||
-- the frame has no unit. Cheap to call repeatedly: it no-ops unless the unit
|
||||
-- actually changed, which matters because visibilityscan runs UpdateVisibility
|
||||
-- for every frame five times a second.
|
||||
function pfUI.uf:RegisterUnitEvents(unitstr)
|
||||
if self.eventunit == unitstr then return end
|
||||
self.eventunit = unitstr
|
||||
|
||||
for i = 1, table.getn(UNIT_EVENTS) do
|
||||
if unitstr then
|
||||
self:RegisterUnitEvent(UNIT_EVENTS[i], unitstr)
|
||||
else
|
||||
self:UnregisterEvent(UNIT_EVENTS[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- UNIT_COMBAT rides along only while the frame draws combat feedback text.
|
||||
-- UpdateConfig clears eventunit when it toggles that, so the next
|
||||
-- UpdateVisibility re-runs this.
|
||||
if unitstr and self.combatfeedback then
|
||||
self:RegisterUnitEvent("UNIT_COMBAT", unitstr)
|
||||
else
|
||||
self:UnregisterEvent("UNIT_COMBAT")
|
||||
end
|
||||
end
|
||||
|
||||
function pfUI.uf:EnableEvents()
|
||||
local f = self
|
||||
|
||||
f:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
f:RegisterEvent("PLAYER_LOGOUT")
|
||||
f:RegisterEvent("UNIT_DISPLAYPOWER")
|
||||
f:RegisterEvent("UNIT_HEALTH")
|
||||
f:RegisterEvent("UNIT_MAXHEALTH")
|
||||
f:RegisterEvent("UNIT_MANA")
|
||||
f:RegisterEvent("UNIT_MAXMANA")
|
||||
f:RegisterEvent("UNIT_RAGE")
|
||||
f:RegisterEvent("UNIT_MAXRAGE")
|
||||
f:RegisterEvent("UNIT_ENERGY")
|
||||
f:RegisterEvent("UNIT_MAXENERGY")
|
||||
f:RegisterEvent("UNIT_FOCUS")
|
||||
f:RegisterEvent("UNIT_PORTRAIT_UPDATE")
|
||||
f:RegisterEvent("UNIT_MODEL_CHANGED")
|
||||
f:RegisterEvent("UNIT_FACTION")
|
||||
f:RegisterEvent("UNIT_AURA") -- frame=buff, frame=debuff
|
||||
f:RegisterEvent("PLAYER_AURAS_CHANGED") -- label=player && frame=buff
|
||||
f:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- label=player && frame=buff (ClassicAPI: weapon-enchant buffs)
|
||||
f:RegisterEvent("PARTY_MEMBERS_CHANGED") -- label=party, frame=leaderIcon
|
||||
@@ -1363,6 +1442,7 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
||||
f.UpdateConfig = pfUI.uf.UpdateConfig
|
||||
f.EnableScripts = pfUI.uf.EnableScripts
|
||||
f.EnableEvents = pfUI.uf.EnableEvents
|
||||
f.RegisterUnitEvents = pfUI.uf.RegisterUnitEvents
|
||||
f.EnableClickCast = pfUI.uf.EnableClickCast
|
||||
f.GetColor = pfUI.uf.GetColor
|
||||
|
||||
@@ -1479,6 +1559,9 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
||||
f:UpdateFrameSize()
|
||||
else
|
||||
f:UnregisterAllEvents()
|
||||
-- that dropped the unit filters along with the registrations, so the cache
|
||||
-- has to go too or the next UpdateVisibility believes they are still set
|
||||
f.eventunit = nil
|
||||
f:Hide()
|
||||
end
|
||||
|
||||
@@ -1939,7 +2022,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
if not unit.indicator_custom and unit.config.buff_indicator == "1" then
|
||||
unit.indicator_custom = {}
|
||||
for k, v in pairs({strsplit("#", unit.config.custom_indicator)}) do
|
||||
unit.indicator_custom[k] = string.lower(v)
|
||||
unit.indicator_custom[k] = v:lower()
|
||||
end
|
||||
elseif not unit.indicator_custom then
|
||||
unit.indicator_custom = {}
|
||||
@@ -1951,17 +2034,12 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
for i=1,n do
|
||||
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
|
||||
if not name then break end
|
||||
local texLower = string.lower(icon)
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
|
||||
for _, filter in pairs(unit.indicators) do
|
||||
if filter == texLower then
|
||||
local hot = HOT_INDICATORS[texLower]
|
||||
if hot and string.lower(name) ~= hot.name then
|
||||
break -- texture matches but name disambiguates (e.g. shared icon)
|
||||
end
|
||||
if hot then
|
||||
local start, duration, prediction = libpredict:GetHotDuration(unitstr, hot.predict)
|
||||
if filter.icon == icon and filter.name == name then
|
||||
if filter.predict then
|
||||
local start, duration, prediction = libpredict:GetHotDuration(unitstr, filter.predict)
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft or prediction, count, tonumber(start), tonumber(duration))
|
||||
else
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
@@ -1979,7 +2057,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
|
||||
if not name then break end
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
local lowerName = string.lower(name)
|
||||
local lowerName = name:lower()
|
||||
for _, filter in pairs(unit.indicator_custom) do
|
||||
if filter == lowerName then
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
@@ -1996,7 +2074,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
if name then
|
||||
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
|
||||
for _, filter in pairs(unit.indicator_custom) do
|
||||
if filter == string.lower(name) then
|
||||
if filter == name:lower() then
|
||||
pfUI.uf:AddIcon(unit, pos, icon, timeleft, count)
|
||||
pos = pos + 1
|
||||
break
|
||||
@@ -2205,17 +2283,17 @@ function pfUI.uf:EnableClickCast()
|
||||
local action = pfUI_config.unitframes["clickcast"..bconf..mconf]
|
||||
if action and action ~= "" then
|
||||
local prefix = modifier ~= "" and (modifier .. "-") or ""
|
||||
local low = string.lower(action)
|
||||
local low = action:lower()
|
||||
if low == "menu" then
|
||||
self:SetAttribute(prefix .. "type" .. bid, "menu")
|
||||
elseif low == "target" then
|
||||
self:SetAttribute(prefix .. "type" .. bid, "target")
|
||||
elseif low == "focus" then
|
||||
self:SetAttribute(prefix .. "type" .. bid, "focus")
|
||||
elseif string.find(low, "^macro:") then
|
||||
elseif low:find("^macro:") then
|
||||
self:SetAttribute(prefix .. "type" .. bid, "macro")
|
||||
self:SetAttribute(prefix .. "macro" .. bid, string.gsub(string.sub(action, 7), "^%s+", ""))
|
||||
elseif string.find(action, "^/") then
|
||||
self:SetAttribute(prefix .. "macro" .. bid, action:sub(7):gsub("^%s+", ""))
|
||||
elseif action:find("^/") then
|
||||
self:SetAttribute(prefix .. "type" .. bid, "macro")
|
||||
self:SetAttribute(prefix .. "macrotext" .. bid, action)
|
||||
else
|
||||
@@ -2353,175 +2431,122 @@ function pfUI.uf:SetupBuffIndicators(config)
|
||||
|
||||
if config.show_buffs == "1" then -- buffs
|
||||
if myclass == "DRUID" then
|
||||
-- Mark of the Wild
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_regeneration")
|
||||
-- Gift of the Wild
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_giftofthewild")
|
||||
-- Thorns
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_thorns")
|
||||
AddIndicator(indicators, 1126) -- Mark of the Wild
|
||||
AddIndicator(indicators, 21849) -- Gift of the Wild
|
||||
AddIndicator(indicators, 467) -- Thorns
|
||||
end
|
||||
|
||||
if myclass == "PRIEST" then
|
||||
-- Prayer Of Fortitude"
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_wordfortitude")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_prayeroffortitude")
|
||||
-- Prayer of Spirit
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_divinespirit")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_prayerofspirit")
|
||||
-- Shadow Protection
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_antishadow")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_prayerofshadowprotection")
|
||||
-- Fear Ward
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_excorcism")
|
||||
AddIndicator(indicators, 1243) -- Power Word: Fortitude
|
||||
AddIndicator(indicators, 21562) -- Prayer of Fortitude
|
||||
AddIndicator(indicators, 6386) -- Divine Spirit
|
||||
AddIndicator(indicators, 27681) -- Prayer of Spirit
|
||||
AddIndicator(indicators, 976) -- Shadow Protection
|
||||
AddIndicator(indicators, 27683) -- Prayer of Shadow Protection
|
||||
AddIndicator(indicators, 6346) -- Fear Ward
|
||||
end
|
||||
|
||||
if myclass == "PALADIN" then
|
||||
-- Blessing of Salvation
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_greaterblessingofsalvation")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_sealofsalvation")
|
||||
-- Blessing of Wisdom
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_sealofwisdom")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_greaterblessingofwisdom")
|
||||
-- Blessing of Sanctuary
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_lightningshield")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_greaterblessingofsanctuary")
|
||||
-- Blessing of Kings
|
||||
table.insert(indicators, "interface\\icons\\spell_magic_magearmor")
|
||||
table.insert(indicators, "interface\\icons\\spell_magic_greaterblessingofkings")
|
||||
-- Blessing of Might
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_fistofjustice")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_greaterblessingofkings")
|
||||
-- Blessing of Light
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_prayerofhealing02")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_greaterblessingoflight")
|
||||
-- Blessing of Sacrifice
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_sealofsacrifice")
|
||||
-- Blessing of Freedom
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_sealofvalor")
|
||||
-- Blessing of Protection
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_sealofprotection")
|
||||
AddIndicator(indicators, 1038) -- Blessing of Salvation
|
||||
AddIndicator(indicators, 25895) -- Greater Blessing of Salvation
|
||||
AddIndicator(indicators, 19742) -- Blessing of Wisdom
|
||||
AddIndicator(indicators, 25894) -- Greater Blessing of Wisdom
|
||||
AddIndicator(indicators, 20204) -- Blessing of Sanctuary
|
||||
AddIndicator(indicators, 25899) -- Greater Blessing of Sanctuary
|
||||
AddIndicator(indicators, 20217) -- Blessing of Kings
|
||||
AddIndicator(indicators, 25898) -- Greater Blessing of Kings
|
||||
AddIndicator(indicators, 19740) -- Blessing of Might
|
||||
AddIndicator(indicators, 25782) -- Greater Blessing of Might
|
||||
AddIndicator(indicators, 19977) -- Blessing of Light
|
||||
AddIndicator(indicators, 25890) -- Greater Blessing of Light
|
||||
AddIndicator(indicators, 6940) -- Hand of Sacrifice
|
||||
AddIndicator(indicators, 45801) -- Greater Blessing of Sacrifice
|
||||
AddIndicator(indicators, 1044) -- Hand of Freedom
|
||||
AddIndicator(indicators, 1022) -- Hand of Protection
|
||||
end
|
||||
|
||||
if myclass == "WARLOCK" then
|
||||
-- Fire Shield
|
||||
table.insert(indicators, "interface\\icons\\spell_fire_firearmor")
|
||||
-- Blood Pact
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_bloodboil")
|
||||
-- Soulstone
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_soulgem")
|
||||
-- Unending Breath
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_demonbreath")
|
||||
-- Detect Greater Invisibility or Detect Invisibility
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_detectinvisibility")
|
||||
-- Detect Lesser Invisibility
|
||||
table.insert(indicators, "interface\\icons\\spell_shadow_detectlesserinvisibility")
|
||||
-- Paranoia
|
||||
table.insert(indicators, "interface\\icons\\Spell_Shadow_AuraOfDarkness")
|
||||
AddIndicator(indicators, 1167) -- Fire Shield
|
||||
AddIndicator(indicators, 6307) -- Blood Pact
|
||||
AddIndicator(indicators, 20707) -- Soulstone Resurrection
|
||||
AddIndicator(indicators, 5697) -- Unending Breath
|
||||
AddIndicator(indicators, 2970) -- Detect Invisibility
|
||||
AddIndicator(indicators, 11743) -- Detect Greater Invisibility
|
||||
AddIndicator(indicators, 132) -- Detect Lesser Invisibility
|
||||
AddIndicator(indicators, 19480) -- Paranoia
|
||||
end
|
||||
|
||||
if myclass == "WARRIOR" then
|
||||
-- Battle Shout
|
||||
table.insert(indicators, "interface\\icons\\ability_warrior_battleshout")
|
||||
-- Commanding Shout (TBC)
|
||||
table.insert(indicators, "interface\\icons\\ability_warrior_rallyingcry")
|
||||
AddIndicator(indicators, 5242) -- Battle Shout
|
||||
AddIndicator(indicators, 45580) -- Commanding Shout
|
||||
end
|
||||
|
||||
if myclass == "MAGE" then
|
||||
-- Arcane Intellect
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_magicalsentry")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_arcaneintellect")
|
||||
-- Dampen Magic
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_abolishmagic")
|
||||
-- Amplify Magic
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_flashheal")
|
||||
AddIndicator(indicators, 1459) -- Arcane Intellect
|
||||
AddIndicator(indicators, 23028) -- Arcane Brilliance
|
||||
AddIndicator(indicators, 604) -- Dampen Magic
|
||||
AddIndicator(indicators, 1008) -- Amplify Magic
|
||||
end
|
||||
|
||||
if myclass == "HUNTER" then
|
||||
-- Aspect of the Wild
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_protectionformnature")
|
||||
|
||||
-- Aspect of the Pack
|
||||
table.insert(indicators, "interface\\icons\\ability_mount_whitetiger")
|
||||
|
||||
-- Misdirection (TBC)
|
||||
table.insert(indicators, "interface\\icons\\ability_hunter_misdirection")
|
||||
AddIndicator(indicators, 20043) -- Aspect of the Wild
|
||||
AddIndicator(indicators, 13159) -- Aspect of the Pack
|
||||
end
|
||||
|
||||
if myclass == "SHAMAN" then
|
||||
-- Earth Shield (TBC)
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_skinofearth")
|
||||
AddIndicator(indicators, 45525) -- Earth Shield
|
||||
end
|
||||
end
|
||||
|
||||
if config.show_procs == "1" then -- procs
|
||||
if myclass == "SHAMAN" or config.all_procs == "1" then
|
||||
-- Ancestral Fortitude
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_undyingstrength")
|
||||
-- Healing Way
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_healingway")
|
||||
-- Totemic Power (known issue: one conflicts with Blessed Sunfruit buff)
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_spiritualguidence")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_devotion")
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_holynova")
|
||||
table.insert(indicators, "interface\\icons\\spell_magic_magearmor")
|
||||
AddIndicator(indicators, 16177) -- Ancestral Fortitude
|
||||
AddIndicator(indicators, 29202) -- Healing Way
|
||||
-- Totemic Power is four auras, one per totem school, each with its own icon
|
||||
AddIndicator(indicators, 28824)
|
||||
AddIndicator(indicators, 28825)
|
||||
AddIndicator(indicators, 28826)
|
||||
AddIndicator(indicators, 28827)
|
||||
end
|
||||
|
||||
if myclass == "PRIEST" or config.all_procs == "1" then
|
||||
-- Inspiration
|
||||
table.insert(indicators, "interface\\icons\\inv_shield_06")
|
||||
AddIndicator(indicators, 14893) -- Inspiration
|
||||
end
|
||||
end
|
||||
|
||||
if config.show_hots == "1" then -- hots
|
||||
if myclass == "PRIEST" or config.all_hots == "1" then
|
||||
-- Renew
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_renew")
|
||||
-- Power Word: Shield
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_powerwordshield")
|
||||
-- Prayer of Mending (TBC)
|
||||
table.insert(indicators, "interface\\icons\\spell_holy_prayerofmendingtga")
|
||||
AddIndicator(indicators, 139, "Renew") -- Renew
|
||||
AddIndicator(indicators, 17) -- Power Word: Shield
|
||||
end
|
||||
|
||||
if myclass == "DRUID" or config.all_hots == "1" then
|
||||
-- Regrowth
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_resistnature")
|
||||
-- Rejuvenation
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_rejuvenation")
|
||||
-- Lifebloom
|
||||
table.insert(indicators, "interface\\icons\\inv_misc_herb_felblossom")
|
||||
AddIndicator(indicators, 8936, "Regr") -- Regrowth
|
||||
AddIndicator(indicators, 774, "Reju") -- Rejuvenation
|
||||
end
|
||||
end
|
||||
|
||||
if config.show_totems == "1" and myclass == "SHAMAN" then -- totems
|
||||
-- Strength of Earth Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_earthbindtotem")
|
||||
-- Stoneskin Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_stoneskintotem")
|
||||
-- Mana Spring Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_manaregentotem")
|
||||
-- Mana Tide Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_frost_summonwaterelemental")
|
||||
-- Healing Spring Totem
|
||||
table.insert(indicators, "interface\\icons\\inv_spear_04")
|
||||
-- Tranquil Air Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_brilliance")
|
||||
-- Grace of Air Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_invisibilitytotem")
|
||||
-- Grounding Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_groundingtotem")
|
||||
-- Nature Resistance Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_nature_natureresistancetotem")
|
||||
-- Fire Resistance Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_fireresistancetotem_01")
|
||||
-- Frost Resistance Totem
|
||||
table.insert(indicators, "interface\\icons\\spell_frostresistancetotem_01")
|
||||
-- the aura each totem applies, not the cast that drops it: they share an
|
||||
-- icon but the totem's own name carries a " Totem" suffix the aura lacks
|
||||
AddIndicator(indicators, 8076) -- Strength of Earth
|
||||
AddIndicator(indicators, 8072) -- Stoneskin
|
||||
AddIndicator(indicators, 5677) -- Mana Spring
|
||||
AddIndicator(indicators, 16191) -- Mana Tide
|
||||
AddIndicator(indicators, 5672) -- Healing Stream
|
||||
AddIndicator(indicators, 25909) -- Tranquil Air
|
||||
AddIndicator(indicators, 8836) -- Grace of Air
|
||||
AddIndicator(indicators, 8177) -- Grounding Totem
|
||||
AddIndicator(indicators, 10596) -- Nature Resistance
|
||||
AddIndicator(indicators, 8185) -- Fire Resistance
|
||||
AddIndicator(indicators, 8182) -- Frost Resistance
|
||||
end
|
||||
|
||||
return indicators
|
||||
end
|
||||
|
||||
local function abbrevname(t)
|
||||
return string.sub(t,1,1)..". "
|
||||
return t:sub(1,1)..". "
|
||||
end
|
||||
|
||||
function pfUI.uf:GetNameString(unitstr)
|
||||
@@ -2531,12 +2556,12 @@ function pfUI.uf:GetNameString(unitstr)
|
||||
|
||||
-- first try to only abbreviate the first word
|
||||
if abbrev and name and strlen(name) > size then
|
||||
name = string.gsub(name, "^(%S+) ", abbrevname)
|
||||
name = name:gsub("^(%S+) ", abbrevname)
|
||||
end
|
||||
|
||||
-- abbreviate all if it still doesn't fit
|
||||
if abbrev and name and strlen(name) > size then
|
||||
name = string.gsub(name, "(%S+) ", abbrevname)
|
||||
name = name:gsub("(%S+) ", abbrevname)
|
||||
end
|
||||
|
||||
return name
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["deDE"] = {
|
||||
["Scale"] = nil,
|
||||
["Scale Border On HiDPI Displays"] = nil,
|
||||
["Scaling"] = nil,
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = nil,
|
||||
["Screen Resolution"] = nil,
|
||||
["Screenshot"] = nil,
|
||||
|
||||
Vendored
-1
@@ -683,7 +683,6 @@ pfUI_translation["enUS"] = {
|
||||
["Scale"] = nil,
|
||||
["Scale Border On HiDPI Displays"] = nil,
|
||||
["Scaling"] = nil,
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = nil,
|
||||
["Screen Resolution"] = nil,
|
||||
["Screenshot"] = nil,
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["esES"] = {
|
||||
["Scale"] = "Escala",
|
||||
["Scale Border On HiDPI Displays"] = "Escalar los bordes en las pantallas con DPI alto",
|
||||
["Scaling"] = "Escalada",
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = "Intensidad de brillo en los bordes de la pantalla",
|
||||
["Screen Resolution"] = "Resolución de pantalla",
|
||||
["Screenshot"] = "Captura de pantalla",
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["frFR"] = {
|
||||
["Scale"] = "Échelle",
|
||||
["Scale Border On HiDPI Displays"] = "Échelle de bordure sur les écrans HiDPI",
|
||||
["Scaling"] = "Mise à l'échelle",
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = nil,
|
||||
["Screen Resolution"] = "Résolution d'écran",
|
||||
["Screenshot"] = "Imprime écran",
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["koKR"] = {
|
||||
["Scale"] = nil,
|
||||
["Scale Border On HiDPI Displays"] = nil,
|
||||
["Scaling"] = nil,
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = nil,
|
||||
["Screen Resolution"] = "화면 해상도",
|
||||
["Screenshot"] = nil,
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["ruRU"] = {
|
||||
["Scale"] = "Масштаб",
|
||||
["Scale Border On HiDPI Displays"] = "Масштабировать границы на HiDPI мониторах",
|
||||
["Scaling"] = "Масштаб интерфейса",
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = "Интенсивность свечения на краях экрана",
|
||||
["Screen Resolution"] = "Разрешение экрана",
|
||||
["Screenshot"] = "Снимок экрана",
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["zhCN"] = {
|
||||
["Scale"] = "比例",
|
||||
["Scale Border On HiDPI Displays"] = "缩放高DPI显示器上的边框",
|
||||
["Scaling"] = "UI缩放",
|
||||
["Scan Macros For Spells"] = "扫描宏命令中的法术",
|
||||
["Screen Edge Glow Intensity"] = "屏幕边缘发光强度",
|
||||
["Screen Resolution"] = "屏幕分辨率",
|
||||
["Screenshot"] = "屏幕截图",
|
||||
|
||||
Vendored
-1
@@ -670,7 +670,6 @@ pfUI_translation["zhTW"] = {
|
||||
["Scale"] = "比例",
|
||||
["Scale Border On HiDPI Displays"] = nil,
|
||||
["Scaling"] = nil,
|
||||
["Scan Macros For Spells"] = nil,
|
||||
["Screen Edge Glow Intensity"] = nil,
|
||||
["Screen Resolution"] = "螢幕解析度",
|
||||
["Screenshot"] = nil,
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
<Include file="..\modules\addoncompat.lua"/>
|
||||
<Include file="..\modules\energytick.lua"/>
|
||||
<Include file="..\modules\totems.lua"/>
|
||||
<Include file="..\modules\macrotweak.lua"/>
|
||||
<Include file="..\modules\macroicons.lua"/>
|
||||
<Include file="..\modules\superwow.lua"/>
|
||||
<Include file="..\modules\innervatecall.lua"/>
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ local libhealth = CreateFrame("Frame")
|
||||
libhealth.enabled = true
|
||||
libhealth.reqhit = 4
|
||||
libhealth.reqdmg = 5
|
||||
libhealth:RegisterEvent("UNIT_HEALTH")
|
||||
libhealth:RegisterEvent("UNIT_COMBAT")
|
||||
libhealth:RegisterUnitEvent("UNIT_HEALTH", "target")
|
||||
libhealth:RegisterUnitEvent("UNIT_COMBAT", "target")
|
||||
libhealth:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
libhealth:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
libhealth:SetScript("OnEvent", function()
|
||||
|
||||
+1
-1
@@ -1134,7 +1134,7 @@ libpredict.sender:RegisterEvent("SPELL_HEAL_BY_SELF")
|
||||
libpredict.sender:RegisterEvent("SPELL_HEAL_BY_OTHER") -- populates foreignCache for other healers
|
||||
|
||||
-- force cache updates
|
||||
libpredict.sender:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
||||
libpredict.sender:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player")
|
||||
libpredict.sender:RegisterEvent("SKILL_LINES_CHANGED")
|
||||
|
||||
-- Shared cleanup helper for failed/interrupted casts
|
||||
|
||||
+23
-73
@@ -360,68 +360,6 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
end
|
||||
end
|
||||
|
||||
local function ButtonMacroScan(self)
|
||||
if self.bar > 10 then return end
|
||||
if not self.scanmacro then return end
|
||||
if pfUI.bars.skip_macro then return end
|
||||
|
||||
-- SuperCleveRoidMacros: for macros it manages, leave spellslot/booktype unset
|
||||
-- so the button's icon, cooldown, and tooltip flow through the hooked
|
||||
-- GetActionTexture / GetActionCooldown / GameTooltip:SetAction and follow the
|
||||
-- active conditional dynamically, instead of being frozen to the first
|
||||
-- statically-scanned spell.
|
||||
if CleveRoids and CleveRoids.IsManagedAction and CleveRoids.IsManagedAction(self.id) then
|
||||
self.spellslot, self.booktype, self.spellID = nil, nil, nil
|
||||
return
|
||||
end
|
||||
|
||||
local kind, slot = GetActionInfo(self.id)
|
||||
self.spellslot, self.booktype, self.spellID = nil, nil, nil
|
||||
if kind == 'macro' then
|
||||
local name, _, body = GetMacroInfo(slot)
|
||||
|
||||
if name and body then
|
||||
local match
|
||||
|
||||
for line in gfind(body, "[^%\n]+") do
|
||||
_, _, match = string.find(line, '^#showtooltip (.+)')
|
||||
|
||||
-- allow the user to disable the scan
|
||||
if match and strfind(match, "disable") then
|
||||
return
|
||||
end
|
||||
|
||||
if not match then
|
||||
-- add support to specify custom tooltips via:
|
||||
-- /run --showtooltip SPELLNAME
|
||||
_, _, match = string.find(line, '%-%-showtooltip (.+)')
|
||||
end
|
||||
|
||||
if not match then
|
||||
_, _, match = string.find(line, '^/cast (.+)')
|
||||
end
|
||||
|
||||
if not match then
|
||||
_, _, match = string.find(line, '^/pfcast (.+)')
|
||||
end
|
||||
|
||||
if not match then
|
||||
_, _, match = string.find(line, '^/pfmouse (.+)')
|
||||
end
|
||||
|
||||
if not match then
|
||||
_, _, match = string.find(line, 'CastSpellByName%(%"(.+)%"%)')
|
||||
end
|
||||
|
||||
if match then
|
||||
self.spellslot, self.booktype, self.spellID = select(7, libspell.GetSpellInfo(match))
|
||||
if self.spellslot and self.spellslot > 0 then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ButtonEnter(self)
|
||||
self = self or this
|
||||
|
||||
@@ -690,7 +628,6 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
local function ButtonFullUpdate(button)
|
||||
if not button then return end
|
||||
|
||||
ButtonMacroScan(button)
|
||||
ButtonSlotUpdate(button)
|
||||
ButtonRangeUpdate(button)
|
||||
ButtonUsableUpdate(button)
|
||||
@@ -807,10 +744,28 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
-- create the main event and update handler for pfUI actionbars
|
||||
local bars = CreateFrame("Frame", "pfActionBar", UIParent)
|
||||
for event in pairs(special_events) do bars:RegisterEvent(event) end
|
||||
for event in pairs(global_events) do bars:RegisterEvent(event) end
|
||||
for event in pairs(aura_events) do bars:RegisterEvent(event) end
|
||||
for event in pairs(pet_events) do bars:RegisterEvent(event) end
|
||||
|
||||
-- The only unit events in the tables above; both concern the player alone.
|
||||
-- A registration keeps its kind, so these have to go in unit-filtered from
|
||||
-- the start -- RegisterUnitEvent over a plain registration stays plain.
|
||||
local event_units = {
|
||||
["UNIT_INVENTORY_CHANGED"] = "player",
|
||||
["UNIT_PET"] = "player",
|
||||
}
|
||||
|
||||
local function RegisterBarEvent(event)
|
||||
local unit = event_units[event]
|
||||
if unit then
|
||||
bars:RegisterUnitEvent(event, unit)
|
||||
else
|
||||
bars:RegisterEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
for event in pairs(special_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(global_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(aura_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(pet_events) do RegisterBarEvent(event) end
|
||||
|
||||
-- refresh actionbar buttons on event
|
||||
bars:SetScript("OnEvent", BarsEvent)
|
||||
@@ -1148,12 +1103,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
f.count:SetJustifyH("RIGHT")
|
||||
f.count:SetJustifyV("BOTTOM")
|
||||
|
||||
-- macro spell scan (disabled when macro addons are loaded)
|
||||
if C.bars.macroscan == "0" or pfUI:MacroAddonsLoaded() then
|
||||
f.scanmacro, f.spellslot, f.booktype = nil, nil, nil
|
||||
else
|
||||
f.scanmacro = true
|
||||
end
|
||||
f.scanmacro, f.spellslot, f.booktype = nil, nil, nil
|
||||
|
||||
-- range glow color
|
||||
f.rangeColor = GetStringColorObject(C.bars.rangecolor)
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ pfUI:RegisterModule("buff", function ()
|
||||
pfUI.buff = CreateFrame("Frame", "pfGlobalBuffFrame", UIParent)
|
||||
pfUI.buff:RegisterEvent("PLAYER_AURAS_CHANGED")
|
||||
pfUI.buff:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
|
||||
pfUI.buff:RegisterEvent("UNIT_MODEL_CHANGED")
|
||||
pfUI.buff:RegisterUnitEvent("UNIT_MODEL_CHANGED", "player")
|
||||
pfUI.buff:RegisterEvent("BUFF_UPDATE_DURATION_SELF")
|
||||
pfUI.buff:RegisterEvent("DEBUFF_UPDATE_DURATION_SELF")
|
||||
pfUI.buff:SetScript("OnEvent", function()
|
||||
|
||||
+23
-14
@@ -86,7 +86,7 @@ pfUI:RegisterModule("castbar", function ()
|
||||
|
||||
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
||||
-- 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.endTime = endMs
|
||||
cb.isChannel = isChannel
|
||||
@@ -97,7 +97,10 @@ pfUI:RegisterModule("castbar", function ()
|
||||
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
|
||||
-- through by RefreshBar). Only the retarget re-poll has no event in hand, so
|
||||
@@ -152,10 +155,10 @@ pfUI:RegisterModule("castbar", function ()
|
||||
ClearBar(cb)
|
||||
return
|
||||
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
|
||||
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
|
||||
end
|
||||
-- Synthetic fallback for abilities the engine treats as instant-cast but
|
||||
@@ -169,7 +172,7 @@ pfUI:RegisterModule("castbar", function ()
|
||||
end
|
||||
end
|
||||
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
|
||||
ClearBar(cb)
|
||||
end
|
||||
@@ -322,15 +325,21 @@ pfUI:RegisterModule("castbar", function ()
|
||||
-- casts only ever fire arg1=="player" -- when the bar's unit resolves to the
|
||||
-- player (target=self). PLAYER_TARGET/FOCUS_CHANGED re-polls so a unit
|
||||
-- already mid-cast when it becomes the target/focus still shows.
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_START")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_FAILED")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_DELAYED")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
|
||||
-- Filter to this bar's unit, plus "player" for the target/focus bars: the
|
||||
-- player's own casts only ever fire arg1=="player", so a self-targeted cast
|
||||
-- has to reach them too (nil for the player bar itself, which the filter
|
||||
-- skips). This only narrows what arrives -- the arg1/UnitIsUnit test below
|
||||
-- still decides whether the bar acts on it.
|
||||
local selfunit = unitstr ~= "player" and "player" or nil
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_START", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_STOP", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_DELAYED", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", unitstr, selfunit)
|
||||
cb:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", unitstr, selfunit)
|
||||
if unitstr == "target" then
|
||||
cb:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
elseif unitstr == "focus" then
|
||||
|
||||
@@ -52,7 +52,7 @@ pfUI:RegisterModule("combopoints", function ()
|
||||
-- combo
|
||||
if class == "DRUID" or class == "ROGUE" then
|
||||
local combo = CreateFrame("Frame")
|
||||
combo:RegisterEvent("UNIT_COMBO_POINTS")
|
||||
combo:RegisterUnitEvent("UNIT_COMBO_POINTS", "player")
|
||||
combo:RegisterEvent("PLAYER_COMBO_POINTS")
|
||||
combo:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
combo:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
|
||||
+185
-60
@@ -1,20 +1,82 @@
|
||||
local function getAdjustedTickTimer()
|
||||
local adjustedEnergyTick = 2
|
||||
-- One server clock drives every power: Player::RegenerateAll fires every
|
||||
-- REGEN_TIME_FULL (2s), re-arms with `+=`, and is never reset by casting. The
|
||||
-- five-second rule (SetLastManaUse on any mana-costing cast) changes what a tick
|
||||
-- pays, never when it lands; mp5 and the player's MOD_MANA_REGEN_INTERRUPT share
|
||||
-- still come in. That share can't be computed here -- item sources are equip
|
||||
-- auras absent from the buff list and m_modManaRegenInterrupt is never sent --
|
||||
-- so the spark shows it instead: dim through the window until a tick lands.
|
||||
--
|
||||
-- The sweep free-runs on that clock and phase-locks to observed gains. A gain
|
||||
-- mid-sweep (Illumination, Judgement of Wisdom, potions, a Mana Spring totem on
|
||||
-- its own phase) is not the tick and never moves it.
|
||||
|
||||
-- Check rogue talents and compute energy tick timing reduction for Combat spec (1.18.0 Blade Rush Talent)
|
||||
if UnitClassBase("player") == "ROGUE" then
|
||||
local _, _, _, _, currRank = GetTalentInfo(2, 16)
|
||||
local bladeRushRank = currRank or 0
|
||||
local FIVE_SECOND_RULE = 5
|
||||
|
||||
if bladeRushRank > 0 then
|
||||
local agility = UnitStat("player", 2) -- 2 is agility stat index
|
||||
local reductionPerAgi = 0.0006 * bladeRushRank -- 0.0006 for rank 1, 0.0012 for rank 2
|
||||
local totalReduction = agility * reductionPerAgi
|
||||
adjustedEnergyTick = adjustedEnergyTick - totalReduction
|
||||
-- gains farther than this from the predicted boundary are not the tick
|
||||
local TICK_TOLERANCE = .25
|
||||
|
||||
-- arrival jitter; a tick inside this band confirms the sweep rather than
|
||||
-- re-anchoring it, or the spark hitches at every wrap
|
||||
local TICK_JITTER = .08
|
||||
|
||||
-- Player::RegenerateAll:
|
||||
-- mod = GetTotalAuraModifier(SPELL_AURA_MOD_ENERGY_REGEN_TIME)
|
||||
-- if mod > 0 then mod = mod * agility / 10 end
|
||||
-- m_regenTimer += max(1, REGEN_TIME_FULL - mod) -- milliseconds
|
||||
local REGEN_TIME_FULL = 2
|
||||
local ENERGY_REGEN_TIME_AURA = 217 -- SPELL_AURA_MOD_ENERGY_REGEN_TIME
|
||||
|
||||
-- fixed magnitude is basePoints + baseDice (stored 11 -> 12); a die above 1 is
|
||||
-- a roll the client can't know, so it counts as nothing rather than a guess
|
||||
local amountCache = {}
|
||||
local function auraAmount(spellID)
|
||||
local amount = amountCache[spellID]
|
||||
if amount then return amount end
|
||||
amount = 0
|
||||
local effects = C_Spell.GetSpellEffectInfo(spellID) -- nil for an id with no record
|
||||
if effects then
|
||||
for i = 1, 3 do
|
||||
local fx = effects[i]
|
||||
if fx.auraName == ENERGY_REGEN_TIME_AURA and fx.dieSides <= 1 then
|
||||
amount = fx.basePoints + fx.baseDice
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
amountCache[spellID] = amount
|
||||
return amount
|
||||
end
|
||||
|
||||
return adjustedEnergyTick
|
||||
-- A passive is in effect exactly while known (current rank only, never in the
|
||||
-- buff list); anything castable or cast on us counts only while it is up.
|
||||
local function getEnergyRegenTimeMod()
|
||||
local sum = 0
|
||||
for _, spellID in ipairs(C_SpellBook.GetPlayerSpellsByAura(ENERGY_REGEN_TIME_AURA)) do
|
||||
if C_Spell.IsSpellPassive(spellID) then
|
||||
sum = sum + auraAmount(spellID)
|
||||
end
|
||||
end
|
||||
for i = 1, 32 do
|
||||
local spellID = select(10, C_UnitAuras.UnitAura("player", i, "HELPFUL"))
|
||||
if not spellID then break end
|
||||
sum = sum + auraAmount(spellID)
|
||||
end
|
||||
return sum
|
||||
end
|
||||
|
||||
-- cleared on SPELLS_CHANGED (passives) and PLAYER_AURAS_CHANGED (buffs), and
|
||||
-- recomputed by the next tick that asks. Agility stays live: it's one call.
|
||||
local energyRegenTimeMod
|
||||
|
||||
local function getAdjustedTickTimer()
|
||||
if not energyRegenTimeMod then
|
||||
energyRegenTimeMod = getEnergyRegenTimeMod()
|
||||
end
|
||||
if energyRegenTimeMod == 0 then return REGEN_TIME_FULL end
|
||||
|
||||
-- ms on the server, seconds here; the 1ms floor is the server's and this is a divisor
|
||||
local reduction = energyRegenTimeMod * UnitStat("player", 2) / 10000
|
||||
return math.max(0.001, REGEN_TIME_FULL - reduction)
|
||||
end
|
||||
|
||||
pfUI:RegisterModule("energytick", function()
|
||||
@@ -22,14 +84,53 @@ pfUI:RegisterModule("energytick", function()
|
||||
return
|
||||
end
|
||||
|
||||
-- inside the module body on purpose: C is on pfUI.env, not _G
|
||||
local function getBarWidth()
|
||||
return C.unitframes.player.pwidth ~= "-1" and C.unitframes.player.pwidth or C.unitframes.player.width
|
||||
end
|
||||
|
||||
-- was this gain the regen tick? if so, re-anchor the sweep on it
|
||||
local function lockTick(frame)
|
||||
local now, period = GetTime(), getAdjustedTickTimer()
|
||||
|
||||
if frame.start then
|
||||
-- signed distance to the nearest predicted boundary
|
||||
local err = mod(now - frame.start, period)
|
||||
if err > period / 2 then err = err - period end
|
||||
|
||||
if math.abs(err) <= TICK_TOLERANCE then
|
||||
-- correct only what lies beyond normal jitter
|
||||
if err > TICK_JITTER then
|
||||
frame.start = frame.start + (err - TICK_JITTER)
|
||||
elseif err < -TICK_JITTER then
|
||||
frame.start = frame.start + (err + TICK_JITTER)
|
||||
end
|
||||
frame.max, frame.rejected = period, nil
|
||||
return true
|
||||
end
|
||||
|
||||
-- two rejected gains one period apart are the real clock: relock to it
|
||||
local periodic = frame.rejected and math.abs(now - frame.rejected - period) <= TICK_TOLERANCE
|
||||
if not periodic then
|
||||
frame.rejected = now
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
frame.start, frame.max, frame.rejected = now, period, nil
|
||||
return true
|
||||
end
|
||||
|
||||
local energytick = CreateFrame("Frame", nil, pfUI.uf.player.power.bar)
|
||||
energytick:SetAllPoints(pfUI.uf.player.power.bar)
|
||||
energytick:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
energytick:RegisterEvent("UNIT_DISPLAYPOWER")
|
||||
energytick:RegisterEvent("UNIT_ENERGY")
|
||||
energytick:RegisterEvent("UNIT_MANA")
|
||||
energytick:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF")
|
||||
energytick:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS")
|
||||
energytick:RegisterUnitEvent("UNIT_DISPLAYPOWER", "player")
|
||||
energytick:RegisterUnitEvent("UNIT_ENERGY", "player")
|
||||
energytick:RegisterUnitEvent("UNIT_MANA", "player")
|
||||
energytick:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
|
||||
energytick:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", "player")
|
||||
energytick:RegisterEvent("SPELLS_CHANGED")
|
||||
energytick:RegisterEvent("PLAYER_AURAS_CHANGED")
|
||||
|
||||
energytick:SetScript("OnEvent", function()
|
||||
if UnitPowerType("player") == Enum.PowerType.Mana and C.unitframes.player.manatick == "1" then
|
||||
@@ -42,44 +143,52 @@ pfUI:RegisterModule("energytick", function()
|
||||
this:Hide()
|
||||
end
|
||||
|
||||
-- Filter nur eigene Energy-Gewinne von Talents/Buffs
|
||||
if event == "CHAT_MSG_SPELL_SELF_BUFF" or event == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" then
|
||||
if string.find(arg1, "You gain") and string.find(arg1, "Energy from") then
|
||||
this.ignoreNextGain = true
|
||||
end
|
||||
if event == "SPELLS_CHANGED" or event == "PLAYER_AURAS_CHANGED" then
|
||||
energyRegenTimeMod = nil
|
||||
return
|
||||
end
|
||||
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
this.lastMana = UnitPower("player")
|
||||
this.lastPower = UnitPower("player")
|
||||
end
|
||||
|
||||
-- the rule arms on the cast (Spell::TakePower: mana powerType, cost > 0),
|
||||
-- not on a mana drop -- Mana Burn lowers mana without arming it
|
||||
if event == "UNIT_SPELLCAST_SUCCEEDED" and arg1 == "player" then
|
||||
local cost = C_Spell.GetSpellPowerCost(arg3)
|
||||
cost = cost and cost[1]
|
||||
if cost and cost.type == Enum.PowerType.Mana and cost.cost > 0 then
|
||||
this.fsrSpell, this.fsrEnd = arg3, GetTime() + FIVE_SECOND_RULE
|
||||
this.fsrGain = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Unit::Update won't expire the rule while the spending spell still channels
|
||||
if event == "UNIT_SPELLCAST_CHANNEL_STOP" and arg1 == "player" then
|
||||
if this.fsrSpell and this.fsrSpell == arg3 then
|
||||
this.fsrEnd, this.fsrGain = GetTime() + FIVE_SECOND_RULE, nil
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if (event == "UNIT_MANA" or event == "UNIT_ENERGY") and arg1 == "player" then
|
||||
this.currentMana = UnitPower("player")
|
||||
local diff = 0
|
||||
if this.lastMana then
|
||||
diff = this.currentMana - this.lastMana
|
||||
local power = UnitPower("player")
|
||||
local diff = this.lastPower and (power - this.lastPower) or 0
|
||||
this.lastPower = power
|
||||
|
||||
-- only a gain can be the tick; a spend never touches the phase
|
||||
if diff > 0 and lockTick(this) then
|
||||
-- a tick inside the window proves regen continues through it
|
||||
if this.fsrEnd and this.fsrEnd > GetTime() then
|
||||
this.fsrGain = true
|
||||
end
|
||||
end
|
||||
|
||||
if this.mode == "MANA" and diff < 0 then
|
||||
this.target = 5
|
||||
elseif this.mode == "MANA" and diff > 0 then
|
||||
if UnitPower("player") >= UnitPowerMax("player") then
|
||||
this.start = nil
|
||||
this.spark:SetAlpha(0)
|
||||
this:Hide()
|
||||
elseif this.max ~= 5 and diff > (this.badtick and this.badtick * 1.2 or 5) then
|
||||
this.target = 2
|
||||
else
|
||||
this.badtick = diff
|
||||
end
|
||||
elseif this.mode == "ENERGY" and diff >= 0 then
|
||||
if not this.ignoreNextGain then
|
||||
this.target = getAdjustedTickTimer()
|
||||
end
|
||||
this.ignoreNextGain = false
|
||||
-- phase is kept while hidden; OnUpdate catches up by whole periods
|
||||
if this.mode == "MANA" and power >= UnitPowerMax("player") then
|
||||
this:Hide()
|
||||
end
|
||||
this.lastMana = this.currentMana
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -90,37 +199,53 @@ pfUI:RegisterModule("energytick", function()
|
||||
end
|
||||
this.tick = GetTime() + 0.020 -- ~50 FPS
|
||||
|
||||
if this.target then
|
||||
this.start, this.max = GetTime(), this.target
|
||||
this.target = nil
|
||||
this.spark:SetAlpha(1)
|
||||
this:Show()
|
||||
-- five-second rule drains to nothing
|
||||
local remaining = this.fsrEnd and (this.fsrEnd - GetTime()) or 0
|
||||
if this.mode == "MANA" and remaining > 0 then
|
||||
this.fsrbar:SetWidth(getBarWidth() * remaining / FIVE_SECOND_RULE)
|
||||
this.fsrbar:Show()
|
||||
else
|
||||
this.fsrSpell, this.fsrEnd, this.fsrGain = nil, nil, nil
|
||||
this.fsrbar:Hide()
|
||||
end
|
||||
|
||||
if not this.start then
|
||||
this.spark:SetAlpha(0)
|
||||
return
|
||||
end
|
||||
|
||||
if this.mode == "MANA" and UnitPower("player") >= UnitPowerMax("player") then
|
||||
this.spark:SetAlpha(0)
|
||||
return
|
||||
end
|
||||
|
||||
this.current = GetTime() - this.start
|
||||
|
||||
-- roll over by whole periods, not from now: restarting bakes frame
|
||||
-- overshoot into the phase as drift the lock then has to chase
|
||||
if this.current > this.max then
|
||||
-- Don't restart tick timer if mana is full
|
||||
if this.mode == "MANA" and UnitPower("player") >= UnitPowerMax("player") then
|
||||
this.start = nil
|
||||
this.spark:SetAlpha(0)
|
||||
return
|
||||
end
|
||||
this.start, this.max, this.current = GetTime(), getAdjustedTickTimer(), 0
|
||||
this.start = this.start + this.max * math.floor(this.current / this.max)
|
||||
this.max = getAdjustedTickTimer()
|
||||
this.current = GetTime() - this.start
|
||||
end
|
||||
|
||||
local pos = (C.unitframes.player.pwidth ~= "-1" and C.unitframes.player.pwidth or C.unitframes.player.width)
|
||||
* (this.current / this.max)
|
||||
-- dim while the rule is up and nothing has ticked inside it yet
|
||||
this.spark:SetAlpha((remaining > 0 and not this.fsrGain) and .4 or 1)
|
||||
|
||||
if not C.unitframes.player.pheight then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = getBarWidth() * (this.current / this.max)
|
||||
this.spark:SetPoint("LEFT", pos - ((C.unitframes.player.pheight + 5) / 2), 0)
|
||||
end)
|
||||
|
||||
energytick.fsrbar = energytick:CreateTexture(nil, "ARTWORK")
|
||||
energytick.fsrbar:SetTexture(1, 1, 1, .15)
|
||||
energytick.fsrbar:SetPoint("TOPLEFT", 0, 0)
|
||||
energytick.fsrbar:SetPoint("BOTTOMLEFT", 0, 0)
|
||||
energytick.fsrbar:Hide()
|
||||
|
||||
energytick.spark = energytick:CreateTexture(nil, "OVERLAY")
|
||||
energytick.spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
|
||||
energytick.spark:SetHeight(C.unitframes.player.pheight + 15)
|
||||
@@ -133,4 +258,4 @@ pfUI:RegisterModule("energytick", function()
|
||||
energytick.spark:SetWidth(C.unitframes.player.pheight + 5)
|
||||
hookUpdateConfig(pfUI.uf.player)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
+20
-1
@@ -130,9 +130,28 @@ pfUI:RegisterModule("eqcompare", function ()
|
||||
SetTradeTargetItem = GetTradeTargetItemLink
|
||||
}
|
||||
|
||||
-- Guda anchors its item tooltips with ANCHOR_NONE and its own SetPoint, and
|
||||
-- the tooltip module then moves every ANCHOR_NONE tooltip to its configured
|
||||
-- spot. Reading the rect inside the Set* call picks the side against the
|
||||
-- position the tooltip is about to leave, so place the compare a frame later.
|
||||
local deferred
|
||||
if C_AddOns.DoesAddOnExist("Guda") then
|
||||
EventUtil.ContinueOnAddOnLoaded("Guda", function()
|
||||
deferred = true
|
||||
end)
|
||||
end
|
||||
|
||||
local function makeHook(getter)
|
||||
return function(tooltip, arg1, arg2, arg3)
|
||||
ShowCompareItem(tooltip, getter(arg1, arg2, arg3))
|
||||
local link = getter(arg1, arg2, arg3)
|
||||
if not deferred then
|
||||
return ShowCompareItem(tooltip, link)
|
||||
end
|
||||
RunNextFrame(function()
|
||||
if tooltip:IsShown() then
|
||||
ShowCompareItem(tooltip, link)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+2
-5
@@ -2556,9 +2556,6 @@ pfUI:RegisterModule("gui", function ()
|
||||
CreateConfig(U["bars"], T["Button Animation"], C.bars, "animation", "dropdown", pfUI.gui.dropdowns.actionbuttonanimations)
|
||||
CreateConfig(U["bars"], T["Button Animation Trigger"], C.bars, "animmode", "dropdown", pfUI.gui.dropdowns.animationmode)
|
||||
CreateConfig(U["bars"], T["Show Animation On Hidden Bars"], C.bars, "animalways", "checkbox")
|
||||
if not pfUI:MacroAddonsLoaded() then
|
||||
CreateConfig(U["bars"], T["Scan Macros For Spells"], C.bars, "macroscan", "checkbox", nil, nil, nil, nil)
|
||||
end
|
||||
CreateConfig(U["bars"], T["Show Reagent Count"], C.bars, "reagents", "checkbox")
|
||||
CreateConfig(U["bars"], T["Highlight Equipped Items"], C.bars, "showequipped", "checkbox")
|
||||
CreateConfig(U["bars"], T["Equipped Item Color"], C.bars, "eqcolor", "color")
|
||||
@@ -2795,6 +2792,7 @@ pfUI:RegisterModule("gui", function ()
|
||||
CreateConfig(nil, T["Use Unit Fonts"], C.castbar, "use_unitfonts", "checkbox")
|
||||
CreateConfig(nil, T["Casting Color"], C.appearance.castbar, "castbarcolor", "color")
|
||||
CreateConfig(nil, T["Channeling Color"], C.appearance.castbar, "channelcolor", "color")
|
||||
CreateConfig(nil, T["Uninterruptible Color"], C.appearance.castbar, "shieldcolor", "color")
|
||||
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")
|
||||
end)
|
||||
@@ -3029,8 +3027,7 @@ pfUI:RegisterModule("gui", function ()
|
||||
CreateGUIEntry(T["Components"], T["Modules"], function()
|
||||
table.sort(pfUI.modules)
|
||||
for i,m in pairs(pfUI.modules) do
|
||||
-- skip gui and macrotweak when macro addons are loaded
|
||||
if m ~= "gui" and not (m == "macrotweak" and pfUI:MacroAddonsLoaded()) then
|
||||
if m ~= "gui" then
|
||||
-- create disabled entry if not existing and display
|
||||
pfUI:UpdateConfig("disabled", nil, m, "0")
|
||||
CreateConfig(nil, T["Disable Module"] .. " " .. m, C.disabled, m, "checkbox")
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
pfUI:RegisterModule("macrotweak", function ()
|
||||
local conflictAddons = { "Supermacro", "SuperCleveRoidMacros", "UltimaMacros" }
|
||||
local disabled = false
|
||||
|
||||
for _, addon in pairs(conflictAddons) do
|
||||
local name = addon
|
||||
EventUtil.ContinueOnAddOnLoaded(name, function()
|
||||
if not disabled then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpfUI|r: " .. name .. " found, macrotweak disabled.")
|
||||
end
|
||||
disabled = true
|
||||
end)
|
||||
end
|
||||
|
||||
-- do not write macro calls into chat input history
|
||||
-- (install once: _AddHistoryLine is our backup slot and is nil until we set it)
|
||||
if not ChatFrameEditBox._AddHistoryLine then
|
||||
local userinput
|
||||
ChatFrameEditBox._AddHistoryLine = ChatFrameEditBox.AddHistoryLine
|
||||
ChatFrameEditBox.AddHistoryLine = function(self, text)
|
||||
if disabled then return ChatFrameEditBox._AddHistoryLine(self, text) end
|
||||
if not userinput and text and string.find(text, "^/run(.+)") then return end
|
||||
if not userinput and string.find(text, "^/script(.+)") then return end
|
||||
if not userinput and string.find(text, "^/cast(.+)") then return end
|
||||
ChatFrameEditBox._AddHistoryLine(self, text)
|
||||
end
|
||||
|
||||
local OnEnter = ChatFrameEditBox:GetScript("OnEnterPressed")
|
||||
ChatFrameEditBox:SetScript("OnEnterPressed", function(a1,a2,a3,a4)
|
||||
userinput = true
|
||||
OnEnter(a1,a2,a3,a4)
|
||||
userinput = nil
|
||||
end)
|
||||
end
|
||||
|
||||
-- make sure #showtooltip inside macros won't be sent
|
||||
local hookSendChatMessage = SendChatMessage
|
||||
function _G.SendChatMessage(msg, ...)
|
||||
if disabled then return hookSendChatMessage(msg, unpack(arg)) end
|
||||
if msg and string.find(msg, "^#showtooltip ") then return end
|
||||
hookSendChatMessage(msg, unpack(arg))
|
||||
end
|
||||
|
||||
-- add /use and /equip to the macro api:
|
||||
-- https://wowwiki.fandom.com/wiki/Making_a_macro
|
||||
-- supported arguments:
|
||||
-- /use <itemname>
|
||||
-- /use <inventory slot>
|
||||
-- /use <bag> <slot>
|
||||
pfUI.api.RegisterSlashCommand("PFUSE", { "/equip" , "/use", "/pfequip", "/pfuse" }, function (msg)
|
||||
if not msg or msg == "" then return end
|
||||
local bag, slot, _
|
||||
if string.find(msg, "%d+%s+%d+") then
|
||||
_, _, bag, slot = string.find(msg, "(%d+)%s+(%d+)")
|
||||
elseif string.find(msg, "%d+") then
|
||||
_, _, slot = string.find(msg, "(%d+)")
|
||||
else
|
||||
bag, slot = FindItem(msg)
|
||||
end
|
||||
|
||||
if bag and slot then
|
||||
UseContainerItem(bag, slot)
|
||||
elseif not bag and slot then
|
||||
UseInventoryItem(slot)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
+38
-18
@@ -1,12 +1,9 @@
|
||||
pfUI:RegisterModule("marktracking", function ()
|
||||
if not UnitExists("mark1") and not UnitExists("mark8") then
|
||||
if not pcall(function() UnitExists("mark1") end) then return end
|
||||
end
|
||||
|
||||
local rawborder, border = GetBorderSize()
|
||||
|
||||
local markerOrder = { 8, 7, 6, 5, 4, 3, 2, 1 } -- skull, cross, square, moon, triangle, diamond, circle, star
|
||||
local markerTokens = {}
|
||||
local markerTokens = {} -- [i] = "markN"
|
||||
local markerIndex = {} -- ["markN"] = i, for the event handler's arg1
|
||||
|
||||
local markerConfigKeys = {
|
||||
"raidmarkercolor_star",
|
||||
@@ -22,6 +19,7 @@ pfUI:RegisterModule("marktracking", function ()
|
||||
local markerColors = {}
|
||||
for i, markKey in ipairs(markerConfigKeys) do
|
||||
markerTokens[i] = "mark" .. i
|
||||
markerIndex[markerTokens[i]] = i
|
||||
local r, g, b, a = GetStringColor(C.unitframes[markKey])
|
||||
markerColors[i] = { tonumber(r), tonumber(g), tonumber(b), tonumber(a) }
|
||||
end
|
||||
@@ -73,8 +71,7 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
||||
else
|
||||
pfUI.marktracking:SetPoint("TOP", UIParent, "CENTER", 0, 0)
|
||||
end
|
||||
pfUI.marktracking:SetWidth(TOTAL_ROW_WIDTH)
|
||||
pfUI.marktracking:SetHeight(8 * (ROW_HEIGHT + 1) + border * 2 - 1)
|
||||
pfUI.marktracking:SetSize(TOTAL_ROW_WIDTH, 8 * (ROW_HEIGHT + 1) + border * 2 - 1)
|
||||
pfUI.marktracking:Hide()
|
||||
|
||||
CreateBackdrop(pfUI.marktracking)
|
||||
@@ -284,27 +281,50 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
||||
-- Event-driven scanner frame
|
||||
local scanner = CreateFrame("Frame")
|
||||
|
||||
-- Fallback poll: catches units that come into range AFTER a marker was set
|
||||
-- (no event fires for that case, so we need this safety net). UpdateDisplay
|
||||
-- is a full eight-row rebuild, so it exists only while grouped -- raid markers
|
||||
-- are a group feature and there is nothing to discover alone. The group events
|
||||
-- below start and cancel it, so outside a group there is no timer queued at
|
||||
-- all rather than one waking every second to return early.
|
||||
--
|
||||
-- Deliberately NOT keyed on a mark being visible: a marker set on a unit that
|
||||
-- is out of range shows no row, and that is exactly what this poll catches.
|
||||
local poll
|
||||
local function UpdatePoll()
|
||||
local grouped = IsInGroup()
|
||||
if grouped and not poll then
|
||||
poll = C_Timer.NewTicker(FALLBACK_INTERVAL, UpdateDisplay)
|
||||
elseif not grouped and poll then
|
||||
poll:Cancel()
|
||||
poll = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- RAID_TARGET_UPDATE: a raid marker was set/cleared -> full refresh
|
||||
-- PLAYER_ENTERING_WORLD: login/reload/zone -> full refresh
|
||||
-- UNIT_HEALTH/UNIT_MAXHEALTH: ClassicAPI fires these per token; with the mark
|
||||
-- tokens observed they arrive as arg1 == "markN", so we refresh just that
|
||||
-- one row (UpdateRow) instead of rescanning all eight.
|
||||
-- PARTY_MEMBERS_CHANGED/RAID_ROSTER_UPDATE: joined or left a group -> the rows
|
||||
-- can change, and the fallback poll starts or stops with it
|
||||
-- UNIT_HEALTH/UNIT_MAXHEALTH: filtered to the eight mark tokens, so arg1 is
|
||||
-- always "markN" and we refresh just that row (UpdateRow) instead of
|
||||
-- rescanning all eight.
|
||||
scanner:RegisterEvent("RAID_TARGET_UPDATE")
|
||||
scanner:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
scanner:RegisterEvent("UNIT_HEALTH")
|
||||
scanner:RegisterEvent("UNIT_MAXHEALTH")
|
||||
scanner:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
||||
scanner:RegisterEvent("RAID_ROSTER_UPDATE")
|
||||
scanner:RegisterUnitEvent("UNIT_HEALTH", "mark1", "mark2", "mark3", "mark4", "mark5", "mark6", "mark7", "mark8")
|
||||
scanner:RegisterUnitEvent("UNIT_MAXHEALTH", "mark1", "mark2", "mark3", "mark4", "mark5", "mark6", "mark7", "mark8")
|
||||
|
||||
scanner:SetScript("OnEvent", function()
|
||||
if event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" then
|
||||
-- arg1 is the token; "markN" -> N, nil for any non-mark token.
|
||||
local i = arg1 and tonumber(string.match(arg1, "^mark(%d)"))
|
||||
-- arg1 is one of the eight tokens we registered for, so this is a lookup
|
||||
-- rather than a parse -- string.match would allocate a capture and
|
||||
-- tonumber would parse it, on every health tick of every marked unit.
|
||||
local i = arg1 and markerIndex[arg1]
|
||||
if i then UpdateRow(i) end
|
||||
return
|
||||
end
|
||||
if event ~= "RAID_TARGET_UPDATE" then UpdatePoll() end
|
||||
UpdateDisplay()
|
||||
end)
|
||||
|
||||
-- Fallback poll: catches units that come into range AFTER a marker was set
|
||||
-- (no event fires for that case, so we need this safety net)
|
||||
C_Timer.NewTicker(FALLBACK_INTERVAL, UpdateDisplay)
|
||||
end)
|
||||
+1
-1
@@ -225,7 +225,7 @@ pfUI:RegisterModule("minimap", function ()
|
||||
pfUI.minimap.pvpicon = CreateFrame("Frame", nil, pfUI.minimap)
|
||||
pfUI.minimap.pvpicon:Hide()
|
||||
pfUI.minimap.pvpicon:RegisterEvent("UPDATE_FACTION")
|
||||
pfUI.minimap.pvpicon:RegisterEvent("UNIT_FACTION")
|
||||
pfUI.minimap.pvpicon:RegisterUnitEvent("UNIT_FACTION", "player")
|
||||
pfUI.minimap.pvpicon:SetFrameStrata("HIGH")
|
||||
pfUI.minimap.pvpicon:SetSize(16, 16)
|
||||
pfUI.minimap.pvpicon:SetAlpha(.5)
|
||||
|
||||
+104
-77
@@ -5,10 +5,7 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
-- Local function references for performance
|
||||
local GetTime = GetTime
|
||||
local UnitName = UnitName
|
||||
local UnitClass = UnitClass
|
||||
local UnitLevel = UnitLevel
|
||||
local UnitIsPlayer = UnitIsPlayer
|
||||
local UnitIsDead = UnitIsDead
|
||||
local UnitAffectingCombat = UnitAffectingCombat
|
||||
local UnitIsUnit = UnitIsUnit
|
||||
local UnitCanAssist = UnitCanAssist
|
||||
@@ -80,10 +77,10 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
-- vs channel itself. Never called per frame.
|
||||
local function PollCastInfo(unit)
|
||||
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
|
||||
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
|
||||
end
|
||||
if not name or not startMs or not endMs then return nil end
|
||||
@@ -95,6 +92,7 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
endTime = endMs / 1000,
|
||||
duration = (endMs - startMs) / 1000,
|
||||
isChannel = isChannel,
|
||||
noInterrupt = noInterrupt,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -162,6 +160,24 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
cfg.debuffanim = tonumber(C.nameplates.debuffanim) or 0
|
||||
cfg.debufftext = tonumber(C.nameplates.debufftext) or 1
|
||||
|
||||
-- Throttle delays, resolved once instead of per plate per tick.
|
||||
-- libthrottle:Get walks the saved-variable table, a defaults fallback and a
|
||||
-- preset table, and can build a "<category>_custom" key -- the per-plate
|
||||
-- OnUpdate was calling it one or two times for every visible plate, a
|
||||
-- hundred times a second, just to decide it had nothing to do.
|
||||
--
|
||||
-- cfg.throttle_min is the floor across all four. No plate can ever be due
|
||||
-- sooner than that, so the update can bail on it before working out which
|
||||
-- category it actually belongs to.
|
||||
cfg.throttle_target = pfUI.throttle:Get("nameplates_target")
|
||||
cfg.throttle_mass = pfUI.throttle:Get("nameplates_mass")
|
||||
cfg.throttle_normal = pfUI.throttle:Get("nameplates")
|
||||
cfg.throttle_castbar = pfUI.throttle:Get("nameplates_castbar")
|
||||
cfg.throttle_min = cfg.throttle_target
|
||||
if cfg.throttle_mass < cfg.throttle_min then cfg.throttle_min = cfg.throttle_mass end
|
||||
if cfg.throttle_normal < cfg.throttle_min then cfg.throttle_min = cfg.throttle_normal end
|
||||
if cfg.throttle_castbar < cfg.throttle_min then cfg.throttle_min = cfg.throttle_castbar end
|
||||
|
||||
-- Rebuild offtanks lookup table
|
||||
offtanks = {}
|
||||
for k, v in pairs({strsplit("#", C.nameplates.combatofftanks)}) do
|
||||
@@ -490,7 +506,7 @@ local nameplates = CreateFrame("Frame", "pfNameplates", UIParent)
|
||||
nameplates:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
nameplates:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
nameplates:RegisterEvent("PLAYER_LOGOUT")
|
||||
nameplates:RegisterEvent("UNIT_COMBO_POINTS")
|
||||
nameplates:RegisterUnitEvent("UNIT_COMBO_POINTS", "player")
|
||||
nameplates:RegisterEvent("PLAYER_COMBO_POINTS")
|
||||
nameplates:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
||||
nameplates:RegisterEvent("RAID_ROSTER_UPDATE")
|
||||
@@ -498,13 +514,10 @@ nameplates:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_CREATED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_UNIT_ADDED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
|
||||
nameplates:RegisterEvent("UNIT_AURA")
|
||||
nameplates:RegisterEvent("UNIT_FLAGS")
|
||||
nameplates:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_START")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||
-- UNIT_AURA / UNIT_FLAGS / UNIT_SPELLCAST_* are registered per plate, on the
|
||||
-- plate's own frame, against its own token -- see OnCreate and
|
||||
-- NAME_PLATE_UNIT_ADDED.
|
||||
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
|
||||
nameplates:SetScript("OnEvent", function()
|
||||
@@ -516,6 +529,15 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
if nameplates.mouselook then
|
||||
nameplates.mouselook:SetScript("OnUpdate", nil)
|
||||
end
|
||||
-- The plates hold their own unit subscriptions now, so silencing this
|
||||
-- frame alone would leave them dispatching through logout -- exactly what
|
||||
-- this branch exists to prevent.
|
||||
for plate in pairs(registry) do
|
||||
if plate.nameplate then
|
||||
plate.nameplate:UnregisterAllEvents()
|
||||
plate.nameplate:SetScript("OnEvent", nil)
|
||||
end
|
||||
end
|
||||
return
|
||||
|
||||
elseif event == "PLAYER_GUILD_UPDATE" and arg1 == 'player' then
|
||||
@@ -591,6 +613,16 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
local guid = UnitGUID(arg1)
|
||||
plate.nameplate.cachedGuid = guid
|
||||
plate.nameplate.unit = arg1
|
||||
|
||||
-- Point this plate's own subscriptions at the token it just took. On a
|
||||
-- recycled frame these replace the previous unit rather than stacking:
|
||||
-- RegisterUnitEvent on an already-filtered registration swaps the units.
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_AURA", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_FLAGS", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_START", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_STOP", arg1)
|
||||
plate.nameplate:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", arg1)
|
||||
plate.nameplate.creatureType = nil -- recompute for the new unit
|
||||
plate.nameplate.totemIcon = nil
|
||||
plate.nameplate.totemSpell = nil
|
||||
@@ -621,14 +653,9 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
if plate and plate.nameplate and plate.nameplate.cachedGuid == guid then
|
||||
plate.nameplate.cachedGuid = nil
|
||||
plate.nameplate.unit = nil
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_FLAGS" then
|
||||
if arg1 and strfind(arg1, "^nameplate") then
|
||||
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.eventcache = true
|
||||
-- Drop the subscriptions with the token: this slot is now free and the
|
||||
-- next plate to take it would otherwise feed this frame its events.
|
||||
plate.nameplate:UnregisterAllEvents()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -643,48 +670,6 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
if pn then pn.eventcache = true end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||
-- ClassicAPI fires UNIT_SPELLCAST_* per unit token, including the caster's
|
||||
-- "nameplateN". The payload has no timing, so poll it (PollCastInfo picks
|
||||
-- cast vs channel) and cache -- only for a unit we have a plate for, so
|
||||
-- the table stays bounded to on-screen casters.
|
||||
if arg1 and strfind(arg1, "^nameplate") then
|
||||
local guid = UnitGUID(arg1)
|
||||
local plate = guid and plateByGuid[guid]
|
||||
if plate then
|
||||
castState[guid] = PollCastInfo(arg1)
|
||||
if castState[guid] then
|
||||
plate.castUpdate = true -- bypass the throttle so the bar shows now
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
|
||||
-- Cast/channel ended (natural, interrupted, or cancelled -- the poll fires
|
||||
-- STOP for all three). Clear the cached cast and refresh its plate.
|
||||
if arg1 and strfind(arg1, "^nameplate") then
|
||||
local guid = UnitGUID(arg1)
|
||||
if guid and castState[guid] then
|
||||
castState[guid] = nil
|
||||
local plate = plateByGuid[guid]
|
||||
if plate then plate.castUpdate = true end
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_AURA" then
|
||||
-- ClassicAPI: fires with arg1 == "nameplateN" when a unit's aura set
|
||||
-- changes (add/remove/modify). Flag the matching plate so OnUpdate does a
|
||||
-- fresh C_UnitAuras read next tick instead of waiting on the 0.5s
|
||||
-- throttle -- covers expirations, dispels, refreshes, and stack changes
|
||||
-- in one event. Guard on the token prefix (UNIT_AURA also fires for
|
||||
-- target/party/raid).
|
||||
if arg1 and strfind(arg1, "^nameplate") then
|
||||
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.auraUpdate = true
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "PLAYER_TARGET_CHANGED" then
|
||||
frameState.targetGuid = UnitGUID('target')
|
||||
-- Flag the target's plate for update
|
||||
@@ -766,6 +751,40 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
nameplate.cache = {}
|
||||
nameplate.original = {}
|
||||
|
||||
-- Each plate watches its own unit. With RegisterUnitEvent the token IS the
|
||||
-- subscription, so there is no central listener sifting every unit event in
|
||||
-- the world for a "^nameplate" prefix and then resolving the plate back out
|
||||
-- of arg1 -- the event arrives only at the plate it concerns, and `this` is
|
||||
-- already that plate. NAME_PLATE_UNIT_ADDED points the registration at the
|
||||
-- new token; _REMOVED drops it, which matters because freed slots are
|
||||
-- reused and a stale token would feed this frame another unit's events.
|
||||
nameplate:SetScript("OnEvent", function()
|
||||
if event == "UNIT_AURA" then
|
||||
-- a fresh C_UnitAuras read next tick rather than waiting out the 0.5s
|
||||
-- throttle -- covers expiry, dispels, refreshes and stack changes
|
||||
this.auraUpdate = true
|
||||
elseif event == "UNIT_FLAGS" then
|
||||
this.eventcache = true
|
||||
elseif event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||
-- the payload carries no timing, so poll it (PollCastInfo picks cast
|
||||
-- vs channel)
|
||||
local guid = this.cachedGuid
|
||||
if guid then
|
||||
castState[guid] = PollCastInfo(this.unit)
|
||||
if castState[guid] then
|
||||
this.castUpdate = true -- bypass the throttle so the bar shows now
|
||||
end
|
||||
end
|
||||
elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
|
||||
-- ended: natural, interrupted or cancelled -- the poll fires STOP for all
|
||||
local guid = this.cachedGuid
|
||||
if guid and castState[guid] then
|
||||
castState[guid] = nil
|
||||
this.castUpdate = true
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- create shortcuts for all known elements and disable them
|
||||
nameplate.original.healthbar, nameplate.original.castbar = parent:GetChildren()
|
||||
DisableObject(nameplate.original.healthbar)
|
||||
@@ -1409,6 +1428,16 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
|
||||
-- cachedGuid is maintained by NAME_PLATE_UNIT_ADDED / _REMOVED events.
|
||||
|
||||
-- Cheap gate first. The central loop calls this for every visible plate ~100
|
||||
-- times a second, and classifying the plate below costs two C calls, a cast
|
||||
-- lookup and a throttle resolution -- all of it wasted on a plate that is
|
||||
-- throttled to 10fps. cfg.throttle_min is the floor across every category,
|
||||
-- so nothing that would have updated can be turned away here; the real
|
||||
-- category-specific throttle is still applied after the classification.
|
||||
-- Event flags bypass both gates, as before.
|
||||
local hasEventUpdate = nameplate.eventcache or nameplate.auraUpdate or nameplate.castUpdate or nameplate.targetUpdate or nameplate.comboUpdate
|
||||
if not hasEventUpdate and (nameplate.lasttick or 0) + cfg.throttle_min > now then return end
|
||||
|
||||
-- PERF: Intelligent throttling based on target/castbar status and plate count
|
||||
-- Use GUID comparison as primary target detection: instant, immune to alpha transitions,
|
||||
-- and immediately correct on de-target (unlike istarget which updates one tick later)
|
||||
@@ -1435,25 +1464,24 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
end
|
||||
end
|
||||
|
||||
-- Resolved in CacheConfig, so these are table reads rather than a walk
|
||||
-- through the saved variables and preset tables.
|
||||
local throttle
|
||||
if target then
|
||||
throttle = pfUI.throttle:Get("nameplates_target")
|
||||
throttle = cfg.throttle_target
|
||||
elseif visiblePlateCount > 20 then
|
||||
throttle = pfUI.throttle:Get("nameplates_mass")
|
||||
throttle = cfg.throttle_mass
|
||||
else
|
||||
throttle = pfUI.throttle:Get("nameplates")
|
||||
throttle = cfg.throttle_normal
|
||||
end
|
||||
|
||||
-- Non-target plates with active castbar use the castbar throttle
|
||||
if isCastingNonTarget then
|
||||
local cbThrottle = pfUI.throttle:Get("nameplates_castbar")
|
||||
if cbThrottle < throttle then throttle = cbThrottle end
|
||||
if isCastingNonTarget and cfg.throttle_castbar < throttle then
|
||||
throttle = cfg.throttle_castbar
|
||||
end
|
||||
|
||||
-- Check for pending event updates (these bypass throttle for immediate response)
|
||||
local hasEventUpdate = nameplate.eventcache or nameplate.auraUpdate or nameplate.castUpdate or nameplate.targetUpdate or nameplate.comboUpdate
|
||||
|
||||
-- Event updates bypass throttle
|
||||
-- The category-specific gate. hasEventUpdate was read above, before the
|
||||
-- classification, and still bypasses the throttle.
|
||||
if not hasEventUpdate and (nameplate.lasttick or 0) + throttle > now then return end
|
||||
nameplate.lasttick = now
|
||||
|
||||
@@ -1655,10 +1683,9 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
-- engine framerate, decoupled from central loop). Only update non-target castbars here.
|
||||
local isTargetPlate = target or nameplate.istarget or (nameplate.health and nameplate.health.zoomed)
|
||||
if cfg.showcastbar and not cfg.targetcastbar and not isTargetPlate then
|
||||
local cbThrottle = pfUI.throttle:Get("nameplates_castbar")
|
||||
if visiblePlateCount > 20 then
|
||||
local massThrottle = pfUI.throttle:Get("nameplates_mass")
|
||||
if massThrottle > cbThrottle then cbThrottle = massThrottle end
|
||||
local cbThrottle = cfg.throttle_castbar
|
||||
if visiblePlateCount > 20 and cfg.throttle_mass > cbThrottle then
|
||||
cbThrottle = cfg.throttle_mass
|
||||
end
|
||||
if (nameplate.castbar_tick or 0) + cbThrottle <= now then
|
||||
nameplate.castbar_tick = now
|
||||
@@ -1725,7 +1752,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||
-- Relative 0..duration range to avoid float precision loss with large
|
||||
-- absolute timestamps.
|
||||
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
|
||||
nameplate.castbar.icon.tex:SetTexture(castInfo.icon)
|
||||
nameplate.castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
|
||||
|
||||
+1
-1
@@ -486,7 +486,7 @@ pfUI:RegisterModule("panel", function()
|
||||
do -- Ammo
|
||||
local widget = CreateFrame("Frame", "pfPanelWidgetAmmo", UIParent)
|
||||
widget:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
widget:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
||||
widget:RegisterUnitEvent("UNIT_INVENTORY_CHANGED", "player")
|
||||
widget:RegisterEvent("BAG_UPDATE_DELAYED")
|
||||
widget.Tooltip = function()
|
||||
if GetInventoryItemQuality("player", 0) then
|
||||
|
||||
@@ -816,7 +816,7 @@ pfUI:RegisterModule("swingtimer", function ()
|
||||
events:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||
events:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
events:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
|
||||
events:RegisterEvent("UNIT_DIED")
|
||||
events:RegisterUnitEvent("UNIT_DIED", UnitGUID("player"))
|
||||
events:RegisterEvent("SPELL_QUEUE_EVENT")
|
||||
events:RegisterEvent("START_AUTOATTACK")
|
||||
events:RegisterEvent("STOP_AUTOATTACK")
|
||||
|
||||
+3
-3
@@ -363,9 +363,9 @@ end
|
||||
b:EnableMouse(true)
|
||||
|
||||
b:RegisterEvent("FACTION_STANDING_CHANGED")
|
||||
b:RegisterEvent("UNIT_PET")
|
||||
b:RegisterEvent("UNIT_LEVEL")
|
||||
b:RegisterEvent("UNIT_PET_EXPERIENCE")
|
||||
b:RegisterUnitEvent("UNIT_PET", "player")
|
||||
b:RegisterUnitEvent("UNIT_LEVEL", "player")
|
||||
b:RegisterUnitEvent("UNIT_PET_EXPERIENCE", "player", "pet")
|
||||
b:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
b:RegisterEvent("UPDATE_EXHAUSTION")
|
||||
b:RegisterEvent("PLAYER_XP_UPDATE")
|
||||
|
||||
Reference in New Issue
Block a user