A World of Warcraft Experience Bar addon
worldofwarcraft wow addon midnight
at main 406 lines 14 kB view raw
1local AddonName, F = ... 2 3F.UI = {} 4 5local CFG = { 6 width = 600, 7 height = 24, 8 texture = "Interface\\Buttons\\WHITE8x8", 9 font = "Fonts\\FRIZQT__.TTF", 10 fontSize = 14, 11 barFontSize = 12, 12 13 -- Colors (R, G, B, A) 14 colorBack = {0.0, 0.0, 0.0, 0.8}, 15 colorBorder = {0, 0, 0, 1}, 16 17 colorMain = {0.76, 0.38, 1, 1}, -- Base Purple 18 colorRested = {0.34, 0.61, 0.99, .8}, -- Rested Blue 19 colorQuest = {1, 0.64, 0.0078, 0.25}, -- Quest Yellow 20 colorQuestComplete = {1, 0.64, 0.0078, 0.8}, -- Completed Quest 21} 22 23function F.UI.CreateStatusBar(parent, layer, subLevel, color) 24 local bar = CreateFrame("StatusBar", nil, parent) 25 bar:SetAllPoints() 26 bar:SetStatusBarTexture(CFG.texture) 27 bar:SetStatusBarColor(unpack(color)) 28 bar:GetStatusBarTexture():SetDrawLayer(layer, subLevel) 29 return bar 30end 31 32function F.UI.Create() 33 local f = CreateFrame("Frame", "NXP_Frame", UIParent) 34 f:SetSize(CFG.width, CFG.height) 35 f:SetPoint("TOP", UIParent, "TOP", 0, 100) -- Default Position 36 f:SetFrameStrata("LOW") 37 38 f:SetMovable(false) 39 f:EnableMouse(false) 40 41 F.Frame = f 42 43 -- 2. Background & Border 44 local bg = f:CreateTexture(nil, "BACKGROUND") 45 bg:SetAllPoints() 46 bg:SetTexture(CFG.texture) 47 bg:SetVertexColor(unpack(CFG.colorBack)) 48 49 -- Rested XP Bar 50 F.BarRested = F.UI.CreateStatusBar(f, "BACKGROUND", 2, CFG.colorRested) 51 52 -- Quest XP Bar 53 F.BarQuest = F.UI.CreateStatusBar(f, "BORDER", 1, CFG.colorQuest) 54 55 -- Completed Quest Bar 56 F.BarQuestComplete = F.UI.CreateStatusBar(f, "BORDER", 2, CFG.colorQuestComplete) 57 58 -- Main XP Bar 59 F.BarMain = F.UI.CreateStatusBar(f, "ARTWORK", 1, CFG.colorMain) 60 61 -- XP Ticks (20 segments) 62 local tickContainer = CreateFrame("Frame", nil, f) 63 tickContainer:SetAllPoints() 64 tickContainer.ticks = {} 65 for i = 1, 19 do 66 local tick = tickContainer:CreateTexture(nil, "OVERLAY") 67 tick:SetColorTexture(0, 0, 0, 0.35) 68 tick:SetWidth(1) 69 tickContainer.ticks[i] = tick 70 end 71 F.TickContainer = tickContainer 72 73 local overlay = CreateFrame("Frame", nil, f) 74 overlay:SetAllPoints() 75 overlay:SetFrameLevel(f:GetFrameLevel() + 10) 76 F.Overlay = overlay 77 78 -- level label 79 F.LevelText = overlay:CreateFontString(nil, "OVERLAY") 80 F.LevelText:SetFont(CFG.font, CFG.barFontSize, "OUTLINE") 81 F.LevelText:SetPoint("LEFT", overlay, "LEFT", 8, 0) 82 F.LevelText:SetJustifyH("LEFT") 83 F.LevelText:SetDrawLayer("OVERLAY", 2) 84 F.LevelText:SetTextColor(1, 1, 1, 1) 85 86 -- current / max XP 87 F.TextCenter = overlay:CreateFontString(nil, "OVERLAY") 88 F.TextCenter:SetFont(CFG.font, CFG.barFontSize, "OUTLINE") 89 F.TextCenter:SetPoint("CENTER", overlay, "CENTER", 0, 0) 90 F.TextCenter:SetJustifyH("CENTER") 91 F.TextCenter:SetDrawLayer("OVERLAY", 2) 92 F.TextCenter:SetTextColor(1, 1, 1, 1) 93 94 -- percent text 95 F.TextRight = overlay:CreateFontString(nil, "OVERLAY") 96 F.TextRight:SetFont(CFG.font, CFG.barFontSize, "OUTLINE") 97 F.TextRight:SetPoint("RIGHT", overlay, "RIGHT", -8, 0) 98 F.TextRight:SetJustifyH("RIGHT") 99 F.TextRight:SetDrawLayer("OVERLAY", 2) 100 F.TextRight:SetTextColor(1, 1, 1, 1) 101 102 -- text below the bar (completed quests/rested) 103 F.InfoText = overlay:CreateFontString(nil, "OVERLAY") 104 F.InfoText:SetFont(CFG.font, CFG.fontSize - 2, "OUTLINE") 105 F.InfoText:SetPoint("TOP", overlay, "BOTTOM", 0, -8) 106 F.InfoText:SetJustifyH("CENTER") 107 F.InfoText:SetDrawLayer("OVERLAY", 2) 108 F.InfoText:SetTextColor(1, 1, 1, 1) 109 110 -- quest/rested XP amounts 111 F.QuestXPText = overlay:CreateFontString(nil, "OVERLAY") 112 F.QuestXPText:SetFont(CFG.font, CFG.fontSize - 2, "OUTLINE") 113 F.QuestXPText:SetPoint("TOP", overlay, "BOTTOM", 0, -22) 114 F.QuestXPText:SetJustifyH("CENTER") 115 F.QuestXPText:SetDrawLayer("OVERLAY", 2) 116 F.QuestXPText:SetTextColor(1, 1, 1, 1) 117 118 -- Leveling info 119 F.LevelingText = overlay:CreateFontString(nil, "OVERLAY") 120 F.LevelingText:SetFont(CFG.font, CFG.fontSize - 2, "OUTLINE") 121 F.LevelingText:SetPoint("BOTTOMLEFT", overlay, "TOPLEFT", 0, 6) 122 F.LevelingText:SetJustifyH("LEFT") 123 F.LevelingText:SetDrawLayer("OVERLAY", 2) 124 F.LevelingText:SetTextColor(1, 1, 1, 1) 125 126 F.UI.Update() 127 128 F.UI.HideBlizzardBars() 129end 130 131function F.UI.HideBlizzardBars() 132 if not (F and F.DB and F.DB.hideBlizzardXPBar) then return end 133 134 if MainMenuExpBar then 135 MainMenuExpBar:UnregisterAllEvents() 136 MainMenuExpBar:Hide() 137 end 138 139 if ReputationWatchBar then 140 ReputationWatchBar:UnregisterAllEvents() 141 ReputationWatchBar:Hide() 142 end 143 144 if StatusTrackingBarManager then 145 StatusTrackingBarManager:UnregisterAllEvents() 146 StatusTrackingBarManager:Hide() 147 end 148 149 if MainMenuBarPerformanceBar then 150 MainMenuBarPerformanceBar:UnregisterAllEvents() 151 MainMenuBarPerformanceBar:Hide() 152 end 153end 154 155function F.UI.Update() 156 if not F.Frame then F.UI.Create() end 157 158 local s = F.State 159 local db = F.DB 160 161 if db and db.barWidth and db.barHeight then 162 local width = db.barWidth 163 if width then 164 local scale = F.Frame:GetEffectiveScale() or 1 165 local stepPixels = math.floor(((width / 20) * scale) + 0.5) 166 width = (stepPixels / scale) * 20 167 end 168 F.Frame:SetSize(width or db.barWidth, db.barHeight) 169 end 170 171 if db then 172 local anchor = db.anchorPoint or "TOP" 173 local x = tonumber(db.offsetX) or 0 174 local y = tonumber(db.offsetY) or 0 175 if anchor == "TOP" then 176 y = -y 177 end 178 F.Frame:ClearAllPoints() 179 F.Frame:SetPoint(anchor, UIParent, anchor, x, y) 180 end 181 182 if F.TickContainer then 183 if db and db.showTicks then 184 local width = F.Frame:GetWidth() 185 local height = F.Frame:GetHeight() 186 if width and width > 0 then 187 local step = width / 20 188 local scale = F.Frame:GetEffectiveScale() or 1 189 local opacity = 0.35 190 if db and type(db.tickOpacity) == "number" then 191 opacity = db.tickOpacity 192 end 193 for i = 1, 19 do 194 local tick = F.TickContainer.ticks[i] 195 if tick then 196 local x = step * i 197 x = math.floor((x * scale) + 0.5) / scale 198 tick:ClearAllPoints() 199 tick:SetColorTexture(0, 0, 0, opacity) 200 tick:SetPoint("TOPLEFT", F.Frame, "TOPLEFT", x, 0) 201 tick:SetPoint("BOTTOMLEFT", F.Frame, "BOTTOMLEFT", x, 0) 202 tick:Show() 203 end 204 end 205 F.TickContainer:Show() 206 else 207 F.TickContainer:Hide() 208 end 209 else 210 F.TickContainer:Hide() 211 end 212 end 213 214 local function resolveColor(color, fallback) 215 if type(color) == "table" then 216 if color.r then 217 return color.r or 1, color.g or 1, color.b or 1, color.a or 1 218 end 219 if color[1] then 220 return color[1] or 1, color[2] or 1, color[3] or 1, color[4] or 1 221 end 222 end 223 return fallback[1], fallback[2], fallback[3], fallback[4] 224 end 225 226 if db then 227 local fontPath = db.fontPath or CFG.font 228 F.LevelText:SetFont(fontPath, CFG.barFontSize, "OUTLINE") 229 F.TextCenter:SetFont(fontPath, CFG.barFontSize, "OUTLINE") 230 F.TextRight:SetFont(fontPath, CFG.barFontSize, "OUTLINE") 231 F.InfoText:SetFont(fontPath, CFG.fontSize - 2, "OUTLINE") 232 F.LevelingText:SetFont(fontPath, CFG.fontSize - 2, "OUTLINE") 233 if F.QuestXPText then 234 F.QuestXPText:SetFont(fontPath, CFG.fontSize - 2, "OUTLINE") 235 end 236 237 local mainTexture = db.barTextureMain or CFG.texture 238 local restedTexture = db.barTextureRested or CFG.texture 239 local questTexture = db.barTextureQuest or CFG.texture 240 local questCompleteTexture = db.barTextureQuestComplete or CFG.texture 241 F.BarMain:SetStatusBarTexture(mainTexture) 242 F.BarRested:SetStatusBarTexture(restedTexture) 243 F.BarQuest:SetStatusBarTexture(questTexture) 244 F.BarQuestComplete:SetStatusBarTexture(questCompleteTexture) 245 246 F.BarMain:SetStatusBarColor(resolveColor(db.colorMain, CFG.colorMain)) 247 F.BarRested:SetStatusBarColor(resolveColor(db.colorRested, CFG.colorRested)) 248 F.BarQuest:SetStatusBarColor(resolveColor(db.colorQuest, CFG.colorQuest)) 249 F.BarQuestComplete:SetStatusBarColor(resolveColor(db.colorQuestComplete, CFG.colorQuestComplete)) 250 end 251 252 if s.isMaxLevel and not db.showAtMaxLevel then 253 F.Frame:Hide() 254 return 255 else 256 F.Frame:Show() 257 end 258 259 if s.isMaxLevel then 260 F.BarMain:Hide() 261 F.BarQuest:Hide() 262 F.BarRested:Hide() 263 else 264 F.BarMain:Show() 265 end 266 267 local maxXP = (s.maxXP > 0) and s.maxXP or 1 268 269 F.BarMain:SetMinMaxValues(0, maxXP) 270 F.BarMain:SetValue(math.min(s.currentXP, maxXP)) 271 272 local projectedComplete = s.currentXP + (s.completeXP or 0) 273 local projectedQuest = projectedComplete + (db.showIncompleteQuestBar and (s.incompleteXP or 0) or 0) 274 275 if s.maxXP > 0 and projectedComplete > s.currentXP then 276 F.BarQuestComplete:Show() 277 F.BarQuestComplete:SetMinMaxValues(0, maxXP) 278 F.BarQuestComplete:SetValue(math.min(projectedComplete, s.maxXP)) 279 else 280 F.BarQuestComplete:Hide() 281 end 282 283 if s.maxXP > 0 and projectedQuest > projectedComplete and projectedComplete < s.maxXP then 284 F.BarQuest:Show() 285 F.BarQuest:SetMinMaxValues(0, maxXP) 286 F.BarQuest:SetValue(math.min(projectedQuest, s.maxXP)) 287 else 288 F.BarQuest:Hide() 289 end 290 291 local projectedRested = s.currentXP + (s.restedXP or 0) 292 if s.maxXP > 0 and (s.restedXP or 0) > 0 and s.currentXP < s.maxXP then 293 F.BarRested:Show() 294 F.BarRested:SetMinMaxValues(0, maxXP) 295 F.BarRested:SetValue(math.min(projectedRested, s.maxXP)) 296 else 297 F.BarRested:Hide() 298 end 299 300 local hourlyXP, timeToLevel, sessionTime = F.State:GetSessionStats() 301 local percentXP = (s.maxXP > 0) and (s.currentXP / s.maxXP * 100) or 0 302 local percentRested = (s.maxXP > 0) and (s.restedXP / s.maxXP * 100) or 0 303 304 if db.showLevelText then 305 F.LevelText:SetText("Level " .. s.level) 306 F.LevelText:Show() 307 else 308 F.LevelText:SetText("") 309 F.LevelText:Hide() 310 end 311 312 if db.showXPText then 313 if s.isMaxLevel then 314 F.TextCenter:SetText("Level " .. s.level .. " (Max)") 315 else 316 F.TextCenter:SetText(string.format("%s / %s", FormatLargeNumber(s.currentXP), FormatLargeNumber(s.maxXP))) 317 end 318 F.TextCenter:Show() 319 else 320 F.TextCenter:SetText("") 321 F.TextCenter:Hide() 322 end 323 324 local percentStr = "" 325 if not s.isMaxLevel and s.maxXP > 0 then 326 local completedXP = (s.completeXP or 0) 327 local percentCompleted = (s.maxXP > 0) and (completedXP / s.maxXP * 100) or 0 328 local percentWithComplete = percentXP + percentCompleted 329 330 if completedXP > 0 then 331 percentStr = string.format("%.1f%% (%.1f%%)", percentXP, math.min(100, percentWithComplete)) 332 elseif (s.restedXP or 0) > 0 and db.showQuestRestedText then 333 local percentWithRest = percentXP + percentRested 334 percentStr = string.format("%.1f%% (%.1f%%)", percentXP, math.min(100, percentWithRest)) 335 else 336 percentStr = string.format("%.1f%%", percentXP) 337 end 338 end 339 340 if db.showPercentText and percentStr ~= "" and s.maxXP > 0 then 341 F.TextRight:SetText(percentStr) 342 F.TextRight:Show() 343 else 344 F.TextRight:SetText("") 345 F.TextRight:Hide() 346 end 347 348 do 349 local infoParts = {} 350 351 if db.showQuestRestedText and s.maxXP > 0 then 352 if db.questTrackingEnabled ~= false and (s.completeXP or 0) > 0 then 353 table.insert(infoParts, string.format("Completed Quests: %.1f%%", ((s.completeXP or 0) / s.maxXP * 100))) 354 end 355 if (s.restedXP or 0) > 0 then 356 table.insert(infoParts, string.format("Rested Experience: %.1f%%", ((s.restedXP or 0) / s.maxXP * 100))) 357 end 358 end 359 360 local levelingStr = "" 361 if db.showXPHourText and not s.isMaxLevel and hourlyXP > 0 then 362 local xpRateText = hourlyXP > 10000 and (F.Utils.Round(hourlyXP / 1000, 1) .. "K") or FormatLargeNumber(hourlyXP) 363 local timerText = timeToLevel > 0 and F.Utils.FormatTime(timeToLevel) or "--" 364 levelingStr = string.format("Leveling in: %s (%s XP/Hr)", timerText, xpRateText) 365 end 366 367 if db.showQuestRestedText and #infoParts > 0 then 368 F.InfoText:SetText(table.concat(infoParts, " - ")) 369 F.InfoText:Show() 370 else 371 F.InfoText:SetText("") 372 F.InfoText:Hide() 373 end 374 375 if db.showLevelingText and levelingStr ~= "" then 376 F.LevelingText:SetText(levelingStr) 377 F.LevelingText:Show() 378 else 379 F.LevelingText:SetText("") 380 F.LevelingText:Hide() 381 end 382 end 383 384 do 385 local xpParts = {} 386 if db.questTrackingEnabled ~= false then 387 if db.showIncompleteQuestXPText and (s.incompleteXP or 0) > 0 then 388 table.insert(xpParts, string.format("Uncompleted Quest XP: %s", FormatLargeNumber(s.incompleteXP or 0))) 389 end 390 if db.showCompletedQuestXPText and (s.completeXP or 0) > 0 then 391 table.insert(xpParts, string.format("Completed Quest XP: %s", FormatLargeNumber(s.completeXP or 0))) 392 end 393 end 394 if db.showRestedXPText and (s.restedXP or 0) > 0 then 395 table.insert(xpParts, string.format("Rested XP: %s", FormatLargeNumber(s.restedXP or 0))) 396 end 397 398 if #xpParts > 0 then 399 F.QuestXPText:SetText(table.concat(xpParts, " - ")) 400 F.QuestXPText:Show() 401 else 402 F.QuestXPText:SetText("") 403 F.QuestXPText:Hide() 404 end 405 end 406end