The option to hide Blizzard's floating XP text was removed in 1.0.1, so the Features section now only covers hiding the XP chat line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
531 lines
21 KiB
Lua
531 lines
21 KiB
Lua
--[[
|
|
================================================================================
|
|
XP Percent - XPPercent.lua (core)
|
|
================================================================================
|
|
Shows every XP gain as a percentage of your current level ("+1.25% XP")
|
|
instead of Blizzard's flat number ("XP: 200").
|
|
|
|
What this file does:
|
|
1. Saved settings - loads/creates XPPercentDB and fills in defaults.
|
|
2. Popup - the floating purple text that rises and fades out.
|
|
3. Drag-to-move - "unlock" mode that lets the player drag the popup.
|
|
4. Blizzard text - optionally hides Blizzard's own XP chat line.
|
|
5. XP tracking - compares XP before/after each gain to get the %.
|
|
6. Events - wires all of the above to game events.
|
|
7. Slash commands - /xpp and /xppercent.
|
|
|
|
The options window lives in Options.lua. The two files share functions
|
|
through the addon namespace table `ns` (see below).
|
|
================================================================================
|
|
--]]
|
|
|
|
-- Every addon file receives two values from the game when it loads:
|
|
-- ADDON - the addon's folder name ("XPPercent")
|
|
-- ns - a private table shared by all of this addon's files. We put
|
|
-- functions on it (ns.Show, ns.DB, ...) so Options.lua can use them
|
|
-- without creating global variables.
|
|
local ADDON, ns = ...
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 1. SAVED SETTINGS
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Default value for every setting. Anything missing from the saved settings
|
|
-- (first install, or a new option added in an update) is filled from here.
|
|
local defaults = {
|
|
hideChat = true, -- hide Blizzard's "You gain 200 experience." chat line
|
|
chat = false, -- also print our own "+1.25% XP" line in chat
|
|
popup = true, -- show our floating popup text
|
|
decimals = 2, -- digits after the decimal point (0-4)
|
|
size = 26, -- popup font size
|
|
x = 0, -- popup horizontal offset from screen center (pixels)
|
|
y = 60, -- popup vertical offset from screen center (pixels)
|
|
color = { r = 0.75, g = 0.4, b = 1 }, -- popup color (0-1 per channel), purple
|
|
}
|
|
ns.defaults = defaults -- Options.lua uses this for the "Reset" buttons
|
|
|
|
--[[
|
|
DB() - returns the saved settings table, creating it if needed.
|
|
|
|
XPPercentDB is a *global* listed under "## SavedVariables" in the .toc file.
|
|
The game saves it to disk on logout and restores it on the next login.
|
|
It is nil until saved variables load, so every caller goes through DB().
|
|
--]]
|
|
local function DB()
|
|
XPPercentDB = XPPercentDB or {}
|
|
|
|
-- Remove settings from older versions that no longer exist:
|
|
-- hideFloat - "hide Blizzard's floating XP text" (removed in 1.0.1)
|
|
-- debugLog - log from a debug command used during development
|
|
XPPercentDB.hideFloat = nil
|
|
XPPercentDB.debugLog = nil
|
|
|
|
-- Fill in any missing settings from the defaults.
|
|
for key, value in pairs(defaults) do
|
|
if XPPercentDB[key] == nil then
|
|
-- Tables (like `color`) must be copied. Otherwise the saved settings and
|
|
-- `defaults` would be the same table, so changing the color would also
|
|
-- change the default and "Reset color" would stop working.
|
|
if type(value) == "table" then
|
|
local copy = {}
|
|
for k2, v2 in pairs(value) do copy[k2] = v2 end
|
|
value = copy
|
|
end
|
|
XPPercentDB[key] = value
|
|
end
|
|
end
|
|
|
|
return XPPercentDB
|
|
end
|
|
ns.DB = DB
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 2. THE POPUP (floating "+1.25% XP" text)
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- The container frame. It is attached to UIParent (the main game UI), so it
|
|
-- hides with the rest of the UI when the player presses Alt+Z.
|
|
local popup = CreateFrame("Frame", nil, UIParent)
|
|
popup:SetSize(300, 40) -- real size is set by ApplyStyle() once settings load
|
|
popup:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
|
|
|
|
-- "Strata" is the drawing layer. DIALOG is above the options window, so the
|
|
-- "Test popup" button's preview isn't hidden behind it.
|
|
popup:SetFrameStrata("DIALOG")
|
|
|
|
-- The text itself. The real font size and color are applied in ApplyStyle().
|
|
popup.text = popup:CreateFontString(nil, "OVERLAY")
|
|
popup.text:SetFont(STANDARD_TEXT_FONT, 26, "OUTLINE")
|
|
popup.text:SetPoint("CENTER")
|
|
popup.text:SetTextColor(0.75, 0.4, 1)
|
|
popup:Hide() -- hidden until there's something to show
|
|
|
|
-- Animation: drift up 70 pixels over 1.6 seconds while fading out.
|
|
-- Both animations are in one group, so they play at the same time.
|
|
local ag = popup:CreateAnimationGroup()
|
|
|
|
local move = ag:CreateAnimation("Translation")
|
|
move:SetOffset(0, 70) -- move 0 px sideways, 70 px up
|
|
move:SetDuration(1.6) -- seconds
|
|
|
|
local fade = ag:CreateAnimation("Alpha")
|
|
fade:SetFromAlpha(1) -- fully visible...
|
|
fade:SetToAlpha(0) -- ...to invisible
|
|
fade:SetStartDelay(0.9) -- stay solid for 0.9 s first, so it's readable
|
|
fade:SetDuration(0.7) -- then fade over 0.7 s (0.9 + 0.7 = 1.6 s total)
|
|
|
|
-- When the animation ends, hide the frame. Translation/alpha effects only
|
|
-- apply while playing, so the frame snaps back to its normal spot invisibly.
|
|
ag:SetScript("OnFinished", function() popup:Hide() end)
|
|
|
|
--[[
|
|
ApplyStyle() - applies the saved font size, color and position to the popup.
|
|
Called at login and whenever a setting changes (options window, slash commands).
|
|
--]]
|
|
local function ApplyStyle()
|
|
local db = DB()
|
|
|
|
popup.text:SetFont(STANDARD_TEXT_FONT, db.size, "OUTLINE")
|
|
popup.text:SetTextColor(db.color.r, db.color.g, db.color.b)
|
|
|
|
-- Size the box to fit the font. You can't see the box normally, but in
|
|
-- drag-to-move mode it's the blue area you grab, so it should cover the text.
|
|
popup:SetSize(math.max(300, db.size * 11), db.size + 14)
|
|
|
|
-- Position is stored as an offset from the center of the screen. That keeps
|
|
-- it in roughly the same spot across different resolutions and UI scales.
|
|
popup:ClearAllPoints()
|
|
popup:SetPoint("CENTER", UIParent, "CENTER", db.x, db.y)
|
|
end
|
|
ns.ApplyStyle = ApplyStyle
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 3. DRAG-TO-MOVE MODE
|
|
--------------------------------------------------------------------------------
|
|
-- When unlocked, the popup stays on screen as a translucent blue box with
|
|
-- sample text, and the player can drag it with the left mouse button.
|
|
-- Releasing it saves the new position. Locking hides it again.
|
|
|
|
local unlocked = false -- true while drag-to-move mode is on
|
|
local SAMPLE = "+1.25% XP" -- placeholder text shown while unlocked
|
|
|
|
-- Translucent blue background so the player can see what to grab.
|
|
local moverBg = popup:CreateTexture(nil, "BACKGROUND")
|
|
moverBg:SetAllPoints() -- fill the whole popup frame
|
|
moverBg:SetColorTexture(0, 0.6, 1, 0.3) -- r, g, b, alpha (30% opaque blue)
|
|
moverBg:Hide()
|
|
|
|
-- Small instruction line shown just below the box.
|
|
local moverHint = popup:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
moverHint:SetPoint("TOP", popup, "BOTTOM", 0, -4)
|
|
moverHint:SetText("Drag to move. Click \"Lock popup\" in options or type /xpp lock when done.")
|
|
moverHint:Hide()
|
|
|
|
popup:SetMovable(true) -- allow StartMoving() on this frame
|
|
popup:SetClampedToScreen(true) -- can't be dragged off the edge of the screen
|
|
popup:EnableMouse(false) -- clicks pass through while locked (normal play)
|
|
popup:RegisterForDrag("LeftButton")
|
|
|
|
-- Start following the mouse when a drag begins (only while unlocked).
|
|
popup:SetScript("OnDragStart", function(self)
|
|
if unlocked then self:StartMoving() end
|
|
end)
|
|
|
|
-- Drag ended: work out where the box is relative to screen center and save it.
|
|
popup:SetScript("OnDragStop", function(self)
|
|
self:StopMovingOrSizing()
|
|
|
|
local db = DB()
|
|
local cx, cy = self:GetCenter() -- popup center
|
|
local ux, uy = UIParent:GetCenter() -- screen center
|
|
-- Round to whole pixels so the saved numbers are tidy.
|
|
db.x = math.floor(cx - ux + 0.5)
|
|
db.y = math.floor(cy - uy + 0.5)
|
|
|
|
-- StartMoving() re-anchors the frame to a screen corner. Re-apply our
|
|
-- center-based anchor using the offset we just saved.
|
|
ApplyStyle()
|
|
|
|
-- Let the options window update its "Position: x, y" readout (if loaded).
|
|
if ns.OnPositionChanged then ns.OnPositionChanged() end
|
|
end)
|
|
|
|
--[[
|
|
SetUnlocked(on) - turns drag-to-move mode on (true) or off (false).
|
|
--]]
|
|
local function SetUnlocked(on)
|
|
unlocked = on and true or false -- force a real boolean
|
|
|
|
ag:Stop() -- cancel any popup currently animating
|
|
popup:EnableMouse(unlocked) -- only catch the mouse while unlocked
|
|
moverBg:SetShown(unlocked)
|
|
moverHint:SetShown(unlocked)
|
|
|
|
if unlocked then
|
|
popup.text:SetText(SAMPLE)
|
|
popup:Show() -- stays visible until locked again
|
|
else
|
|
popup:Hide()
|
|
end
|
|
|
|
-- Update the options window's "Unlock popup"/"Lock popup" button text.
|
|
if ns.OnPositionChanged then ns.OnPositionChanged() end
|
|
end
|
|
ns.SetUnlocked = SetUnlocked
|
|
ns.IsUnlocked = function() return unlocked end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 4. HIDING BLIZZARD'S OWN XP TEXT
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- Only the chat line can be hidden. Earlier versions also tried to hide the
|
|
-- floating XP text by filtering Blizzard's CombatText frame. That never
|
|
-- caught it: on newer clients (confirmed on the _forever_ client) the
|
|
-- in-world "XP: 200" text is drawn by the game engine, which addons can't
|
|
-- intercept, so the option was removed.
|
|
|
|
--[[
|
|
XPFilter() - chat filter for Blizzard's "You gain 200 experience." line.
|
|
|
|
Chat filters return true to hide a message and false/nil to let it through.
|
|
|
|
Two deliberate limits:
|
|
- It never reads the message text. That text may be a secret value on
|
|
newer clients, and we don't need it anyway.
|
|
- It doesn't change any addon state, because the game calls it once for
|
|
*each* chat window showing XP messages, not once per message.
|
|
--]]
|
|
local function XPFilter()
|
|
return XPPercentDB and XPPercentDB.hideChat
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 5. SHOWING A GAIN + XP TRACKING
|
|
--------------------------------------------------------------------------------
|
|
|
|
--[[
|
|
Show(pct, kind) - displays one XP gain.
|
|
pct - percent of a level gained, e.g. 1.25
|
|
kind - label after the number: "XP" or "XP (quest)"
|
|
--]]
|
|
local function Show(pct, kind)
|
|
local db = DB()
|
|
|
|
-- Build "+1.25%". The format is assembled from the decimals setting, e.g.
|
|
-- decimals = 2 gives "+%.2f%%". (%% is a literal % sign in string.format.)
|
|
local s = string.format("+%." .. db.decimals .. "f%%", pct)
|
|
|
|
-- Optional chat line, in the same color as the popup.
|
|
-- |cffRRGGBB starts a color in WoW text and |r ends it; RRGGBB is hex 00-ff.
|
|
if db.chat then
|
|
local c = db.color
|
|
local hex = string.format("|cff%02x%02x%02x", c.r * 255, c.g * 255, c.b * 255)
|
|
DEFAULT_CHAT_FRAME:AddMessage(hex .. s .. " " .. kind .. "|r")
|
|
end
|
|
|
|
if unlocked then
|
|
-- In drag-to-move mode, just update the text without animating, so the
|
|
-- box doesn't float away while the player is placing it.
|
|
popup.text:SetText(s .. " " .. kind)
|
|
elseif db.popup then
|
|
popup.text:SetText(s .. " " .. kind)
|
|
ag:Stop() -- restart from the beginning if a popup is already playing
|
|
popup:Show()
|
|
ag:Play()
|
|
end
|
|
end
|
|
ns.Show = Show
|
|
|
|
-- XP values from the previous update. Each gain is "now minus last time".
|
|
local lastXP, lastMax, lastLevel
|
|
|
|
-- Highest level PLAYER_LEVEL_UP has told us about. That event passes the new
|
|
-- level before UnitLevel() reports it, so this can be ahead of UnitLevel().
|
|
local knownLevel = 0
|
|
|
|
--[[
|
|
CurrentLevel() - the player's level, using whichever source is further
|
|
ahead: UnitLevel() or the last PLAYER_LEVEL_UP.
|
|
--]]
|
|
local function CurrentLevel()
|
|
return math.max(UnitLevel("player"), knownLevel)
|
|
end
|
|
|
|
-- Quest labelling: QUEST_TURNED_IN fires just before its XP arrives. We note
|
|
-- the time, and an XP gain within QUEST_WINDOW seconds is labelled
|
|
-- "XP (quest)". Quests that report no XP reward are skipped (see
|
|
-- QUEST_TURNED_IN below); the time limit is a backstop, so a label whose XP
|
|
-- never arrives can't mislabel some later, unrelated kill.
|
|
local pendingKind, pendingTime = "XP", 0
|
|
local QUEST_WINDOW = 2 -- seconds
|
|
|
|
--[[
|
|
Snapshot() - remembers current XP, XP needed for the level, and level.
|
|
--]]
|
|
local function Snapshot()
|
|
lastXP = UnitXP("player") -- XP earned so far this level
|
|
lastMax = UnitXPMax("player") -- XP needed to finish this level
|
|
lastLevel = CurrentLevel()
|
|
end
|
|
|
|
--[[
|
|
OnXPUpdate() - runs on every PLAYER_XP_UPDATE. Works out the % gained
|
|
since the last update and shows it.
|
|
--]]
|
|
local function OnXPUpdate()
|
|
local xp, max, lvl = UnitXP("player"), UnitXPMax("player"), CurrentLevel()
|
|
|
|
-- Need a previous snapshot to compare against. lastMax > 0 avoids dividing
|
|
-- by zero (UnitXPMax can be 0 at max level).
|
|
if lastXP and lastMax and lastMax > 0 then
|
|
local pct
|
|
|
|
-- LEVEL-UP CHECK. Either sign means the player leveled:
|
|
-- - XP went *down*: it reset to 0 plus the overflow. This is the usual
|
|
-- sign, and it works even when the game fires PLAYER_XP_UPDATE
|
|
-- *before* the new level shows up.
|
|
-- - The level went up: catches a gain worth more than a whole level,
|
|
-- where the new XP ends up *higher* than before (e.g. a huge quest
|
|
-- turn-in at a low level). "xp ~= lastXP" skips level changes that
|
|
-- came with no XP gain.
|
|
if xp < lastXP or (lvl > lastLevel and xp ~= lastXP) then
|
|
-- Total = what was left of the old level
|
|
-- + 100% for any whole levels skipped (rare; huge quest turn-ins)
|
|
-- + how far into the new level we are now.
|
|
-- lvl - lastLevel is 1 for a normal level-up, so extraLevels is usually 0.
|
|
-- math.max keeps it from going negative if the level hasn't caught up.
|
|
local extraLevels = math.max(0, (lvl - lastLevel) - 1)
|
|
pct = (lastMax - lastXP) / lastMax * 100
|
|
+ extraLevels * 100
|
|
+ (max > 0 and xp / max * 100 or 0)
|
|
else
|
|
-- Normal gain within the same level.
|
|
pct = (xp - lastXP) / lastMax * 100
|
|
end
|
|
|
|
-- Only show real gains (no-change updates happen too).
|
|
if pct > 0 then
|
|
local recentQuest = (GetTime() - pendingTime <= QUEST_WINDOW)
|
|
local kind = recentQuest and pendingKind or "XP"
|
|
Show(pct, kind)
|
|
|
|
-- The quest label has been used (or was stale), so clear it. This only
|
|
-- happens after a real gain: a no-change update arriving between the
|
|
-- turn-in and its XP must not wipe the label.
|
|
pendingKind, pendingTime = "XP", 0
|
|
end
|
|
end
|
|
|
|
-- Save this update's values for next time.
|
|
Snapshot()
|
|
end
|
|
|
|
--[[
|
|
QuestGivesXP(xpReward) - false only if QUEST_TURNED_IN says for certain the
|
|
quest gave no XP (e.g. at max level). If the value is missing (older
|
|
clients) or secret (can't be read), we assume it might give XP.
|
|
--]]
|
|
local function QuestGivesXP(xpReward)
|
|
if issecretvalue and issecretvalue(xpReward) then return true end
|
|
if type(xpReward) ~= "number" then return true end
|
|
return xpReward > 0
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 6. EVENTS
|
|
--------------------------------------------------------------------------------
|
|
-- An invisible frame that receives game events and passes them to the code above.
|
|
|
|
local f = CreateFrame("Frame")
|
|
f:RegisterEvent("PLAYER_LOGIN") -- logged in / UI reloaded; saved variables are ready
|
|
f:RegisterEvent("PLAYER_XP_UPDATE") -- XP changed
|
|
f:RegisterEvent("PLAYER_LEVEL_UP") -- leveled up
|
|
f:RegisterEvent("QUEST_TURNED_IN") -- turned in a quest (its XP arrives right after)
|
|
|
|
-- arg1, arg2 are the event's first two arguments, e.g. the new level for
|
|
-- PLAYER_LEVEL_UP, or the quest ID and XP reward for QUEST_TURNED_IN.
|
|
f:SetScript("OnEvent", function(_, event, arg1, arg2)
|
|
if event == "PLAYER_LOGIN" then
|
|
-- Make sure saved settings exist and have every default.
|
|
DB()
|
|
|
|
-- Register the chat filter that hides Blizzard's XP line. Newer clients
|
|
-- moved this function into ChatFrameUtil, so try that name first.
|
|
local add = (ChatFrameUtil and ChatFrameUtil.AddMessageEventFilter)
|
|
or ChatFrame_AddMessageEventFilter
|
|
if add then add("CHAT_MSG_COMBAT_XP_GAIN", XPFilter) end
|
|
|
|
-- Apply saved look/position, and add our page to the game's Options menu
|
|
-- (InitOptions comes from Options.lua).
|
|
ApplyStyle()
|
|
if ns.InitOptions then ns.InitOptions() end
|
|
|
|
-- Starting point for measuring the first gain.
|
|
Snapshot()
|
|
|
|
elseif event == "QUEST_TURNED_IN" then
|
|
-- Label the next XP gain (if it arrives within QUEST_WINDOW) as quest XP.
|
|
-- arg2 is the quest's XP reward. Skip quests that gave none, so a later
|
|
-- kill isn't mislabelled.
|
|
if QuestGivesXP(arg2) then
|
|
pendingKind, pendingTime = "XP (quest)", GetTime()
|
|
end
|
|
|
|
elseif event == "PLAYER_LEVEL_UP" then
|
|
-- arg1 is the new level. UnitLevel may not show it yet, so remember it.
|
|
if type(arg1) == "number" and not (issecretvalue and issecretvalue(arg1)) then
|
|
knownLevel = math.max(knownLevel, arg1)
|
|
|
|
-- If XP still equals our last snapshot, this level-up's XP gain has
|
|
-- already been counted (it arrived before this event). Catch lastLevel
|
|
-- up now, or the next gain would look like another level-up.
|
|
-- Otherwise the gain is still on its way, and OnXPUpdate will see the
|
|
-- higher level and count it as a level-up.
|
|
if lastXP and UnitXP("player") == lastXP and lastLevel then
|
|
lastLevel = math.max(lastLevel, arg1)
|
|
end
|
|
end
|
|
|
|
-- UnitXPMax can still return the *old* level's max right after leveling.
|
|
-- Re-read max and level after 1 second, so the next gain is divided by
|
|
-- the new level's max. Only these two are updated; lastXP stays correct.
|
|
-- math.max: never move lastLevel backwards.
|
|
if C_Timer and C_Timer.After then
|
|
C_Timer.After(1, function()
|
|
lastMax = UnitXPMax("player")
|
|
lastLevel = math.max(lastLevel or 0, CurrentLevel())
|
|
end)
|
|
end
|
|
|
|
elseif event == "PLAYER_XP_UPDATE" then
|
|
OnXPUpdate()
|
|
end
|
|
end)
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- 7. SLASH COMMANDS (/xpp and /xppercent)
|
|
--------------------------------------------------------------------------------
|
|
-- The game links SLASH_XPPERCENT1/2 to SlashCmdList.XPPERCENT by name.
|
|
-- `msg` is whatever was typed after the command, e.g. "size 30".
|
|
|
|
SLASH_XPPERCENT1 = "/xpp"
|
|
SLASH_XPPERCENT2 = "/xppercent"
|
|
|
|
SlashCmdList.XPPERCENT = function(msg)
|
|
local db = DB()
|
|
|
|
-- Lower-case and strip spaces at both ends, so " Size 30 " works too.
|
|
msg = (msg or ""):lower():match("^%s*(.-)%s*$")
|
|
|
|
if msg == "chat" then
|
|
-- Toggle our own % line in chat.
|
|
db.chat = not db.chat
|
|
print("XP Percent chat line:", db.chat and "on" or "off")
|
|
|
|
elseif msg == "popup" then
|
|
-- Toggle the floating popup.
|
|
db.popup = not db.popup
|
|
print("XP Percent popup:", db.popup and "on" or "off")
|
|
|
|
elseif msg == "blizz" then
|
|
-- Toggle hiding Blizzard's "You gain 200 experience." chat line.
|
|
db.hideChat = not db.hideChat
|
|
print("Blizzard XP chat message hidden:", db.hideChat and "yes" or "no")
|
|
|
|
elseif msg:match("^size %d+") then
|
|
-- "/xpp size 30": set the font size and show a preview. Kept within
|
|
-- 10-60, the same range as the slider in the options window.
|
|
db.size = math.max(10, math.min(60, tonumber(msg:match("%d+"))))
|
|
ApplyStyle()
|
|
Show(0.5, "XP")
|
|
|
|
elseif msg:match("^pos %-?%d+ %-?%d+") then
|
|
-- "/xpp pos 0 60": set an exact position (offset from screen center;
|
|
-- negative numbers allowed) and show a preview.
|
|
local x, y = msg:match("(%-?%d+) (%-?%d+)")
|
|
db.x, db.y = tonumber(x), tonumber(y)
|
|
ApplyStyle()
|
|
Show(0.5, "XP")
|
|
if ns.OnPositionChanged then ns.OnPositionChanged() end
|
|
|
|
elseif msg == "unlock" or msg == "move" then
|
|
SetUnlocked(true) -- start drag-to-move mode
|
|
|
|
elseif msg == "lock" then
|
|
SetUnlocked(false) -- end drag-to-move mode
|
|
|
|
elseif msg == "" or msg == "options" or msg == "config" then
|
|
-- Bare "/xpp" opens the options window (from Options.lua).
|
|
if ns.OpenOptions then ns.OpenOptions() end
|
|
|
|
elseif msg == "test" then
|
|
Show(0.5, "XP") -- sample popup
|
|
|
|
elseif tonumber(msg) then
|
|
-- "/xpp 1": number of decimal places. Rounded down and kept within 0-4,
|
|
-- because a fraction like 1.5 would build an invalid format string.
|
|
db.decimals = math.max(0, math.min(4, math.floor(tonumber(msg))))
|
|
print("XP Percent decimals:", db.decimals)
|
|
|
|
else
|
|
-- Anything else (including "/xpp help"): list the commands.
|
|
print("|cff9966ffXP Percent|r commands:")
|
|
print(" /xpp - open the options window")
|
|
print(" /xpp chat - toggle the % line in chat")
|
|
print(" /xpp popup - toggle the floating % on screen")
|
|
print(" /xpp blizz - toggle hiding Blizzard's flat XP chat message")
|
|
print(" /xpp 0-4 - number of decimal places")
|
|
print(" /xpp test - show a sample popup")
|
|
print(" /xpp size 26 - popup text size")
|
|
print(" /xpp unlock / lock - drag the popup to move it")
|
|
print(" /xpp pos 0 60 - popup position (x y from screen center)")
|
|
end
|
|
end
|