Files
Adrestie ca2b78e217 Remove every debug command
/fui keeps edit mode, reset and list. The thirty diagnostic and tuning
functions behind the other subcommands (bar, bags, character, tabs, close,
model, minimap, mouse, map, questlog, chat, chatlines, tabard...) go with
them, with Panes.Report, the bags read-back and the 205 texts they alone used.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 13:39:35 +02:00

265 lines
9.3 KiB
Lua

-- Bottom status bars: experience and reputation.
-- mainline/StatusTrackingBarTemplate.xml: both bars are the same object (background, fill,
-- frame over it, centered text), so both are built the same way.
-- camelot/StatusTrackingBarConstants.lua: the containers are one bar height apart, so the
-- bars touch; camelot's image is 13 high. The game shows reputation above experience,
-- although the priorities (Experience 0, Reputation 2) sorted descending suggest the reverse.
-- Reputation fill color by standing (shared/ReputationBar.lua), same ranges as 3.3.5
-- FACTION_BAR_COLORS.
-- The experience bar hides at max level and reputation moves down to its place (camelot
-- StatusTrackingBarManager fills containers from the bottom). Reputation hides when no
-- faction is watched.
-- Both bars span the bottom row (action bar, micro menu, bags) and sit on its top, measured
-- by BottomBar (ForeverUI.BottomRow). Each stays movable. Both carry camelot's 19 dividers.
local HEIGHT = 13 -- camelot image height (1020 x 13)
-- Dividers (camelot StatusTrackingBarContainerMixin:UpdateDividers, unchanged in 70450):
-- STATUS_BAR_NUM_SEGMENTS = 20 segments, so 19 StatusBarDividerTemplate frames (3 x 10,
-- ui-hud-experiencebar-divider, OVERLAY) at LEFT (width / 20 * i, 0), above the fill.
-- Rested tick (ExhaustionTick, UI-HUD-ExperienceBar-Frame-Pip, 10 x 14): centered on the right
-- end of the rested fill, shown while rested experience remains. The rested fill is
-- Fill-Rested (dark blue); while rested, the earned fill is Fill-Prediction (bright blue) instead
-- of Fill-Experience (purple). camelot's ExpBarOverrides names them the other way round
-- (earned Fill-Rested, bonus Fill-Prediction); the game shows them as here (seen in game).
local SEGMENTS = 20
local DIVIDER_W, DIVIDER_H = 3, 10
local L = ForeverUI.L
local ATLAS_REPUTATION = {
"ui-hud-experiencebar-fill-reputation-faction-red-camelot", -- hated
"ui-hud-experiencebar-fill-reputation-faction-red-camelot", -- hostile
"ui-hud-experiencebar-fill-reputation-faction-orange-camelot", -- unfriendly
"ui-hud-experiencebar-fill-reputation-faction-yellow-camelot", -- neutral
"ui-hud-experiencebar-fill-reputation-faction-green-camelot", -- friendly
"ui-hud-experiencebar-fill-reputation-faction-green-camelot", -- honored
"ui-hud-experiencebar-fill-reputation-faction-green-camelot", -- revered
"ui-hud-experiencebar-fill-reputation-faction-green-camelot", -- exalted
}
-- Crops a fill to the fraction. The image has rounded ends: cutting it on the right gives
-- the straight edge of a partial fill. width: bar width at 100 %.
local function populate(texture, atlas, fraction, width)
local e = atlas and ForeverUI.AtlasEntry(atlas)
if not e or not fraction or fraction ~= fraction or fraction <= 0 then
texture:Hide()
return
end
if fraction > 1 then
fraction = 1
end
local w = width * fraction
if w < 1 then
texture:Hide()
return
end
texture:SetTexture(e[1])
texture:SetTexCoord(e[2], e[2] + (e[3] - e[2]) * fraction, e[4], e[5])
texture:SetWidth(w)
texture:Show()
end
local function createBar(name)
local bar = CreateFrame("Frame", name, UIParent)
bar:SetHeight(HEIGHT)
bar:EnableMouse(true)
local background = bar:CreateTexture(nil, "BACKGROUND")
ForeverUI.SetAtlas(background, "ui-hud-experiencebar-background-camelot", true)
background:SetAllPoints(bar)
-- Rested part shows behind the earned part: lower layer, same left edge.
local rested = bar:CreateTexture(nil, "BORDER")
rested:SetPoint("LEFT", bar, "LEFT", 0, 0)
rested:SetHeight(HEIGHT)
rested:Hide()
local fill = bar:CreateTexture(nil, "ARTWORK")
fill:SetPoint("LEFT", bar, "LEFT", 0, 0)
fill:SetHeight(HEIGHT)
fill:Hide()
local frame = bar:CreateTexture(nil, "OVERLAY")
ForeverUI.SetAtlas(frame, "ui-hud-experiencebar-frame-camelot", true)
frame:SetAllPoints(bar)
local text = bar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
text:SetPoint("CENTER")
text:Hide()
bar.background, bar.rested, bar.fill, bar.frame, bar.text =
background, rested, fill, frame, text
-- Dividers and rested tick, in a child frame above the fill and the frame art
local marks = CreateFrame("Frame", nil, bar)
marks:SetAllPoints(bar)
marks:SetFrameLevel(bar:GetFrameLevel() + 1)
bar.dividers = {}
for i = 1, SEGMENTS - 1 do
local divider = marks:CreateTexture(nil, "OVERLAY")
ForeverUI.SetAtlas(divider, "ui-hud-experiencebar-divider", true)
divider:SetWidth(DIVIDER_W)
divider:SetHeight(DIVIDER_H)
bar.dividers[i] = divider
end
local tick = marks:CreateTexture(nil, "OVERLAY")
ForeverUI.SetAtlas(tick, "ui-hud-experiencebar-frame-pip-camelot")
tick:Hide()
bar.marks, bar.tick = marks, tick
bar:SetScript("OnEnter", function(self)
self.text:Show()
end)
bar:SetScript("OnLeave", function(self)
self.text:Hide()
end)
return bar
end
-- Places the dividers on the bar's current width (camelot: on each layout change)
local function placeDividers(bar)
local width = bar:GetWidth() or 0
for i, divider in ipairs(bar.dividers) do
divider:ClearAllPoints()
divider:SetPoint("LEFT", bar, "LEFT", math.floor(width / SEGMENTS * i + 0.5), 0)
end
end
local experience = createBar("ForeverUIExperienceBar")
local reputation = createBar("ForeverUIReputationBar")
-- Reputation: just above experience, or in its place when experience is hidden (max level)
local function placeReputation()
local rowLine = ForeverUI.BottomRow
if not rowLine then
return
end
local center = (rowLine.left + rowLine.right) / 2
local y = experience:IsShown() and rowLine.top + HEIGHT or rowLine.top
ForeverUI.Layout.SetDefaults("reputationbar", "BOTTOM", "BOTTOM", center, y)
end
-- ---------- Experience
local function updateExperience()
local maximum = UnitXPMax("player")
local level = UnitLevel("player")
local maxLevel = MAX_PLAYER_LEVEL or 80
-- hidden too while a vehicle bar replaces the player's bars (Vehicle.lua)
if ForeverUI.VehicleArt or not maximum or maximum <= 0 or (level and level >= maxLevel) then
experience:Hide()
placeReputation()
return
end
experience:Show()
placeReputation()
local width = experience:GetWidth()
local earned = UnitXP("player")
local rested = (GetXPExhaustion and GetXPExhaustion()) or 0
local fraction = earned / maximum
populate(experience.rested, "ui-hud-experiencebar-fill-rested-camelot",
(earned + rested) / maximum, width)
-- rested tick at the end of the rested part
if rested > 0 then
local x = math.min(1, (earned + rested) / maximum) * width
experience.tick:ClearAllPoints()
experience.tick:SetPoint("CENTER", experience, "LEFT", x, 0)
experience.tick:Show()
else
experience.tick:Hide()
end
-- rested (GetRestState 1): the earned part turns bright blue over the darker rested bonus
local isRested = GetRestState and GetRestState() == 1
populate(experience.fill, isRested and "ui-hud-experiencebar-fill-prediction-camelot"
or "ui-hud-experiencebar-fill-experience-camelot", fraction, width)
experience.text:SetText(string.format("%d / %d (%d%%)", earned, maximum,
math.floor(fraction * 100)))
end
-- ---------- Reputation
local function updateReputation()
local name, standingId, minimum, maximum, value = GetWatchedFactionInfo()
if ForeverUI.VehicleArt or not name or not maximum or maximum <= minimum then
reputation:Hide()
return
end
reputation:Show()
local span = maximum - minimum
local earned = value - minimum
local fraction = earned / span
populate(reputation.fill, ATLAS_REPUTATION[standingId] or ATLAS_REPUTATION[4],
fraction, reputation:GetWidth())
reputation.text:SetText(string.format("%s %d / %d", name, earned, span))
end
-- ---------- Placement
-- Both bars span the row (action bar, micro menu, bags) and touch: experience on the row,
-- reputation just above (or on the row without experience).
local function place()
local rowLine = ForeverUI.BottomRow
if not rowLine then
return
end
local width = rowLine.right - rowLine.left
local center = (rowLine.left + rowLine.right) / 2
experience:SetWidth(width)
reputation:SetWidth(width)
placeDividers(experience)
placeDividers(reputation)
ForeverUI.Layout.SetDefaults("experiencebar", "BOTTOM", "BOTTOM", center, rowLine.top)
placeReputation()
end
local listener = CreateFrame("Frame")
listener:RegisterEvent("PLAYER_ENTERING_WORLD")
listener:RegisterEvent("PLAYER_XP_UPDATE")
listener:RegisterEvent("PLAYER_LEVEL_UP")
listener:RegisterEvent("UPDATE_EXHAUSTION")
listener:RegisterEvent("PLAYER_UPDATE_RESTING")
listener:RegisterEvent("UPDATE_FACTION")
listener:SetScript("OnEvent", function(_self, event)
if event == "PLAYER_ENTERING_WORLD" then
-- The client's bars: experience, rested tick, and reputation, which re-places itself on
-- every update.
ForeverUI.Suppress(MainMenuExpBar)
ForeverUI.Suppress(ExhaustionTick)
ForeverUI.Suppress(ReputationWatchBar)
place()
end
updateExperience()
updateReputation()
end)
ForeverUI.Layout.Register(experience, "experiencebar", L.STATUSBARS_EDIT_LABEL_EXPERIENCE, "BOTTOM", "BOTTOM", 0, 54)
ForeverUI.Layout.Register(reputation, "reputationbar", L.STATUSBARS_EDIT_LABEL_REPUTATION, "BOTTOM", "BOTTOM", 0, 67)
place()
updateExperience()
updateReputation()
ForeverUI.ReputationBar = reputation
ForeverUI.StatusBarsUpdate = function()
updateExperience()
updateReputation()
end
-- the row changed width (BottomBar.lua: a micro button was added)
ForeverUI.StatusBarsLayout = function()
place()
updateExperience()
updateReputation()
end