Files
pfUI/pfUI.lua
T
brues-code 6b458c9e27 Modernize cast bars, unit-frame clicks, and mark tracking with ClassicAPI (#32)
* Migrate player castbar to ClassicAPI UNIT_SPELLCAST_* events

Drive the player cast path off ClassicAPI's synthesized, player-only
UNIT_SPELLCAST_* events instead of the vanilla SPELLCAST_* plus nampower
SPELL_{START,GO,DELAYED}_SELF mix. START/CHANNEL_START poll UnitCastingInfo/
UnitChannelInfo and stamp; STOP/CHANNEL_STOP/FAILED/INTERRUPTED clear;
SUCCEEDED drives tradeskill craft counting; DELAYED/CHANNEL_UPDATE re-poll.
Since UNIT_SPELLCAST_START fires for chained same-spell recasts, the nampower
SELF deps and their RunNextFrame co-hook-ordering workarounds are gone.
Remote target/focus bars keep SPELL_*_OTHER (the new events are player-only).

Fix the cast-start flash: StampBar now primes the fill on the stamp frame,
and ClearBar no longer snaps the bar to full (that snap lingered in the fade
tail and flashed when the next cast stamped).

Add a red flash on a cancelled cast: new appearance.castbar.failcolor,
flashed by ClearBar only when a cast was actually in progress.

Handle pushback Quartz-style: DELAYED/CHANNEL_UPDATE re-poll just the times
and accumulate the endMs shift into this.delay for the +/- indicator (cast
+X, channel -X), rather than a full restamp.

* Route target/focus castbars through remote UNIT_SPELLCAST_*

ClassicAPI now fires UNIT_SPELLCAST_* for remote tokens (target/focus/...)
via PollRemote, so drop the nampower SPELL_*_OTHER path and drive all three
bars off one event model. The gate is now token-based (arg1 == this.unitstr,
plus the arg1=="player" + UnitIsUnit case for target=self); the RunNextFrame
defer is gone since the remote poll fires after UnitCastingInfo is readable.
Cast detection is now nampower-free across every bar.

Use the event's rank payload (arg5): thread it through RefreshBar into
StampBar, which now only calls C_Spell.GetSpellSubtext as a fallback on the
retarget re-poll (PLAYER_TARGET/FOCUS_CHANGED) where no event is in hand.

* Drive nameplate castbars off UNIT_SPELLCAST_*

ClassicAPI now fires UNIT_SPELLCAST_* for nameplate tokens, so populate the
per-GUID castState cache from UNIT_SPELLCAST_{START,CHANNEL_START} (poll
PollCastInfo for the timing the payload omits) and clear it on
{STOP,CHANNEL_STOP} -- the remote poll fires STOP for natural end, interrupt,
and cancel alike. Replaces the nampower SPELL_{START,FAILED}_OTHER path; the
^nameplate arg1 gate ignores the target/focus/party fires of the same events,
and the NAME_PLATE_UNIT_ADDED seed still catches a plate spawning mid-cast.
Nameplate cast detection is now nampower-free.

* We no longer use these features from SuperWoW/Nampower

* Use secure unit attributes; remove mouseover scripts

Switch unitframes to attribute-driven clicks and remove mouseover tooltip handlers. Adds SetAttribute("unit") in UpdateVisibility and sets frame attributes (unit and type1='target') when creating frames. Removes OnEnter/OnLeave functions and their SetScript registrations and eliminates direct TargetUnit calls in ClickAction

* Use SetShown and simplify component default

Replace explicit Show/Hide conditionals in api/unitframes.lua with SetShown(...) for ressIcon, leaderIcon, lootIcon, pvpIcon, and restIcon to reduce branching and improve readability. Also remove the local shadowing of the parameter 'component' by using assignment (component = component or ""). No intended behavior changes.

* Drive unit-frame clicks via secure attributes

Replace the Lua OnClick dispatch (OnClick/ClickAction/RightClickAction) with
secure frame attributes: default type1=target / type2=menu, and EnableClickCast
now writes type/spell/macrotext/menu/target/focus attributes per button+modifier
instead of caching a clickactions table read at click time. Drops the now-dead
clickactions table and buttons list.

Also set a "unit" attribute on each frame (at creation and re-synced in
UpdateVisibility to the live token, so a party shown on the raid grid reports
partyN, not raidN) so the hovered unit resolves from the frame.

Match the target/focus/menu click keywords exactly rather than by prefix, so a
spell whose name starts with "focus"/"target"/"menu" (e.g. Focus Magic) casts
instead of being swallowed as the keyword action.

* Simplify marktracking colors and refresh per mark

Replace the hand-rolled ParseColor plus its default-color table with
GetStringColor -- the raidmarkercolor_* config keys already carry those same
defaults, so the fallback was dead code.

Restructure the refresh off observed mark tokens: UNIT_HEALTH/UNIT_MAXHEALTH
now arrive as arg1 == "markN", so refresh just that one row (UpdateRow) instead
of rescanning all eight on every nearby unit's health tick. A visibility flip
(into range / death / hp crossing 0) re-packs the rows, so UpdateRow hands off
to a full UpdateDisplay; RAID_TARGET_UPDATE / PLAYER_ENTERING_WORLD stay full
refreshes, with the 1s poll as the range-change backstop.

* not true anymore

* Poll marktracking fallback via C_Timer instead of OnUpdate

The 1s range-change safety net ran a per-frame OnUpdate that no-oped ~59 of
every 60 frames. Replace it with C_Timer.NewTicker(FALLBACK_INTERVAL,
UpdateDisplay) -- one wakeup per second off the shared timer driver -- and drop
the elapsed accumulator. The scanner frame is now purely event-driven.

* SuperWoW is now optional

* Update README feature list

Add 'Mouseover Unit Frames' and 'Click-casting' to the main features list. Update the SuperWoW entry to reflect that it tracks party/raid units on the minimap (replacing the prior SetMouseoverUnit note).

* Replace fixed-interval OnUpdate polls with C_Timer/RunNextFrame

Swap hand-rolled per-frame throttles for the modern timer primitives:

- turtle-wow: one-shot next-frame defer (self-hiding OnUpdate frame) -> RunNextFrame
- panel: clock, combat, and fps widgets -> NewTicker(1); guild roster -> NewTicker(60)
- minimap: coordinates text -> NewTicker(0.1)
- addonbuttons: one-shot init -> RunNextFrame; 5s button rescan -> NewTicker(5),
  guarded by IsShown() to preserve the old "paused while hidden" behavior

Ticker callbacks reference frames via upvalue since 'this' is unbound outside
OnUpdate. Genuine per-frame work (bar fills, fades, drag) and polls already
coordinated through pfUI.throttle are left as-is.

* update pfQuest link

* Use SetShown/SetSize in panel module

Replace manual Show/Hide toggles with SetShown(not ... ) and replace SetWidth/SetHeight with SetSize in modules/panel.lua. Changes simplify toggle logic (timer, WorldMap, chat hide buttons) and unify sizing calls for timer, frames, textures, and microbutton. No behavior changes intended; purely refactor for conciseness and consistency.

* Bump ClassicAPI min version to 1.9.0

* Drive reagent counter from events instead of a polling OnUpdate

The pfReagentCounter frame ran an OnUpdate that (1) progressively rescanned
all 120 action slots one-per-100ms on any slot change and (2) recounted
reagent inventory on a 1s throttle. Replace both with direct event handling:

- ACTIONBAR_SLOT_CHANGED updates just the changed slot (arg1), full-scanning
  only when arg1 is 0/nil, instead of restarting a ~12s rescan on every edit
- BAG_UPDATE_DELAYED recounts tracked reagents directly (it is already
  Blizzard's coalesced bag event, so the extra 1s throttle was redundant)
- PLAYER_ENTERING_WORLD seeds the full reagent map once

UpdateSlot now seeds a new reagent's real count via GetItemCount so a freshly
placed reagent spell shows the correct number immediately. The updatecache ->
BarsUpdate render path and the IsReagentAction/GetReagentCount accessors are
unchanged.
2026-08-04 14:27:15 -05:00

557 lines
18 KiB
Lua

SLASH_RELOAD1 = '/rl'
function SlashCmdList.RELOAD(msg, editbox)
ReloadUI()
end
SLASH_PFUI1 = '/pfui'
function SlashCmdList.PFUI(msg, editbox)
pfUI.gui:SetShown(not pfUI.gui:IsShown())
end
SLASH_GM1, SLASH_GM2 = '/gm', '/support'
function SlashCmdList.GM(msg, editbox)
ToggleHelpFrame(1)
end
pfUI = CreateFrame("Frame", nil, UIParent)
pfUI:RegisterEvent("ADDON_LOADED")
-- setup bootvar
pfUI.bootup = true
do
-- ClassicAPI dependency check.
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
-- API surface that ClassicAPI polyfills, so presence is required.
local PFUI_CLASSIC_API_MIN = 10900 -- (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"
local function FormatVersion(packed)
local x = math.floor(packed / 10000)
local y = math.floor(math.mod(packed, 10000) / 100)
local z = math.mod(packed, 100)
return string.format("v%d.%d.%d", x, y, z)
end
if not CLASSIC_API_VERSION or CLASSIC_API_VERSION < PFUI_CLASSIC_API_MIN then
local minVersion = FormatVersion(PFUI_CLASSIC_API_MIN)
pfUI.disabled = true
local detail
if not CLASSIC_API_VERSION then
detail = "The ClassicAPI DLL isn't loaded. The |cff33ffcc!!!ClassicAPI|r addon ships bundled with it -- delete your |cff33ffcc!!!ClassicAPI|r folder and install the latest release from:"
else
detail = "ClassicAPI " .. minVersion .. " or newer is required. Delete your |cff33ffcc!!!ClassicAPI|r folder and reinstall the latest release from:"
end
local function ShowRequiredPopup()
StaticPopupDialogs["PFUI_CLASSICAPI_REQUIRED"] = {
text = "|cff33ffccpf|cffffffffUI|r has been disabled.\n\n" .. detail,
button1 = OKAY,
hasEditBox = 1,
editBoxWidth = 280,
timeout = 0,
whileDead = 1,
hideOnEscape = 1,
preferredIndex = 3,
OnShow = function()
local editBox = getglobal(this:GetName().."EditBox")
if editBox then
editBox:SetText(PFUI_CLASSIC_API_LATEST_URL)
editBox:HighlightText()
editBox:SetFocus()
end
end,
}
StaticPopup_Show("PFUI_CLASSICAPI_REQUIRED")
DEFAULT_CHAT_FRAME:AddMessage(
"|cff33ffccpf|cffffffffUI|r disabled: " .. detail .. " " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.3, 0.3
)
end
local loginFrame = CreateFrame("Frame")
loginFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
loginFrame:SetScript("OnEvent", function()
loginFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
ShowRequiredPopup()
end)
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_LATEST then
EventUtil.ContinueOnPlayerLogin(function()
C_Timer.After(8, function()
DEFAULT_CHAT_FRAME:AddMessage(
"|cff33ffccpf|rUI: ClassicAPI " .. FormatVersion(PFUI_CLASSIC_API_LATEST) .. " is available — " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.85, 0.3
)
end)
end)
end
end
-- initialize saved variables
pfUI_playerDB = {}
pfUI_config = {}
pfUI_init = {}
pfUI_profiles = {}
pfUI_addon_profiles = {}
pfUI_cache = {}
pfUI_throttle = {}
-- localization
pfUI_locale = {}
pfUI_translation = {}
-- initialize default variables
pfUI.cache = {}
pfUI.module = {}
pfUI.modules = {}
pfUI.skin = {}
pfUI.skins = {}
pfUI.environment = {}
pfUI.movables = {}
pfUI.version = {}
pfUI.env = {}
if not pfUI.disabled then
pfUI.events = Mixin({}, CallbackRegistryMixin)
pfUI.events:OnLoad()
pfUI.events:SetUndefinedEventsAllowed(true)
end
-- check if macro addons are loaded (disables macrotweak/macroscan)
function pfUI:MacroAddonsLoaded()
return IsAddOnLoaded("Supermacro") or IsAddOnLoaded("SuperCleveRoidMacros") or IsAddOnLoaded("UltimaMacros")
end
-- detect current addon path
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in pairs(tocs) do
local current = string.format("pfUI%s", name)
local title = C_AddOns.GetAddOnName(current)
if title then
pfUI.name = current
pfUI.path = "Interface\\AddOns\\" .. current
break
end
end
-- handle/convert media dir paths
pfUI.media = setmetatable({}, { __index = function(tab,key)
local value = tostring(key)
if strfind(value, "img:") then
value = string.gsub(value, "img:", pfUI.path .. "\\img\\")
elseif strfind(value, "font:") then
value = string.gsub(value, "font:", pfUI.path .. "\\fonts\\")
else
value = string.gsub(value, "Interface\\AddOns\\pfUI\\", pfUI.path .. "\\")
end
rawset(tab,key,value)
return value
end})
-- cache client version
local _, _, _, client = GetBuildInfo()
pfUI.client = client or 11200
-- setup pfUI namespace
setmetatable(pfUI.env, {__index = getfenv(0)})
PFUI_CLASS_COLORS = setmetatable({
WARRIOR = { r = 0.78, g = 0.61, b = 0.43 },
MAGE = { r = 0.25, g = 0.78, b = 0.92 },
ROGUE = { r = 1, g = 0.96, b = 0.41 },
DRUID = { r = 1, g = 0.49, b = 0.04 },
HUNTER = { r = 0.67, g = 0.83, b = 0.45 },
SHAMAN = { r = 0, g = 0.44, b = 0.87 },
PRIEST = { r = 1, g = 1, b = 1 },
WARLOCK = { r = 0.53, g = 0.53, b = 0.93 },
PALADIN = { r = 0.96, g = 0.55, b = 0.73 },
}, { __index = function(t,k)
local unknownColor = CreateColor(0.6, 0.6, 0.6, 1)
unknownColor.colorStr = unknownColor:GenerateHexColor()
return unknownColor
end})
for _, classColor in pairs(PFUI_CLASS_COLORS) do
Mixin(classColor, ColorMixin)
classColor.a = 1
classColor.colorStr = classColor:GenerateHexColor()
end
function pfUI:UpdateFonts()
-- abort when config is not ready yet
if not pfUI_config or not pfUI_config.global then return end
-- load font configuration
local default, tooltip, unit, unit_name, combat
if pfUI_config.global.force_region == "1" and GetLocale() == "zhCN" then
-- force locale compatible fonts (zhCN 1.12)
default = "Fonts\\FZXHLJW.TTF"
tooltip = "Fonts\\FZXHLJW.TTF"
combat = "Fonts\\FZXHLJW.TTF"
unit = "Fonts\\FZXHLJW.TTF"
unit_name = "Fonts\\FZXHLJW.TTF"
elseif pfUI_config.global.force_region == "1" and GetLocale() == "zhTW" then
-- force locale compatible fonts (zhTW 1.12)
default = "Fonts\\FZXHLJW.ttf"
tooltip = "Fonts\\FZXHLJW.ttf"
combat = "Fonts\\FZXHLJW.ttf"
unit = "Fonts\\FZXHLJW.ttf"
unit_name = "Fonts\\FZXHLJW.ttf"
elseif pfUI_config.global.force_region == "1" and GetLocale() == "koKR" then
-- force locale compatible fonts (koKR)
default = "Fonts\\2002.TTF"
tooltip = "Fonts\\2002.TTF"
combat = "Fonts\\2002.TTF"
unit = "Fonts\\2002.TTF"
unit_name = "Fonts\\2002.TTF"
else
-- use default entries
default = pfUI.media[pfUI_config.global.font_default]
tooltip = pfUI.media[pfUI_config.tooltip.font_tooltip]
combat = pfUI.media[pfUI_config.global.font_combat]
unit = pfUI.media[pfUI_config.global.font_unit]
unit_name = pfUI.media[pfUI_config.global.font_unit_name]
end
-- write setting shortcuts
pfUI.font_default = default
pfUI.font_combat = combat
pfUI.font_unit = unit
pfUI.font_unit_name = unit_name
-- skip setting fonts, keep blizzard defaults
if pfUI_config.global.font_blizzard == "1" then
return
end
-- set game constants
STANDARD_TEXT_FONT = default
DAMAGE_TEXT_FONT = combat
NAMEPLATE_FONT = default
UNIT_NAME_FONT = unit_name
-- If the Invisible font is selected, suppress all combat text entirely
if string.find(combat or "", "AdobeBlank") then
SHOW_COMBAT_TEXT = "0"
end
-- set dropdown font to default size
UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT = 11
-- change default game font objects
SystemFont:SetFont(default, 15)
GameFontNormal:SetFont(default, 12)
GameFontBlack:SetFont(default, 12)
GameFontNormalSmall:SetFont(default, 11)
GameFontNormalLarge:SetFont(default, 16)
GameFontNormalHuge:SetFont(default, 20)
NumberFontNormal:SetFont(default, 14, "OUTLINE")
NumberFontNormalSmall:SetFont(default, 14, "OUTLINE")
NumberFontNormalLarge:SetFont(default, 16, "OUTLINE")
NumberFontNormalHuge:SetFont(default, 30, "OUTLINE")
QuestTitleFont:SetFont(default, 18)
QuestFont:SetFont(default, 13)
QuestFontHighlight:SetFont(default, 14)
ItemTextFontNormal:SetFont(default, 15)
MailTextFontNormal:SetFont(default, 15)
SubSpellFont:SetFont(default, 12)
DialogButtonNormalText:SetFont(default, 16)
ZoneTextFont:SetFont(default, 34, "OUTLINE")
SubZoneTextFont:SetFont(default, 24, "OUTLINE")
GameTooltipText:SetFont(tooltip, pfUI_config.tooltip.font_tooltip_size)
GameTooltipTextSmall:SetFont(tooltip, pfUI_config.tooltip.font_tooltip_size)
GameTooltipHeaderText:SetFont(tooltip, pfUI_config.tooltip.font_tooltip_size + 1)
WorldMapTextFont:SetFont(default, 102, "THICK")
InvoiceTextFontNormal:SetFont(default, 12)
InvoiceTextFontSmall:SetFont(default, 12)
CombatTextFont:SetFont(combat, 25)
ChatFontNormal:SetFont(default, 13, pfUI_config.chat.text.outline == "1" and "OUTLINE")
if TextStatusBarTextSmall then -- does not exist in koKR
TextStatusBarTextSmall:SetFont(default, 12, "NORMAL")
end
end
local translations
function pfUI:GetEnvironment()
-- load api into environment
for m, func in pairs(pfUI.api or {}) do
pfUI.env[m] = func
end
if pfUI_config and pfUI_config.global and pfUI_config.global.language and not translations then
local lang = pfUI_config and pfUI_config.global and pfUI_config.global.language and pfUI_translation[pfUI_config.global.language] and pfUI_config.global.language or GetLocale()
pfUI.env.T = setmetatable(pfUI_translation[lang] or {}, { __index = function(tab,key)
local value = tostring(key)
rawset(tab,key,value)
return value
end})
translations = true
end
pfUI.env._G = getfenv(0)
pfUI.env.C = pfUI_config
pfUI.env.pfUI_throttle = _G.pfUI_throttle
pfUI.env.L = (pfUI_locale[GetLocale()] or pfUI_locale["enUS"])
return pfUI.env
end
-- [ New Module Registry ]
-- Tracks modules introduced after initial release so existing users get
-- a one-time prompt asking if they want to enable them.
pfUI.new_modules = {}
function pfUI:RegisterNewModule(name, label, class)
table.insert(pfUI.new_modules, { name = name, label = label, class = class })
end
function pfUI:CheckNewModules()
pfUI_init.seen_modules = pfUI_init.seen_modules or {}
local pending = 0
local playerClass = UnitClassBase("player")
for _, entry in pairs(pfUI.new_modules) do
if not pfUI_init.seen_modules[entry.name] and pfUI_init["finalize"] then
if not entry.class or entry.class == playerClass then
pending = pending + 1
end
end
end
if pending == 0 then return end
local remaining = pending
local needsReload = false
local function onAnswer()
remaining = remaining - 1
if remaining <= 0 and needsReload then
ReloadUI()
end
end
for _, entry in pairs(pfUI.new_modules) do
local name = entry.name
if not pfUI_init.seen_modules[name] then
-- Skip modules restricted to a different class
if entry.class and entry.class ~= playerClass then
-- don't mark as seen - player might have a druid alt later
else
pfUI_init.seen_modules[name] = true
-- Only prompt existing users (firstrun wizard already ran)
if pfUI_init["finalize"] then
StaticPopupDialogs["PFUI_NEW_MODULE_" .. strupper(name)] = {
text = "|cff33ffccpfUI|r: New module available!\n\n|cffffffffDo you want to enable |cff33ffcc" .. (entry.label or name) .. "|r|cffffffff?\n\nYou can always change this later in the pfUI settings.|r",
button1 = "Yes",
button2 = "No",
OnAccept = function()
pfUI_config["disabled"] = pfUI_config["disabled"] or {}
pfUI_config["disabled"][name] = nil
onAnswer()
end,
OnCancel = function()
pfUI_config["disabled"] = pfUI_config["disabled"] or {}
pfUI_config["disabled"][name] = "1"
needsReload = true
onAnswer()
end,
timeout = 0,
whileDead = true,
hideOnEscape = false,
}
StaticPopup_Show("PFUI_NEW_MODULE_" .. strupper(name))
end
end -- else (class match)
end
end
end
local function BackwardsCompatRegister(func, arg3)
if arg3 and type(func) == "string" and type(arg3) == "function" and string.find(func, "vanilla") then
return arg3
end
return func
end
function pfUI:RegisterModule(name, func, arg3)
if pfUI.disabled then return end
if pfUI.module[name] then return end
func = BackwardsCompatRegister(func, arg3)
pfUI.module[name] = func
table.insert(pfUI.modules, name)
if not pfUI.bootup then
pfUI:LoadModule(name)
end
end
function pfUI:RegisterSkin(name, func, arg3)
if pfUI.disabled then return end
if pfUI.skin[name] then return end
func = BackwardsCompatRegister(func, arg3)
pfUI.skin[name] = func
table.insert(pfUI.skins, name)
if not pfUI.bootup then
pfUI:LoadSkin(name)
end
end
function pfUI:LoadModule(m)
setfenv(pfUI.module[m], pfUI:GetEnvironment())
pfUI.module[m]()
end
function pfUI:LoadSkin(s)
setfenv(pfUI.skin[s], pfUI:GetEnvironment())
pfUI.skin[s]()
end
pfUI:SetScript("OnEvent", function()
if pfUI.disabled then return end
-- make sure to initialize and set our fonts
-- each time an addon got loaded but only
-- when the config is already accessible
if not pfUI.bootup then
pfUI:UpdateFonts()
end
if arg1 == pfUI.name then
-- read pfUI version from .toc file. Source/dev installs leave Version as
-- "@project-version@" until release tooling substitutes it — mark those
-- explicitly as "dev" instead of pretending they're a real numbered build.
local raw = tostring(GetAddOnMetadata(pfUI.name, "Version"))
if strfind(raw, "@") then
pfUI.version.major, pfUI.version.minor, pfUI.version.fix = 0, 0, 0
pfUI.version.string = "dev"
else
local major, minor, fix = pfUI.api.strsplit(".", raw)
pfUI.version.major = tonumber(major) or 0
pfUI.version.minor = tonumber(minor) or 0
pfUI.version.fix = tonumber(fix) or 0
pfUI.version.string = pfUI.version.major .. "." .. pfUI.version.minor .. "." .. pfUI.version.fix
end
-- use "Modern" as default profile on a fresh install
if pfUI.api.isempty(pfUI_init) and pfUI.api.isempty(pfUI_config) then
pfUI_config = pfUI.api.CopyTable(pfUI_profiles["Modern"]) or {}
end
pfUI:LoadConfig()
pfUI:MigrateConfig()
pfUI:UpdateFonts()
-- load modules
for _, m in pairs(this.modules) do
if not ( pfUI_config["disabled"] and pfUI_config["disabled"][m] == "1" ) then
pfUI:LoadModule(m)
end
end
-- load skins
for _, s in pairs(this.skins) do
if not ( pfUI_config["disabled"] and pfUI_config["disabled"]["skin_" .. s] == "1" ) then
pfUI:LoadSkin(s)
end
end
pfUI.bootup = nil
-- Prompt existing users about newly introduced modules
pfUI:CheckNewModules()
end
end)
pfUI.backdrop = {
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0,
edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = 1,
insets = {left = -1, right = -1, top = -1, bottom = -1},
}
pfUI.backdrop_no_top = pfUI.backdrop
pfUI.backdrop_thin = {
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0,
edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = 1,
insets = {left = 0, right = 0, top = 0, bottom = 0},
}
pfUI.backdrop_hover = {
edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = 24,
insets = {left = -1, right = -1, top = -1, bottom = -1},
}
pfUI.backdrop_shadow = {
edgeFile = pfUI.media["img:glow2"], edgeSize = 8,
insets = {left = 0, right = 0, top = 0, bottom = 0},
}
pfUI.backdrop_blizz_bg = {
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
}
pfUI.backdrop_blizz_border = {
edgeFile = pfUI.media["img:border_blizz"], edgeSize = 6,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
}
pfUI.backdrop_blizz_full = {
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = true, tileSize = 8,
edgeFile = pfUI.media["img:border_blizz"], edgeSize = 6,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
}
message = function(msg)
DEFAULT_CHAT_FRAME:AddMessage("|cffcccc33INFO: |cffffff55" .. ( msg or "nil" ))
end
print = print or message
error = function(msg)
if PF_DEBUG_MODE then message(debugstack()) end
if string.find(msg, "AddOns\\pfUI") then
DEFAULT_CHAT_FRAME:AddMessage("|cffcc3333ERROR: |cffff5555".. (msg or "nil" ))
elseif not pfUI_config or (pfUI_config.global and pfUI_config.global.errors == "1") then
DEFAULT_CHAT_FRAME:AddMessage("|cffcc3333ERROR: |cffff5555".. (msg or "nil" ))
end
end
seterrorhandler(error)
function pfUI.SetupCVars()
ClearTutorials()
TutorialFrame_HideAllAlerts()
ConsoleExec("CameraDistanceMaxFactor 5")
SetCVar("autoSelfCast", "1")
SetCVar("profanityFilter", "0")
MultiActionBar_ShowAllGrids()
ALWAYS_SHOW_MULTIBARS = "1"
SHOW_BUFF_DURATIONS = "1"
QUEST_FADING_DISABLE = "1"
NAMEPLATES_ON = "1"
SIMPLE_CHAT = "0"
-- Only force combat text CVars when not using the Invisible font.
-- If AdobeBlank is selected, the player wants no combat text -- respect that.
local isInvisible = pfUI_config.global.font_combat and
string.find(pfUI_config.global.font_combat, "AdobeBlank")
if not isInvisible then
SHOW_COMBAT_TEXT = "1"
COMBAT_TEXT_SHOW_LOW_HEALTH_MANA = "1"
COMBAT_TEXT_SHOW_AURAS = "1"
COMBAT_TEXT_SHOW_AURA_FADE = "1"
COMBAT_TEXT_SHOW_COMBAT_STATE = "1"
COMBAT_TEXT_SHOW_DODGE_PARRY_MISS = "1"
COMBAT_TEXT_SHOW_RESISTANCES = "1"
COMBAT_TEXT_SHOW_REPUTATION = "1"
COMBAT_TEXT_SHOW_REACTIVES = "1"
COMBAT_TEXT_SHOW_FRIENDLY_NAMES = "1"
COMBAT_TEXT_SHOW_COMBO_POINTS = "1"
COMBAT_TEXT_SHOW_MANA = "1"
COMBAT_TEXT_FLOAT_MODE = "1"
COMBAT_TEXT_SHOW_HONOR_GAINED = "1"
end
UIParentLoadAddOn("Blizzard_CombatText")
end