A World of Warcraft Experience Bar addon
worldofwarcraft
wow
addon
midnight
1local _, F = ...
2
3F.State = {
4 level = 0,
5 isMaxLevel = false,
6
7 -- XP Values
8 currentXP = 0,
9 maxXP = 0,
10 restedXP = 0,
11 questXP = 0,
12 completeXP = 0,
13 incompleteXP = 0,
14
15 -- Session Data
16 session = {
17 gainedXP = 0,
18 lastXP = 0,
19 startTime = 0,
20 realTotalTime = 0,
21 realLevelTime = 0,
22 lastTimePlayedRequest = 0
23 }
24}
25
26local function GetQuestRewardXP(index, questID)
27 local rewardXP = 0
28
29 if questID and C_QuestLog.GetQuestLogRewardXP then
30 rewardXP = C_QuestLog.GetQuestLogRewardXP(questID) or 0
31 end
32
33 if questID and C_QuestLog.SetSelectedQuest and C_QuestLog.GetSelectedQuest and GetQuestLogRewardXP then
34 local previous = C_QuestLog.GetSelectedQuest()
35 if previous ~= questID then
36 C_QuestLog.SetSelectedQuest(questID)
37 end
38
39 local selectedXP = GetQuestLogRewardXP() or 0
40
41 if previous and previous ~= questID then
42 C_QuestLog.SetSelectedQuest(previous)
43 end
44
45 if selectedXP > 0 then
46 rewardXP = selectedXP
47 end
48 elseif rewardXP == 0 and GetQuestLogRewardXP then
49 rewardXP = GetQuestLogRewardXP(index) or 0
50 end
51
52 return rewardXP
53end
54
55function F.State:UpdatePlayerXP()
56 self.level = UnitLevel("player")
57 self.currentXP = UnitXP("player")
58 self.maxXP = UnitXPMax("player")
59 self.restedXP = GetXPExhaustion() or 0
60
61 -- Max Level Logic
62 local expansionLevel = GetExpansionLevel()
63 local maxLevel = math.min(GetMaxPlayerLevel(), GetMaxLevelForExpansionLevel(expansionLevel))
64 self.isMaxLevel = self.level >= maxLevel
65end
66
67function F.State:UpdateQuestXP()
68 if F.DB and F.DB.questTrackingEnabled == false then
69 self.questXP = 0
70 self.completeXP = 0
71 self.incompleteXP = 0
72 return
73 end
74
75 local numEntries = C_QuestLog.GetNumQuestLogEntries()
76 local qXP, cXP, iXP = 0, 0, 0
77
78 for i = 1, numEntries do
79 local info = C_QuestLog.GetInfo(i)
80 -- this skips the XP header for a category / campaign as they should not be respected
81 if info and not info.isHeader and not info.isHidden and info.questID > 0 then
82 local isTracked = true
83 if F.DB and F.DB.trackedOnly and C_QuestLog.GetQuestWatchType then
84 local watchType = C_QuestLog.GetQuestWatchType(info.questID)
85 isTracked = (watchType == 1)
86 end
87
88 if isTracked then
89 -- Use the quest log index when querying the reward XP
90 local rewardXP = GetQuestRewardXP(i, info.questID)
91 if rewardXP > 0 then
92 qXP = qXP + rewardXP
93
94 local completeState = info.isComplete
95 if completeState == nil then
96 completeState = C_QuestLog.IsComplete(info.questID)
97 end
98
99 local isComplete = completeState == 1 or completeState == true
100 if not isComplete then
101 isComplete = C_QuestLog.ReadyForTurnIn(info.questID)
102 end
103
104 if isComplete then
105 cXP = cXP + rewardXP
106 else
107 iXP = iXP + rewardXP
108 end
109 end
110 end
111 end
112 end
113
114 self.questXP = qXP
115 self.completeXP = cXP
116 self.incompleteXP = iXP
117end
118
119function F.State:DebugDumpQuests()
120 local numEntries = C_QuestLog.GetNumQuestLogEntries()
121 print("NixxnuxXPBar: DebugDumpQuests - numEntries =", numEntries)
122
123 local qXP, cXP, iXP = 0, 0, 0
124
125 for i = 1, numEntries do
126 local info = C_QuestLog.GetInfo(i)
127 if info then
128 local reward = GetQuestRewardXP(i, info.questID)
129
130 local status = "UNKNOWN"
131 if info.isHeader then
132 status = "HEADER"
133 elseif info.isHidden then
134 status = "HIDDEN"
135 else
136 local completeState = info.isComplete
137 if completeState == nil and info.questID then
138 completeState = C_QuestLog.IsComplete(info.questID)
139 end
140
141 local isComplete = completeState == 1 or completeState == true
142 if not isComplete and info.questID then
143 isComplete = C_QuestLog.ReadyForTurnIn(info.questID)
144 end
145
146 status = isComplete and "COMPLETE" or "INCOMPLETE"
147 end
148
149 print(string.format(" [%d] id=%s title=\"%s\" reward=%d status=%s isHeader=%s isHidden=%s",
150 i,
151 tostring(info.questID),
152 tostring(info.title),
153 reward,
154 status,
155 tostring(info.isHeader),
156 tostring(info.isHidden)
157 ))
158
159 if reward > 0 then
160 qXP = qXP + reward
161 if status == "COMPLETE" then
162 cXP = cXP + reward
163 else
164 iXP = iXP + reward
165 end
166 end
167 end
168 end
169
170 print(string.format("Computed totals -> questXP=%d, completeXP=%d, incompleteXP=%d", qXP, cXP, iXP))
171 print(string.format("State totals -> questXP=%d, completeXP=%d, incompleteXP=%d", self.questXP or 0, self.completeXP or 0, self.incompleteXP or 0))
172end
173
174-- Convenience slash command to quickly invoke the debug dump
175SLASH_NIXXNUXXPBARDEBUG1 = SLASH_NIXXNUXXPBARDEBUG1 or "/nxpdebug"
176SlashCmdList = SlashCmdList or {}
177SlashCmdList["NIXXNUXXPBARDEBUG"] = function()
178 F.State:DebugDumpQuests()
179end
180
181function F.State:GetSessionStats()
182 local currentTime = GetTime()
183 local now = time()
184
185 local sessionTime = now - self.session.startTime
186 local hourlyXP, timeToLevel = 0, 0
187
188 local coeff = sessionTime / 3600
189 local remainingXP = self.maxXP - self.currentXP
190
191 if coeff > 0 and self.session.gainedXP > 0 then
192 hourlyXP = math.ceil(self.session.gainedXP / coeff)
193 if hourlyXP > 0 then
194 timeToLevel = math.ceil(remainingXP / hourlyXP * 3600)
195 end
196 end
197
198 return hourlyXP, timeToLevel, sessionTime
199end