vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --------------------------------------------------------------------------------------------------- |
2 | --Name: QuestieQuest |
||
3 | --Description: Handles all the quest related functions |
||
4 | --------------------------------------------------------------------------------------------------- |
||
5 | --///////////////////////////////////////////////////////////////////////////////////////////////-- |
||
6 | --------------------------------------------------------------------------------------------------- |
||
7 | --Local Vars |
||
8 | --------------------------------------------------------------------------------------------------- |
||
9 | local QuestieHashCache = {}; |
||
10 | local LastNrOfEntries = 0; |
||
11 | local CachedIds = {}; |
||
12 | local QuestieQuestHashCache = {}; |
||
13 | local QGet_TitleText = GetTitleText; |
||
14 | local QGet_QuestLogTitle = GetQuestLogTitle; |
||
15 | local QGet_NumQuestLeaderBoards = GetNumQuestLeaderBoards; |
||
16 | local QGet_QuestLogLeaderBoard = GetQuestLogLeaderBoard; |
||
17 | local QGet_QuestLogQuestText = GetQuestLogQuestText; |
||
18 | local QGet_NumQuestLogEntries = GetNumQuestLogEntries; |
||
19 | local QGet_QuestLogSelection = GetQuestLogSelection; |
||
20 | local QSelect_QuestLogEntry = SelectQuestLogEntry; |
||
21 | --------------------------------------------------------------------------------------------------- |
||
22 | --Global Vars |
||
23 | --------------------------------------------------------------------------------------------------- |
||
24 | LastQuestLogHashes = nil; |
||
25 | LastQuestLogCount = 0; |
||
26 | lastObjectives = nil; |
||
27 | QuestAbandonOnAccept = nil; |
||
28 | QuestAbandonWithItemsOnAccept = nil; |
||
29 | QuestRewardCompleteButton = nil; |
||
30 | QuestProgressCompleteButton = nil; |
||
31 | QuestDetailAcceptButton = nil; |
||
32 | Questie.lastCollapsedCount = 0; |
||
33 | Questie.collapsedThisRun = false; |
||
34 | QUESTIE_LAST_UPDATECACHE = GetTime(); |
||
35 | --------------------------------------------------------------------------------------------------- |
||
36 | --Blizzard Hook: Quest Abandon On Accept |
||
37 | --------------------------------------------------------------------------------------------------- |
||
38 | QuestAbandonOnAccept = StaticPopupDialogs["ABANDON_QUEST"].OnAccept; |
||
39 | StaticPopupDialogs["ABANDON_QUEST"].OnAccept = function() |
||
40 | local qName = GetAbandonQuestName(); |
||
41 | for hash,v in pairs(QuestieCachedQuests) do |
||
42 | if v["questName"] == qName then |
||
43 | QuestieSeenQuests[hash] = -1; |
||
44 | QuestieCachedQuests[hash] = nil; |
||
45 | QuestieHandledQuests[hash] = nil; |
||
46 | --Questie:debug_Print("Quest:QuestAbandonOnAccept: [questTitle: "..qName.."] | [Hash: "..hash.."]"); |
||
47 | RemoveCrazyArrow(hash); |
||
48 | end |
||
49 | end |
||
50 | QuestAbandonOnAccept(); |
||
51 | end |
||
52 | --------------------------------------------------------------------------------------------------- |
||
53 | --Blizzard Hook: Quest Abandon With Items On Accept |
||
54 | --------------------------------------------------------------------------------------------------- |
||
55 | QuestAbandonWithItemsOnAccept = StaticPopupDialogs["ABANDON_QUEST_WITH_ITEMS"].OnAccept; |
||
56 | StaticPopupDialogs["ABANDON_QUEST_WITH_ITEMS"].OnAccept = function() |
||
57 | local qName = GetAbandonQuestName(); |
||
58 | for hash,v in pairs(QuestieCachedQuests) do |
||
59 | if v["questName"] == qName then |
||
60 | QuestieSeenQuests[hash] = -1; |
||
61 | QuestieCachedQuests[hash] = nil; |
||
62 | QuestieHandledQuests[hash] = nil; |
||
63 | --Questie:debug_Print("Quest:QuestAbandonWithItemsOnAccept: [questTitle: "..qName.."] | [Hash: "..hash.."]"); |
||
64 | RemoveCrazyArrow(hash); |
||
65 | end |
||
66 | end |
||
67 | QuestAbandonWithItemsOnAccept(); |
||
68 | end |
||
69 | --------------------------------------------------------------------------------------------------- |
||
70 | --This function saves the number of slots that get freed when turning in a quest |
||
71 | --to the QuestieCachedQuests table, so it can be read in the next function. |
||
72 | --It is called upon the QUEST_PROGRESS event. |
||
73 | --------------------------------------------------------------------------------------------------- |
||
74 | function Questie:OnQuestProgress() |
||
75 | local questTitle = QGet_TitleText(); |
||
76 | local _, _, qlevel, qName = string.find(questTitle, "%[(.+)%] (.+)"); |
||
77 | if qName == nil then |
||
78 | qName = QGet_TitleText(); |
||
79 | end |
||
80 | for hash,v in pairs(QuestieCachedQuests) do |
||
81 | if v["questName"] == qName then |
||
82 | v["numQuestItems"] = GetNumQuestItems(); |
||
83 | end |
||
84 | end |
||
85 | end |
||
86 | --------------------------------------------------------------------------------------------------- |
||
87 | --This function is used by the next two hooks. |
||
88 | --It checks if the conditions for completing a quest are met: |
||
89 | -- 1. If there is a choice available, the player must have chosen. |
||
90 | -- 2. There must be (numRewards-numItems) free slots in the invetory. |
||
91 | --If both conditions are met, the quest is marked as finished, otherwise |
||
92 | --false is returned (return value is currently unused). |
||
93 | --------------------------------------------------------------------------------------------------- |
||
94 | function Questie:MarkQuestAsFinished() |
||
95 | local rewards = GetNumQuestRewards(); |
||
96 | local choices = GetNumQuestChoices(); |
||
97 | -- Filter condition: choices available but no choice made. |
||
98 | if ( QuestFrameRewardPanel.itemChoice == 0 and choices > 0 ) then |
||
99 | return false; |
||
100 | end |
||
101 | -- If there are rewards and choices, we need 1 more space. |
||
102 | if choices > 0 then |
||
103 | rewards = rewards + 1; |
||
104 | end |
||
105 | -- Get quest name and compare it against values in cache |
||
106 | local questTitle = QGet_TitleText(); |
||
107 | local _, _, qlevel, qName = string.find(questTitle, "%[(.+)%] (.+)"); |
||
108 | if qName == nil then |
||
109 | qName = QGet_TitleText(); |
||
110 | end |
||
111 | for hash,v in pairs(QuestieCachedQuests) do |
||
112 | if v["questName"] == qName then |
||
113 | if (not v["numQuestItems"]) then |
||
114 | Questie:debug_Print("ERROR: QuestRewardCompleteButton: [questTitle: "..qName.."] | [Hash: "..hash.."]:\n Failed to read numQuestItems from SavedVariables") |
||
115 | end |
||
116 | -- Filter condition: not enough space in inventory. |
||
117 | if (rewards > 0) and (Questie:CheckPlayerInventory() < (rewards - (v["numQuestItems"] or 0))) then |
||
118 | return false; |
||
119 | end |
||
120 | -- All checks passed, mark quest as finished and remove it from cache |
||
121 | QuestieSeenQuests[hash] = 1; |
||
122 | QuestieCompletedQuestMessages[qName] = 1; |
||
123 | QuestieCachedQuests[hash] = nil; |
||
124 | QuestieHandledQuests[hash] = nil; |
||
125 | Questie:debug_Print("Quest:QuestRewardCompleteButton: [questTitle: "..qName.."] | [Hash: "..hash.."]"); |
||
126 | RemoveCrazyArrow(hash); |
||
127 | return true; |
||
128 | end |
||
129 | end |
||
130 | end |
||
131 | --------------------------------------------------------------------------------------------------- |
||
132 | --Blizzard Hook: GetQuestReward function |
||
133 | --This hook marks a quest as finished in Questies DB if it can be finished. |
||
134 | --The call to the hooked function then finishes the quest. |
||
135 | --It is needed in addition to the next hook, because it is used by EQL3 |
||
136 | --when its "Auto Complete Quests"-option is enabled. |
||
137 | --------------------------------------------------------------------------------------------------- |
||
138 | QGetQuestReward = GetQuestReward; |
||
139 | GetQuestReward = function(choice) |
||
140 | Questie:MarkQuestAsFinished(); |
||
141 | QGetQuestReward(choice); |
||
142 | end |
||
143 | --------------------------------------------------------------------------------------------------- |
||
144 | --Blizzard Hook: Quest Reward Complete Button |
||
145 | --This hook marks a quest as finished in Questies DB if it can be finished. |
||
146 | --The call to the hooked function then finishes the quest. |
||
147 | --------------------------------------------------------------------------------------------------- |
||
148 | QuestRewardCompleteButton = QuestRewardCompleteButton_OnClick; |
||
149 | QuestRewardCompleteButton_OnClick = function() |
||
150 | Questie:MarkQuestAsFinished(); |
||
151 | QuestRewardCompleteButton(); |
||
152 | end |
||
153 | --------------------------------------------------------------------------------------------------- |
||
154 | --Blizzard Hook: Quest Progress Accept Button |
||
155 | --------------------------------------------------------------------------------------------------- |
||
156 | QuestDetailAcceptButton = QuestDetailAcceptButton_OnClick; |
||
157 | function QuestDetailAcceptButton_OnClick() |
||
158 | Questie:CheckQuestLogStatus(); |
||
159 | QuestDetailAcceptButton(); |
||
160 | end |
||
161 | --------------------------------------------------------------------------------------------------- |
||
162 | --Matches a looted item to quest items that are contained in the QuestieCachedQuests table |
||
163 | --------------------------------------------------------------------------------------------------- |
||
164 | function Questie:DetectQuestItem(itemName) |
||
165 | for k, v in pairs(QuestieCachedQuests) do |
||
166 | local num = v["leaderboards"] |
||
167 | for i=1,num do |
||
168 | desc = v["objective"..i]["desc"] |
||
169 | if (desc) then |
||
170 | local _, _, questItem, itemHave, itemNeed = string.find(desc, "(.+)%: (%d+)/(%d+)"); |
||
171 | if itemName == questItem and itemHave ~= itemNeed then |
||
172 | --Questie:debug_Print("Quest:DetectQuestItem: TRUE"); |
||
173 | --Questie:debug_Print("Quest:DetectQuestItem: [itemName: "..itemName.."] | [questItem: "..questItem.."] | [itemHave: "..itemHave.."] | [itemNeed: "..itemNeed.."]"); |
||
174 | return true |
||
175 | else |
||
176 | --Questie:debug_Print("Quest:DetectQuestItem: FALSE"); |
||
177 | return false |
||
178 | end |
||
179 | end |
||
180 | end |
||
181 | end |
||
182 | end |
||
183 | --------------------------------------------------------------------------------------------------- |
||
184 | --Parses loot messages then passes item to DetectQuestItem for verification |
||
185 | --------------------------------------------------------------------------------------------------- |
||
186 | function Questie:ParseQuestLoot(arg1) |
||
187 | local msg, item, loot |
||
188 | if string.find(arg1, "(You receive loot%:) (.+)") then |
||
189 | _, _, msg, item = string.find(arg1, "(You receive loot%:) (.+)"); |
||
190 | elseif string.find(arg1, "(Received item%:) (.+)") then |
||
191 | _, _, msg, item = string.find(arg1, "(Received item%:) (.+)"); |
||
192 | elseif string.find(arg1, "(You receive item%:) (.+)") then |
||
193 | _, _, msg, item = string.find(arg1, "(You receive item%:) (.+)"); |
||
194 | end |
||
195 | if item then |
||
196 | _, _, loot = string.find(item, "%[(.+)%].+"); |
||
197 | if Questie:DetectQuestItem(loot) then |
||
198 | --Questie:debug_Print("Quest:ParseQuestLoot --> [POST] Quest Loot: [ "..loot.." ] was found."); |
||
199 | Questie:CheckQuestLogStatus(); |
||
200 | else |
||
201 | --Questie:debug_Print("Quest:ParseQuestLoot --> [POST] Quest Loot: [ "..loot.." ] is not a quest item."); |
||
202 | end |
||
203 | end |
||
204 | end |
||
205 | --------------------------------------------------------------------------------------------------- |
||
206 | --Used to make sure the players inventory isn't full before auto-completing quest. |
||
207 | --------------------------------------------------------------------------------------------------- |
||
208 | function Questie:CheckPlayerInventory() |
||
209 | local totalSlots, usedSlosts, availableSlots; |
||
210 | local totalSlots = 0; |
||
211 | local usedSlots = 0; |
||
212 | for bag = 0, 4 do |
||
213 | local size = GetContainerNumSlots(bag); |
||
214 | if (size and size > 0) then |
||
215 | totalSlots = totalSlots + size; |
||
216 | for slot = 1, size do |
||
217 | if (GetContainerItemInfo(bag, slot)) then |
||
218 | usedSlots = usedSlots + 1; |
||
219 | end |
||
220 | end |
||
221 | end |
||
222 | end |
||
223 | availableSlots = totalSlots - usedSlots; |
||
224 | return availableSlots |
||
225 | end |
||
226 | --------------------------------------------------------------------------------------------------- |
||
227 | --Finishes a quest and performs a recrusive check to make sure all the required quests that come |
||
228 | --before it are also finsihed and recorded in the players QuestieSeenQuests. It will also clear |
||
229 | --any redundant quest tracking data and make sure a quest that is in a players log isn't |
||
230 | --accidently marked finished. When ever this function is run it will also remove invalid tracker |
||
231 | --data when it doesn't find a matching hash in the QuestieSeenQuests table. This sometimes |
||
232 | --happens when a player starts a quest chain. |
||
233 | --------------------------------------------------------------------------------------------------- |
||
234 | function Questie:finishAndRecurse(questhash) |
||
235 | local QSQ = QuestieSeenQuests; |
||
236 | local QCQ = QuestieCachedQuests; |
||
237 | local QHM = QuestieHashMap; |
||
238 | --If it finds a completed quest with left over cached data, then the cached |
||
239 | --data gets cleared. |
||
240 | if (QSQ[questhash] == 1) then |
||
241 | if (QCQ[questhash]) then |
||
242 | QCQ[questhash] = nil; |
||
243 | end |
||
244 | end |
||
245 | --This loop checks to make sure a quest is finished before marking it complete. It then |
||
246 | --recursively checks all required quests before it and marks those as complete as well. It |
||
247 | --also checks each one to make sure we aren't marking a seen quest finished. |
||
248 | if (QSQ[questhash] == 0) and (QCQ[questhash]) then |
||
249 | if ((QCQ[questhash]["leaderboards"] == 0 or QCQ[questhash]["leaderboards"] == 1) or (QCQ[questhash]["isComplete"] == 1)) then |
||
250 | QSQ[questhash] = 1; |
||
251 | QCQ[questhash] = nil; |
||
252 | RemoveCrazyArrow(questhash); |
||
253 | else |
||
254 | local req = nil; |
||
255 | if QHM[questhash] then |
||
256 | req = QHM[questhash]['rq']; |
||
257 | end |
||
258 | if req and QSQ[req] ~= 1 then |
||
259 | Questie:finishAndRecurse(req); |
||
260 | end |
||
261 | return; |
||
262 | end |
||
263 | --This loop allows a player to recursively finish a quest and all required quests that comes |
||
264 | --before it by shift+clicking an icon from one of the maps. It also checks each one to make |
||
265 | --sure we aren't marking a seen quest finished. |
||
266 | elseif ((QSQ[questhash] == nil) and (QCQ[questhash] == nil)) then |
||
267 | QSQ[questhash] = 1; |
||
268 | local req = nil; |
||
269 | if QHM[questhash] then |
||
270 | req = QHM[questhash]['rq']; |
||
271 | end |
||
272 | if req and QSQ[req] ~= 1 then |
||
273 | Questie:finishAndRecurse(req); |
||
274 | else |
||
275 | return; |
||
276 | end |
||
277 | end |
||
278 | --This trolls through all cached data to make sure it stays cleaned up. |
||
279 | local index = 0; |
||
280 | for i,v in pairs(QCQ) do |
||
281 | if QSQ[i] == 1 then |
||
282 | QCQ[i] = nil; |
||
283 | index = index + 1; |
||
284 | end |
||
285 | end |
||
286 | end |
||
287 | --------------------------------------------------------------------------------------------------- |
||
288 | --Checks the players quest log upon login or ReloadUI to make sure QuestieMapNotes and |
||
289 | --QuestieCachedQuests get pre-populated with cache data before normal CheckLog functions are run. |
||
290 | --This is especially important if this data isn't already in the WoW game clients local cache. |
||
291 | --------------------------------------------------------------------------------------------------- |
||
292 | function Questie:UpdateGameClientCache(force) |
||
293 | if (IsQuestieActive == false) then return; end |
||
294 | Questie:debug_Print(); |
||
295 | Questie:debug_Print("****************| Running Quest:UpdateGameClientCache |****************"); |
||
296 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
297 | local id = 1; |
||
298 | local qc = 0; |
||
299 | local nEntry, nQuests = QGet_NumQuestLogEntries(); |
||
300 | while qc < nQuests do |
||
301 | local questName, level, _, isHeader, isCollapsed, _ = QGet_QuestLogTitle(id); |
||
302 | if not isHeader and not isCollapsed then |
||
303 | QSelect_QuestLogEntry(id); |
||
304 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
305 | local hash = Questie:getQuestHash(questName, level, objectiveText); |
||
306 | if (force) then |
||
307 | Questie:AddQuestToMap(hash, true); |
||
308 | Questie:debug_Print("Quest:UpdateGameClientCache --> Questie:AddQuestToMap(forced): [Name: "..questName.."]"); |
||
309 | QuestieTracker:addQuestToTrackerCache(hash, id, level); |
||
310 | Questie:debug_Print("Quest:UpdateGameClientCache --> Questie:addQuestToTrackerCache(forced): [Hash: "..hash.."]"); |
||
311 | end |
||
312 | for index=1, QGet_NumQuestLeaderBoards(id) do |
||
313 | local desc = QGet_QuestLogLeaderBoard(index, id); |
||
314 | local objectiveName = desc; |
||
315 | local splitIndex = findLast(objectiveName, ":"); |
||
316 | if splitIndex ~= nil then |
||
317 | objectiveName = string.sub(objectiveName, 1, splitIndex-1); |
||
318 | if (string.find(objectiveName, " slain")) then |
||
319 | objectiveName = string.sub(objectiveName, 1, string.len(objectiveName)-6); |
||
320 | end |
||
321 | end |
||
322 | if (not LastQuestLogHashes and not force) or (QuestieHandledQuests[hash] and QuestieHandledQuests[hash]["objectives"] and QuestieHandledQuests[hash]["objectives"][index]["name"] ~= objectiveName) then |
||
323 | Questie:AddQuestToMap(hash); |
||
324 | Questie:debug_Print("Quest:UpdateGameClientCache --> Questie:AddQuestToMap(): [Name: "..QuestieHandledQuests[hash]["objectives"][index]["name"].."]"); |
||
325 | QuestieTracker:addQuestToTrackerCache(hash, id, level); |
||
326 | Questie:debug_Print("Quest:UpdateGameClientCache --> Questie:addQuestToTrackerCache(): [Hash: "..hash.."]"); |
||
327 | end |
||
328 | end |
||
329 | end |
||
330 | if not isHeader then |
||
331 | qc = qc + 1; |
||
332 | end |
||
333 | id = id + 1; |
||
334 | end |
||
335 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
336 | end |
||
337 | --------------------------------------------------------------------------------------------------- |
||
338 | --Checks the players quest log |
||
339 | --------------------------------------------------------------------------------------------------- |
||
340 | function Questie:CheckQuestLog() |
||
341 | --LastQuestLogHashes should always be nil upon Login or a ReloadUI - do these checks |
||
342 | if (not LastQuestLogHashes) then |
||
343 | Questie:debug_Print(); |
||
344 | Questie:debug_Print("****************| Running [PRE] Quest:CheckQuestLog |****************"); |
||
345 | --Clears abandoned quests |
||
346 | for k, v in pairs(QuestieSeenQuests) do |
||
347 | if (QuestieSeenQuests[k] == -1) then |
||
348 | Questie:RemoveQuestFromMap(k); |
||
349 | QuestieCachedQuests[k] = nil; |
||
350 | QuestieSeenQuests[k] = nil; |
||
351 | QUEST_WATCH_LIST[k] = nil; |
||
352 | Questie:debug_Print("Quest:CheckQuestLog: Found abandoned quest in QuestDB - Removed: [Hash: "..k.."]"); |
||
353 | end |
||
354 | end |
||
355 | --Clears cached data |
||
356 | for k, v in pairs(QuestieCachedQuests) do |
||
357 | if QuestieSeenQuests[k] == 1 then |
||
358 | Questie:RemoveQuestFromMap(k); |
||
359 | QuestieCachedQuests[k] = nil; |
||
360 | Questie:debug_Print("Quest:CheckQuestLog: Found cached data for a finished quest - Removed: [Hash: "..k.."]"); |
||
361 | end |
||
362 | end |
||
363 | LastQuestLogHashes, LastQuestLogCount = Questie:AstroGetAllCurrentQuestHashesAsMeta(); |
||
364 | for k, v in pairs(LastQuestLogHashes) do |
||
365 | --If a quest is found in the log and for some reason it's set as finished (1), or |
||
366 | --missing all together (nil), reset its status back to active (0). |
||
367 | if QuestieSeenQuests[k] == 1 or QuestieSeenQuests[k] == nil then |
||
368 | QuestieSeenQuests[k] = 0; |
||
369 | Questie:debug_Print("Quest:CheckQuestLog: --> Quest found in QuestLog marked complete - Fixed: [Hash: "..v["hash"].."]"); |
||
370 | end |
||
371 | --This "double-tap" ensures quest data is inserted into the cache |
||
372 | if (QuestieCachedQuests[v["hash"]] == nil) or (QuestieHandledQuests[v["hash"]] == nil) then |
||
373 | QuestieTracker:addQuestToTrackerCache(v["hash"], v["logId"], v["level"]); |
||
374 | Questie:AddQuestToMap(v["hash"]); |
||
375 | Questie:debug_Print("Quest:CheckQuestLog: --> Add quest to Tracker and MapNotes caches: [Hash: "..v["hash"].."]"); |
||
376 | end |
||
377 | end |
||
378 | --Removes active quests from QuestDB if it's not active in the QuestLog |
||
379 | for k, v in pairs(QuestieSeenQuests) do |
||
380 | if QuestieSeenQuests[k] == 0 and LastQuestLogHashes[k] == nil then |
||
381 | QuestieCachedQuests[k] = nil; |
||
382 | QuestieSeenQuests[k] = nil; |
||
383 | QUEST_WATCH_LIST[k] = nil; |
||
384 | Questie:debug_Print("Quest:CheckQuestLog: --> Quest found in QuestDB not in QuestLog - Removed: [Hash: "..k.."]"); |
||
385 | end |
||
386 | end |
||
387 | QUESTIE_LAST_UPDATE_FINISHED = GetTime(); |
||
388 | return; |
||
389 | end |
||
390 | local CheckLogTime = GetTime(); |
||
391 | local Quests, QuestsCount = Questie:AstroGetAllCurrentQuestHashesAsMeta(); |
||
392 | MapChanged = false; |
||
393 | delta = {}; |
||
394 | if (QuestsCount > LastQuestLogCount) then |
||
395 | for k, v in pairs(Quests) do |
||
396 | if (Quests[k] and LastQuestLogHashes[k]) then |
||
397 | else |
||
398 | if (Quests[k]) then |
||
399 | v["deltaType"] = 1; |
||
400 | table.insert(delta, v); |
||
401 | else |
||
402 | v["deltaType"] = 0; |
||
403 | table.insert(delta, v); |
||
404 | end |
||
405 | end |
||
406 | end |
||
407 | else |
||
408 | for k, v in pairs(LastQuestLogHashes) do |
||
409 | if (Quests[k] and LastQuestLogHashes[k]) then |
||
410 | else |
||
411 | if (Quests[k]) then |
||
412 | v["deltaType"] = 1; |
||
413 | table.insert(delta, v); |
||
414 | else |
||
415 | v["deltaType"] = 0; |
||
416 | table.insert(delta, v); |
||
417 | end |
||
418 | end |
||
419 | end |
||
420 | end |
||
421 | for k, v in pairs(delta) do |
||
422 | Questie:debug_Print(); |
||
423 | Questie:debug_Print("****************| Running [POST] Quest:CheckQuestLog |**************** "); |
||
424 | Questie:debug_Print("Quest:CheckQuestLog: UPON ENTER: [QuestsCount: "..QuestsCount.."] | [LastCount: "..LastQuestLogCount.."]"); |
||
425 | if (v["deltaType"] == 1) then |
||
426 | Questie:AddQuestToMap(v["hash"]); |
||
427 | --This adds a quest to the cache |
||
428 | if (QuestieSeenQuests[v["hash"]] == nil) then |
||
429 | QuestieSeenQuests[v["hash"]] = 0; |
||
430 | QuestieTracker:addQuestToTrackerCache(v["hash"], v["logId"], v["level"]); |
||
431 | Questie:debug_Print("Quest:CheckQuestLog: --> Add quest to Tracker and MapNotes caches: [Hash: "..v["hash"].."]"); |
||
432 | RemoveCrazyArrow(v["hash"]); |
||
433 | if (AUTO_QUEST_WATCH == "1") then |
||
434 | AddQuestWatch(v["logId"]); |
||
435 | end |
||
436 | end |
||
437 | MapChanged = true; |
||
438 | elseif not Questie.collapsedThisRun then |
||
439 | Questie:RemoveQuestFromMap(v["hash"]); |
||
440 | --This clears cache of finished quests |
||
441 | if (QuestieSeenQuests[v["hash"]] == 1) then |
||
442 | QuestieTracker:removeQuestFromTracker(v["hash"]); |
||
443 | QUEST_WATCH_LIST[v["hash"]] = nil; |
||
444 | Questie:finishAndRecurse(v["hash"]); |
||
445 | Questie:debug_Print("Quest:CheckQuestLog: --> Quest:finishAndRecurse() [Hash: "..v["hash"].."]"); |
||
446 | if (not QuestieCompletedQuestMessages[v["name"]]) then |
||
447 | QuestieCompletedQuestMessages[v["name"]] = 0; |
||
448 | end |
||
449 | --This clears cache of abandoned quests |
||
450 | elseif (QuestieSeenQuests[v["hash"]] == -1) then |
||
451 | QuestieTracker:removeQuestFromTracker(v["hash"]); |
||
452 | QuestieCachedQuests[v["hash"]] = nil; |
||
453 | QuestieSeenQuests[v["hash"]] = nil; |
||
454 | QUEST_WATCH_LIST[v["hash"]] = nil; |
||
455 | Questie:debug_Print("Quest:CheckQuestLog: clear abandoned quest: [Hash: "..v["hash"].."]"); |
||
456 | end |
||
457 | --Cleans cached data |
||
458 | for k, v in pairs(QuestieCachedQuests) do |
||
459 | if QuestieSeenQuests[k] == 1 then |
||
460 | QuestieCachedQuests[k] = nil; |
||
461 | Questie:debug_Print("Quest:CheckQuestLog: Cleaned Quest Cache: [Hash: "..k.."]"); |
||
462 | end |
||
463 | end |
||
464 | if lastObjectives and lastObjectives[v["hash"]] then |
||
465 | Questie:debug_Print("Quest:CheckQuestLog: lastObjectives update [Hash: "..v["hash"].."]"); |
||
466 | lastObjectives = {}; |
||
467 | end |
||
468 | MapChanged = true; |
||
469 | end |
||
470 | end |
||
471 | delta = nil; |
||
472 | LastQuestLogHashes = Quests; |
||
473 | LastQuestLogCount = QuestsCount; |
||
474 | if (MapChanged == true) then |
||
475 | Questie:debug_Print("Quest:CheckQuestLog: QuestLog Changed --> Questie:RefreshQuestStatus()"); |
||
476 | Questie:RefreshQuestStatus(); |
||
477 | QUESTIE_LAST_UPDATE_FINISHED = GetTime(); |
||
478 | Questie:debug_Print("Quest:CheckQuestLog: UPON EXIT: [QuestsCount: "..QuestsCount.."] | [LastCount: "..LastQuestLogCount.."]"); |
||
479 | return true; |
||
480 | else |
||
481 | Questie:debug_Print("Quest:CheckQuestLog: NO CHANGE --> Refresh Notes and Tracker"); |
||
482 | Questie:AddEvent("SYNCLOG", 0.2); |
||
483 | Questie:AddEvent("DRAWNOTES", 0.4); |
||
484 | Questie:AddEvent("TRACKER", 0.6); |
||
485 | QUESTIE_LAST_UPDATE_FINISHED = GetTime(); |
||
486 | return nil; |
||
487 | end |
||
488 | end |
||
489 | --------------------------------------------------------------------------------------------------- |
||
490 | --Adds or updates all active objectives in the questlog to the lastObjectives table |
||
491 | --------------------------------------------------------------------------------------------------- |
||
492 | function Questie:UpdateQuests(force) |
||
493 | if (not lastObjectives) then |
||
494 | lastObjectives = {}; |
||
495 | Questie:UpdateQuestsInit(); |
||
496 | return; |
||
497 | end |
||
498 | local UpdateQuestsTime = GetTime(); |
||
499 | local ZonesChecked = 0; |
||
500 | local CurrentZone = GetZoneText(); |
||
501 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
502 | local change = Questie:UpdateQuestInZone(CurrentZone); |
||
503 | local i = 1; |
||
504 | local qc = 0; |
||
505 | ZonesChecked = ZonesChecked + 1; |
||
506 | if (not change) then |
||
507 | change = Questie:UpdateQuestInZone(GetMinimapZoneText()); |
||
508 | ZonesChecked = ZonesChecked + 1; |
||
509 | end |
||
510 | if (not change or force) then |
||
511 | while qc < numQuests do |
||
512 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
513 | if (isHeader and q ~= CurrentZone) then |
||
514 | local c = Questie:UpdateQuestInZone(q, force); |
||
515 | ZonesChecked = ZonesChecked + 1; |
||
516 | change = c; |
||
517 | if (c and not force)then |
||
518 | break; |
||
519 | end |
||
520 | end |
||
521 | if not isHeader then |
||
522 | qc = qc + 1; |
||
523 | end |
||
524 | i = i + 1; |
||
525 | end |
||
526 | else |
||
527 | end |
||
528 | return change; |
||
529 | end |
||
530 | --------------------------------------------------------------------------------------------------- |
||
531 | --Updates all active objectives in a zone then updates the lastObjectives table |
||
532 | --------------------------------------------------------------------------------------------------- |
||
533 | function Questie:UpdateQuestInZone(Zone, force) |
||
534 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
535 | local foundChange = nil; |
||
536 | local ZoneFound = nil; |
||
537 | local QuestsChecked = 0; |
||
538 | local i = 1; |
||
539 | local qc = 0; |
||
540 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
541 | while qc < numQuests do |
||
542 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
543 | if (ZoneFound and isHeader) then |
||
544 | break; |
||
545 | end |
||
546 | if (isHeader and q == Zone) then |
||
547 | ZoneFound = true; |
||
548 | end |
||
549 | if not isHeader and ZoneFound then |
||
550 | QuestsChecked = QuestsChecked + 1; |
||
551 | QSelect_QuestLogEntry(i); |
||
552 | local count = QGet_NumQuestLeaderBoards(); |
||
553 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
554 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
555 | if QuestieHashCache[q] == nil then QuestieHashCache[q] = {}; end |
||
556 | QuestieHashCache[q][hash] = GetTime(); |
||
557 | if not lastObjectives[hash] then |
||
558 | lastObjectives[hash] = {}; |
||
559 | end |
||
560 | local Refresh = nil; |
||
561 | for obj = 1, count do |
||
562 | if (not lastObjectives[hash][obj]) then |
||
563 | lastObjectives[hash][obj] = {}; |
||
564 | end |
||
565 | local desc, typ, done = QGet_QuestLogLeaderBoard(obj); |
||
566 | if(lastObjectives[hash][obj].desc == desc and lastObjectives[hash][obj].typ == typ and lastObjectives[hash][obj].done == done) then |
||
567 | elseif(lastObjectives[hash][obj].done ~= done) then |
||
568 | Refresh = true; |
||
569 | foundChange = true; |
||
570 | else |
||
571 | foundChange = true; |
||
572 | end |
||
573 | lastObjectives[hash][obj].desc = desc; |
||
574 | lastObjectives[hash][obj].typ = typ; |
||
575 | lastObjectives[hash][obj].done = done; |
||
576 | end |
||
577 | if (Refresh) then |
||
578 | Questie:AddQuestToMap(hash, true); |
||
579 | end |
||
580 | if (foundChange and QuestieConfig.trackerEnabled == true) then |
||
581 | if (QuestieCachedQuests[hash]) then |
||
582 | QuestieTracker:updateTrackerCache(hash, i, level); |
||
583 | end |
||
584 | end |
||
585 | end |
||
586 | if (foundChange and not force) then |
||
587 | break; |
||
588 | end |
||
589 | if not isHeader then |
||
590 | qc = qc + 1; |
||
591 | end |
||
592 | i = i + 1; |
||
593 | end |
||
594 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
595 | return foundChange; |
||
596 | end |
||
597 | --------------------------------------------------------------------------------------------------- |
||
598 | --Adds all active objectives from all quests in the questlog to the lastObjectives table |
||
599 | --------------------------------------------------------------------------------------------------- |
||
600 | function Questie:UpdateQuestsInit() |
||
601 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
602 | local i = 1; |
||
603 | local qc = 0; |
||
604 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
605 | while qc < numQuests do |
||
606 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
607 | if not isHeader then |
||
608 | QSelect_QuestLogEntry(i); |
||
609 | local count = QGet_NumQuestLeaderBoards(); |
||
610 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
611 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
612 | if not lastObjectives[hash] then |
||
613 | lastObjectives[hash] = {}; |
||
614 | end |
||
615 | for obj = 1, count do |
||
616 | if (not lastObjectives[hash][obj]) then |
||
617 | lastObjectives[hash][obj] = {}; |
||
618 | end |
||
619 | lastObjectives[hash][obj].desc = desc; |
||
620 | lastObjectives[hash][obj].typ = typ; |
||
621 | lastObjectives[hash][obj].done = done; |
||
622 | end |
||
623 | qc = qc + 1; |
||
624 | end |
||
625 | i = i + 1; |
||
626 | end |
||
627 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
628 | end |
||
629 | --------------------------------------------------------------------------------------------------- |
||
630 | --Astrolabe functions |
||
631 | --------------------------------------------------------------------------------------------------- |
||
632 | function Questie:AstroGetAllCurrentQuestHashes(print) |
||
633 | local hashes = {}; |
||
634 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
635 | local i = 1; |
||
636 | local qc = 0; |
||
637 | if (print) then |
||
638 | --Questie:debug_Print("Quest:AstroGetAllCurrentQuestHashes: Listing all current quests"); |
||
639 | end |
||
640 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
641 | while qc < numQuests do |
||
642 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
643 | if not isHeader then |
||
644 | QSelect_QuestLogEntry(i); |
||
645 | local count = QGet_NumQuestLeaderBoards(); |
||
646 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
647 | local quest = {}; |
||
648 | quest["name"] = q; |
||
649 | quest["level"] = level; |
||
650 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
651 | quest["hash"] = hash; |
||
652 | if(IsAddOnLoaded("URLCopy") and print) then |
||
653 | Questie:debug_Print(" "..q,URLCopy_Link(quest["hash"])); |
||
654 | elseif(print) then |
||
655 | Questie:debug_Print(" "..q,quest["hash"]); |
||
656 | end |
||
657 | table.insert(hashes, quest); |
||
658 | qc = qc + 1; |
||
659 | else |
||
660 | if (print) then |
||
661 | Questie:debug_Print(" Zone:", q); |
||
662 | end |
||
663 | end |
||
664 | i = i + 1; |
||
665 | end |
||
666 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
667 | if (print) then |
||
668 | --Questie:debug_Print("Quest:AstroGetAllCurrentQuestHashes: End of all current quests"); |
||
669 | end |
||
670 | return hashes; |
||
671 | end |
||
672 | --------------------------------------------------------------------------------------------------- |
||
673 | function Questie:AstroGetAllCurrentQuestHashesAsMeta(print) |
||
674 | local agacqhamtime = GetTime(); |
||
675 | local hashes = {}; |
||
676 | local Count = 0; |
||
677 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
678 | local collapsedCount = 0; |
||
679 | local i = 1; |
||
680 | local qc = 0; |
||
681 | Questie.collapsedThisRun = false; |
||
682 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
683 | while qc < numQuests do |
||
684 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
685 | if isCollapsed then collapsedCount = collapsedCount + 1; end |
||
686 | if not isHeader then |
||
687 | QSelect_QuestLogEntry(i); |
||
688 | local count = QGet_NumQuestLeaderBoards(); |
||
689 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
690 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
691 | if hash >= 0 then |
||
692 | hashes[hash] = {}; |
||
693 | hashes[hash]["hash"] = hash; |
||
694 | hashes[hash]["name"] = q; |
||
695 | hashes[hash]["level"] = level; |
||
696 | hashes[hash]["logId"] = i; |
||
697 | if(IsAddOnLoaded("URLCopy") and print)then |
||
698 | Questie:debug_Print(" "..q,URLCopy_Link(quest["hash"])); |
||
699 | elseif(print) then |
||
700 | Questie:debug_Print(" "..q,quest["hash"]); |
||
701 | end |
||
702 | end |
||
703 | qc = qc + 1; |
||
704 | else |
||
705 | if (print) then |
||
706 | Questie:debug_Print(" Zone:", q); |
||
707 | end |
||
708 | end |
||
709 | i=i+1 |
||
710 | end |
||
711 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
712 | if (print) then |
||
713 | --Questie:debug_Print("Quest:AstroGetAllCurrentQuestHashesAsMeta: End of all current quests"); |
||
714 | end |
||
715 | if not (collapsedCount == Questie.lastCollapsedCount) then |
||
716 | Questie.lastCollapsedCount = collapsedCount; |
||
717 | Questie.collapsedThisRun = true; |
||
718 | end |
||
719 | --Questie:debug_Print("Quest:AstroGetAllCurrentQuestHashesAsMeta --> Getting all hashes took: ["..tostring((GetTime()- agacqhamtime)*1000).."ms]"); |
||
720 | return hashes, numQuests; |
||
721 | end |
||
722 | --------------------------------------------------------------------------------------------------- |
||
723 | function Questie:AstroGetFinishedQuests() |
||
724 | numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
725 | local FinishedQuests = {}; |
||
726 | local i = 1; |
||
727 | local qc = 0; |
||
728 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
729 | while qc < numQuests do |
||
730 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
731 | if not isHeader then |
||
732 | QSelect_QuestLogEntry(i); |
||
733 | local count = QGet_NumQuestLeaderBoards(); |
||
734 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
735 | Done = true; |
||
736 | for obj = 1, count do |
||
737 | local desc, typ, done = QGet_QuestLogLeaderBoard(obj); |
||
738 | if not done then |
||
739 | Done = nil; |
||
740 | end |
||
741 | end |
||
742 | if(Done) then |
||
743 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
744 | --Questie:debug_Print("AstroGetFinishedQuests: [Hash: "..hash.."] | [Quest: "..q.."] | [Level: "..level.."]"); |
||
745 | table.insert(FinishedQuests, hash); |
||
746 | end |
||
747 | qc = qc + 1; |
||
748 | end |
||
749 | i = i + 1; |
||
750 | end |
||
751 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
752 | return FinishedQuests; |
||
753 | end |
||
754 | --------------------------------------------------------------------------------------------------- |
||
755 | function Questie:GetQuestObjectivePaths(questHash) |
||
756 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
757 | local questLogID = Questie:GetQuestIdFromHash(questHash); |
||
758 | QSelect_QuestLogEntry(questLogID); |
||
759 | local count = QGet_NumQuestLeaderBoards(); |
||
760 | local objectivePaths = {}; |
||
761 | for i = 1, count do |
||
762 | local desc, type, done = QGet_QuestLogLeaderBoard(i); |
||
763 | local typeFunctions = { |
||
764 | ['item'] = GetItemLocations, |
||
765 | ['event'] = GetEventLocations, |
||
766 | ['monster'] = GetMonsterLocations, |
||
767 | ['object'] = GetObjectLocations, |
||
768 | ['reputation'] = GetReputationLocations |
||
769 | }; |
||
770 | local typeFunction = typeFunctions[type]; |
||
771 | if typeFunction ~= nil then |
||
772 | local objectiveName = desc; |
||
773 | local splitIndex = findLast(objectiveName, ":"); |
||
774 | if splitIndex ~= nil then |
||
775 | objectiveName = string.sub(objectiveName, 1, splitIndex-1); |
||
776 | if (string.find(objectiveName, " slain")) then |
||
777 | objectiveName = string.sub(objectiveName, 1, string.len(objectiveName)-6); |
||
778 | end |
||
779 | end |
||
780 | locations = typeFunction(objectiveName); |
||
781 | objectivePaths[i] = {}; |
||
782 | objectivePaths[i]['path'] = locations; |
||
783 | objectivePaths[i]['done'] = done; |
||
784 | objectivePaths[i]['type'] = type; |
||
785 | objectivePaths[i]['name'] = objectiveName; |
||
786 | objectivePaths[i]['desc'] = desc |
||
787 | end |
||
788 | end |
||
789 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
790 | return objectivePaths; |
||
791 | end |
||
792 | --------------------------------------------------------------------------------------------------- |
||
793 | --Perhaps we should consider removing this function from Questie |
||
794 | --------------------------------------------------------------------------------------------------- |
||
795 | function Questie:AstroGetQuestObjectives(questHash) |
||
796 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
797 | local QuestLogID = Questie:GetQuestIdFromHash(questHash); |
||
798 | local mapid = GetCurrentMapID(); |
||
799 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(QuestLogID); |
||
800 | QSelect_QuestLogEntry(QuestLogID); |
||
801 | local count = QGet_NumQuestLeaderBoards(); |
||
802 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
803 | local AllObjectives = {}; |
||
804 | AllObjectives["QuestName"] = q; |
||
805 | AllObjectives["objectives"] = {}; |
||
806 | for i = 1, count do |
||
807 | local desc, typ, done = QGet_QuestLogLeaderBoard(i); |
||
808 | local typeFunction = AstroobjectiveProcessors[typ]; |
||
809 | if typ == "item" or typ == "monster" or not (typeFunction == nil) then |
||
810 | local indx = findLast(desc, ":"); |
||
811 | local countless = indx == nil; |
||
812 | local countstr = ""; |
||
813 | local namestr = desc; |
||
814 | if not countless then |
||
815 | countstr = string.sub(desc, indx + 2); |
||
816 | namestr = string.sub(desc, 1, indx - 1); |
||
817 | end |
||
818 | local objectives = typeFunction(q, namestr, countstr, selected, mapid); |
||
819 | Objective = {}; |
||
820 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
821 | for k, v in pairs(objectives) do |
||
822 | if (AllObjectives["objectives"][v["name"]] == nil) then |
||
823 | AllObjectives["objectives"][v["name"]] = {}; |
||
824 | end |
||
825 | if (not QuestieCachedMonstersAndObjects[hash]) then |
||
826 | QuestieCachedMonstersAndObjects[hash] = {}; |
||
827 | end |
||
828 | if (not QuestieCachedMonstersAndObjects[hash][v["name"]]) then |
||
829 | QuestieCachedMonstersAndObjects[hash][v["name"]] = {}; |
||
830 | end |
||
831 | QuestieCachedMonstersAndObjects[hash][v["name"]].name = v["name"]; |
||
832 | for monster, info in pairs(v['locations']) do |
||
833 | local obj = {}; |
||
834 | obj["mapid"] = info[1]; |
||
835 | obj["x"] = info[2]; |
||
836 | obj["y"] = info[3]; |
||
837 | obj["lootname"] = v["lootname"]; |
||
838 | obj["type"] = v["type"]; |
||
839 | obj["done"] = done; |
||
840 | obj['objectiveid'] = i; |
||
841 | table.insert(AllObjectives["objectives"][v["name"]], obj); |
||
842 | end |
||
843 | end |
||
844 | else |
||
845 | end |
||
846 | end |
||
847 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
848 | return AllObjectives; |
||
849 | end |
||
850 | --------------------------------------------------------------------------------------------------- |
||
851 | AstroobjectiveProcessors = { |
||
852 | ['item'] = function(quest, name, amount, selected, mapid) |
||
853 | local list = {}; |
||
854 | local itemdata = QuestieItems[name]; |
||
855 | --Questie:debug_Print(name); |
||
856 | if itemdata == nil then |
||
857 | Questie:debug_Print("Quest:AstroobjectiveProcessors --> ERROR1 PROCESSING: [Quest: "..quest.."] | [Objective: "..name.."] | No [itemdata] found | ID:0"); |
||
858 | itemdata = QuestieItems[name]; |
||
859 | end |
||
860 | if itemdata then |
||
861 | for k,v in pairs(itemdata) do |
||
862 | if k == "locationCount" then |
||
863 | local monster = {}; |
||
864 | monster["name"] = name; |
||
865 | monster["locations"] = {}; |
||
866 | monster["type"] = "loot"; |
||
867 | for b=1,itemdata['locationCount'] do |
||
868 | local loc = itemdata['locations'][b]; |
||
869 | table.insert(monster["locations"], loc); |
||
870 | end |
||
871 | table.insert(list, monster); |
||
872 | elseif k == "drop" then |
||
873 | for e,r in pairs(v) do |
||
874 | local monster = {}; |
||
875 | monster["name"] = name; |
||
876 | monster["lootname"] = e; |
||
877 | monster["locations"] = {}; |
||
878 | monster["type"] = "loot"; |
||
879 | for k, pos in pairs(QuestieMonsters[e]['locations']) do |
||
880 | table.insert(monster["locations"], pos); |
||
881 | end |
||
882 | table.insert(list, monster); |
||
883 | end |
||
884 | elseif k == "contained" then |
||
885 | for objectName, someNumber in pairs(v) do |
||
886 | local monster = {}; |
||
887 | monster["name"] = name; |
||
888 | monster["lootname"] = objectName; |
||
889 | monster["locations"] = {}; |
||
890 | monster["type"] = "object"; |
||
891 | if QuestieObjects[objectName] then |
||
892 | --TODO: handle objects that appear when a mob is killed |
||
893 | for k, pos in pairs(QuestieObjects[objectName]['locations']) do |
||
894 | table.insert(monster["locations"], pos); |
||
895 | end |
||
896 | table.insert(list, monster); |
||
897 | end |
||
898 | end |
||
899 | elseif k =="locations" then |
||
900 | else |
||
901 | Questie:debug_Print("Quest:AstroobjectiveProcessors --> ERROR2: [Quest: "..quest.."] | [Objective: "..name.."] | ID:1"); |
||
902 | for s, r in pairs(itemdata) do |
||
903 | Questie:debug_Print(s,tostring(r)); |
||
904 | end |
||
905 | end |
||
906 | end |
||
907 | end |
||
908 | return list; |
||
909 | end, |
||
910 | ['event'] = function(quest, name, amount, selected, mapid) |
||
911 | local evtdata = QuestieEvents[name]; |
||
912 | local list = {}; |
||
913 | if evtdata == nil then |
||
914 | Questie:debug_Print("Quest:AstroobjectiveProcessors --> ERROR3 UNKNOWN EVENT: [Quest: "..quest.."] | [Objective: "..name.."] | ID:2"); |
||
915 | else |
||
916 | for b=1,evtdata['locationCount'] do |
||
917 | local monster = {}; |
||
918 | monster["name"] = name; |
||
919 | monster["locations"] = {}; |
||
920 | monster["type"] = "event"; |
||
921 | for b=1,evtdata['locationCount'] do |
||
922 | local loc = evtdata['locations'][b]; |
||
923 | table.insert(monster["locations"], loc); |
||
924 | end |
||
925 | table.insert(list, monster); |
||
926 | end |
||
927 | end |
||
928 | return list; |
||
929 | end, |
||
930 | ['monster'] = function(quest, name, amount, selected, mapid) |
||
931 | local list = {}; |
||
932 | local monster = {}; |
||
933 | if (string.find(name, " slain")) then |
||
934 | name = string.sub(name, 1, string.len(name)-6); |
||
935 | end |
||
936 | monster["name"] = name; |
||
937 | monster["type"] = "slay"; |
||
938 | monster["locations"] = {}; |
||
939 | if (QuestieMonsters[name] and QuestieMonsters[name]['locations']) then |
||
940 | for k, pos in pairs(QuestieMonsters[name]['locations']) do |
||
941 | table.insert(monster["locations"], pos); |
||
942 | end |
||
943 | end |
||
944 | table.insert(list, monster); |
||
945 | return list; |
||
946 | end, |
||
947 | ['object'] = function(quest, name, amount, selected, mapid) |
||
948 | local list = {}; |
||
949 | local objdata = QuestieObjects[name]; |
||
950 | if objdata == nil then |
||
951 | Questie:debug_Print("Quest:AstroobjectiveProcessors: ERROR4 UNKNOWN OBJECT: [Quest: "..quest.."] | [Objective: "..name.."]"); |
||
952 | else |
||
953 | for b=1,objdata['locationCount'] do |
||
954 | local monster = {}; |
||
955 | monster["name"] = name; |
||
956 | monster["locations"] = {}; |
||
957 | monster["type"] = "object"; |
||
958 | for b=1,objdata['locationCount'] do |
||
959 | local loc = objdata['locations'][b]; |
||
960 | table.insert(monster["locations"], loc); |
||
961 | end |
||
962 | table.insert(list, monster); |
||
963 | end |
||
964 | end |
||
965 | return list; |
||
966 | end |
||
967 | } |
||
968 | --------------------------------------------------------------------------------------------------- |
||
969 | --End of Astrolabe functions |
||
970 | --------------------------------------------------------------------------------------------------- |
||
971 | --///////////////////////////////////////////////////////////////////////////////////////////////-- |
||
972 | --------------------------------------------------------------------------------------------------- |
||
973 | --Get quest ID from quest hash |
||
974 | --------------------------------------------------------------------------------------------------- |
||
975 | function Questie:GetQuestIdFromHash(questHash) |
||
976 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
977 | if (QUESTIE_UPDATE_EVENT or numEntries ~= LastNrOfEntries or not CachedIds[questHash]) then |
||
978 | CachedIds[questHash] = {}; |
||
979 | QUESTIE_UPDATE_EVENT = 0; |
||
980 | LastNrOfEntries = numEntries; |
||
981 | Questie:UpdateQuestIds(); |
||
982 | if CachedIds[questHash] then |
||
983 | return CachedIds[questHash]; |
||
984 | end |
||
985 | else |
||
986 | local prevQuestLogSelection = QGet_QuestLogSelection(); |
||
987 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(CachedIds[questHash]); |
||
988 | QSelect_QuestLogEntry(CachedIds[questHash]); |
||
989 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
990 | if (q and level and objectiveText) then |
||
991 | if(Questie:getQuestHash(q, level, objectiveText) == questHash) then |
||
992 | QSelect_QuestLogEntry(prevQuestLogSelection) |
||
993 | return CachedIds[questHash]; |
||
994 | else |
||
995 | Questie:debug_Print("Quest:GetQuestIdFromHash --> Error: [Hash: "..tostring(CachedIds[questHash]).."]1"); |
||
996 | end |
||
997 | else |
||
998 | Questie:debug_Print("Quest:GetQuestIdFromHash --> Error2: [Hash: "..tostring(CachedIds[questHash]).."] | [Quest: "..tostring(q).."] | [Level: "..tostring(level).."]"); |
||
999 | end |
||
1000 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
1001 | end |
||
1002 | end |
||
1003 | --------------------------------------------------------------------------------------------------- |
||
1004 | --Update quest ID's |
||
1005 | --------------------------------------------------------------------------------------------------- |
||
1006 | function Questie:UpdateQuestIds() |
||
1007 | local uqidtime = GetTime() |
||
1008 | local numEntries, numQuests = QGet_NumQuestLogEntries(); |
||
1009 | local i = 1; |
||
1010 | local qc = 0; |
||
1011 | local prevQuestLogSelection = QGet_QuestLogSelection() |
||
1012 | while qc < numQuests do |
||
1013 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(i); |
||
1014 | if not isHeader then |
||
1015 | QSelect_QuestLogEntry(i); |
||
1016 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
1017 | local hash = Questie:getQuestHash(q, level, objectiveText); |
||
1018 | if (not q or not level or not objective) then |
||
1019 | --commented out the error because it was really annoying. -ZoeyZolotova |
||
1020 | --Questie:debug_Print("Quest:UpdateQuestIds --> Error1: [Name: "..tostring(name).."] | [Level: "..tostring(level).."] | [Id: "..tostring(i).."] | [Hash: "..tostring(hash).."]") |
||
1021 | end |
||
1022 | CachedIds[hash] = i; |
||
1023 | qc = qc + 1; |
||
1024 | end |
||
1025 | i = i + 1; |
||
1026 | end |
||
1027 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
1028 | --Questie:debug_Print("Quest:UpdateQuestID: --> Updating QuestIds took: ["..tostring((GetTime()- uqidtime)*1000).."ms]") |
||
1029 | end |
||
1030 | --------------------------------------------------------------------------------------------------- |
||
1031 | --Some outdated server databases still use names like "Tower of Althalaxx part x". |
||
1032 | --which were used to turn quest names into a unique key. This function removes |
||
1033 | --those suffixes, so that they don't harm the quest lookup. |
||
1034 | --------------------------------------------------------------------------------------------------- |
||
1035 | function Questie:SanitisedQuestLookup(name) |
||
1036 | local realName, matched = string.gsub(name, " [(]?[Pp]art %d+[)]?", ""); |
||
1037 | return QuestieLevLookup[realName] or false; |
||
1038 | end |
||
1039 | --------------------------------------------------------------------------------------------------- |
||
1040 | --Remove unique suffix from text. |
||
1041 | --------------------------------------------------------------------------------------------------- |
||
1042 | function Questie:RemoveUniqueSuffix(text) |
||
1043 | if string.sub(text, -1) == "]" then |
||
1044 | local strlen = string.len(text) |
||
1045 | text = string.sub(text, 1, strlen-4) |
||
1046 | end |
||
1047 | return text |
||
1048 | end |
||
1049 | --------------------------------------------------------------------------------------------------- |
||
1050 | --Lookup quest hash from name, level or objective text |
||
1051 | --------------------------------------------------------------------------------------------------- |
||
1052 | function Questie:getQuestHash(name, level, objectiveText) |
||
1053 | local hashLevel = level or "hashLevel"; |
||
1054 | local hashText = objectiveText or "hashText"; |
||
1055 | if QuestieQuestHashCache[name..hashLevel..hashText] then |
||
1056 | return QuestieQuestHashCache[name..hashLevel..hashText]; |
||
1057 | end |
||
1058 | local questLookup = Questie:SanitisedQuestLookup(name); |
||
1059 | local hasOthers = false; |
||
1060 | if questLookup then |
||
1061 | local count = 0; |
||
1062 | local retval = 0; |
||
1063 | local bestDistance = 4294967295; --some high number (0xFFFFFFFF) |
||
1064 | local race = UnitRace("Player"); |
||
1065 | for k,v in pairs(questLookup) do |
||
1066 | if QuestieHashMap[v[2]] ~= nil then |
||
1067 | local rr = v[1]; |
||
1068 | local adjustedDescription = Questie:RemoveUniqueSuffix(k) |
||
1069 | if count == 1 then |
||
1070 | hasOthers = true; |
||
1071 | end |
||
1072 | local requiredQuest = QuestieHashMap[v[2]]['rq'] |
||
1073 | if adjustedDescription == objectiveText and tonumber(QuestieHashMap[v[2]]['questLevel']) == hashLevel and checkRequirements(null, race, null, rr) and (not requiredQuest or QuestieSeenQuests[requiredQuest]) and not QuestieSeenQuests[v[2]] then |
||
1074 | QuestieQuestHashCache[name..hashLevel..hashText] = v[2]; |
||
1075 | return v[2],hasOthers; --exact match |
||
1076 | end |
||
1077 | local dist = 4294967294; |
||
1078 | if not (objectiveText == nil) then |
||
1079 | dist = Questie:Levenshtein(objectiveText, adjustedDescription); |
||
1080 | end |
||
1081 | if dist < bestDistance then |
||
1082 | bestDistance = dist; |
||
1083 | retval = v[2]; |
||
1084 | end |
||
1085 | count = count + 1; |
||
1086 | else |
||
1087 | Questie:debug_Print("ERROR: Quest '"..name.."' was found but data is missing for hash "..v[2].." Please report this on Github!") |
||
1088 | end |
||
1089 | end |
||
1090 | if not (retval == 0) then |
||
1091 | QuestieQuestHashCache[name..hashLevel..hashText] = retval; |
||
1092 | return retval, hasOthers; --nearest match |
||
1093 | end |
||
1094 | end |
||
1095 | if name == nil then |
||
1096 | return -1; |
||
1097 | end |
||
1098 | local hash = Questie:MixString(0, name); |
||
1099 | if not (level == nil) then |
||
1100 | hash = Questie:MixInt(hash, level); |
||
1101 | QuestieQuestHashCache[name..hashLevel..hashText] = hash; |
||
1102 | end |
||
1103 | if not (objectiveText == nil) then |
||
1104 | hash = Questie:MixString(hash, objectiveText); |
||
1105 | QuestieQuestHashCache[name..hashLevel..hashText] = hash; |
||
1106 | end |
||
1107 | QuestieQuestHashCache[name..hashLevel..hashText] = hash; |
||
1108 | return hash, false; |
||
1109 | end |
||
1110 | --------------------------------------------------------------------------------------------------- |
||
1111 | --Checks to see if a quest is finished by quest hash |
||
1112 | --------------------------------------------------------------------------------------------------- |
||
1113 | function Questie:IsQuestFinished(questHash) |
||
1114 | local id = Questie:GetQuestIdFromHash(questHash); |
||
1115 | if (not id) then |
||
1116 | return false; |
||
1117 | end |
||
1118 | local prevQuestLogSelection = QGet_QuestLogSelection() |
||
1119 | local FinishedQuests = {}; |
||
1120 | local q, level, questTag, isHeader, isCollapsed, isComplete = QGet_QuestLogTitle(id); |
||
1121 | QSelect_QuestLogEntry(id); |
||
1122 | local count = QGet_NumQuestLeaderBoards(); |
||
1123 | local questText, objectiveText = QGet_QuestLogQuestText(); |
||
1124 | local Done = true; |
||
1125 | for obj = 1, count do |
||
1126 | local desc, typ, done = QGet_QuestLogLeaderBoard(obj); |
||
1127 | if not done then |
||
1128 | Done = nil; |
||
1129 | end |
||
1130 | end |
||
1131 | QSelect_QuestLogEntry(prevQuestLogSelection); |
||
1132 | if (Done and Questie:getQuestHash(q, level, objectiveText) == questHash) then |
||
1133 | local ret = {}; |
||
1134 | ret["questHash"] = questHash; |
||
1135 | ret["name"] = q; |
||
1136 | ret["level"] = level; |
||
1137 | return ret; |
||
1138 | end |
||
1139 | return nil; |
||
1140 | end |
||
1141 | --------------------------------------------------------------------------------------------------- |
||
1142 | --Race, Class and Profession filter functions |
||
1143 | --------------------------------------------------------------------------------------------------- |
||
1144 | RaceBitIndexTable = { |
||
1145 | ['human'] = 1, |
||
1146 | ['orc'] = 2, |
||
1147 | ['dwarf'] = 3, |
||
1148 | ['nightelf'] = 4, |
||
1149 | ['night elf'] = 4, |
||
1150 | ['scourge'] = 5, |
||
1151 | ['undead'] = 5, |
||
1152 | ['tauren'] = 6, |
||
1153 | ['gnome'] = 7, |
||
1154 | ['troll'] = 8, |
||
1155 | ['goblin'] = 9 |
||
1156 | }; |
||
1157 | ClassBitIndexTable = { |
||
1158 | ['warrior'] = 1, |
||
1159 | ['paladin'] = 2, |
||
1160 | ['hunter'] = 3, |
||
1161 | ['rogue'] = 4, |
||
1162 | ['priest'] = 5, |
||
1163 | ['shaman'] = 7, |
||
1164 | ['mage'] = 8, |
||
1165 | ['warlock'] = 9, |
||
1166 | ['druid'] = 11 |
||
1167 | }; |
||
1168 | --------------------------------------------------------------------------------------------------- |
||
1169 | function unpackBinary(val) |
||
1170 | ret = {}; |
||
1171 | for q=0,16 do |
||
1172 | if bit.band(bit.rshift(val,q), 1) == 1 then |
||
1173 | table.insert(ret, true); |
||
1174 | else |
||
1175 | table.insert(ret, false); |
||
1176 | end |
||
1177 | end |
||
1178 | return ret; |
||
1179 | end |
||
1180 | --------------------------------------------------------------------------------------------------- |
||
1181 | function checkRequirements(class, race, dbClass, dbRace) |
||
1182 | local valid = true; |
||
1183 | if race and dbRace and not (dbRace == 0) then |
||
1184 | local racemap = unpackBinary(dbRace); |
||
1185 | valid = racemap[RaceBitIndexTable[strlower(race)]]; |
||
1186 | end |
||
1187 | if class and dbClass and valid and not (dbRace == 0)then |
||
1188 | local classmap = unpackBinary(dbClass); |
||
1189 | valid = classmap[ClassBitIndexTable[strlower(class)]]; |
||
1190 | end |
||
1191 | return valid; |
||
1192 | end |
||
1193 | --------------------------------------------------------------------------------------------------- |
||
1194 | function Questie:GetAvailableQuestHashes(mapFileName, levelFrom, levelTo) |
||
1195 | local mapid = -1; |
||
1196 | if(QuestieZones[mapFileName]) then |
||
1197 | c = QuestieZones[mapFileName][4]; |
||
1198 | z = QuestieZones[mapFileName][5]; |
||
1199 | end |
||
1200 | local class = UnitClass("Player"); |
||
1201 | local race = UnitRace("Player"); |
||
1202 | local hashes = {}; |
||
1203 | for l = 0,100 do |
||
1204 | if QuestieZoneLevelMap[c] and QuestieZoneLevelMap[c][z] then |
||
1205 | local content = QuestieZoneLevelMap[c][z][l]; |
||
1206 | if content then |
||
1207 | for v, locationMeta in pairs(content) do |
||
1208 | local qdata = QuestieHashMap[v]; |
||
1209 | if (qdata) then |
||
1210 | local stop = false; |
||
1211 | local questLevel = qdata.questLevel; |
||
1212 | for x in string.gfind(questLevel, "%d+") do questLevel = x; end |
||
1213 | questLevel = tonumber(questLevel); |
||
1214 | if QuestieConfig.minLevelFilter and questLevel < levelFrom then |
||
1215 | stop = true; |
||
1216 | end |
||
1217 | if QuestieConfig.maxLevelFilter and qdata.level > levelTo then |
||
1218 | stop = true; |
||
1219 | end |
||
1220 | if (not stop) then |
||
1221 | local requiredQuest = qdata['rq']; |
||
1222 | local requiredRaces = qdata['rr']; |
||
1223 | local requiredClasses = qdata['rc']; |
||
1224 | local requiredSkill = qdata['rs']; |
||
1225 | local valid = not QuestieSeenQuests[requiredQuest]; |
||
1226 | if(requiredQuest) then valid = QuestieSeenQuests[requiredQuest]; end |
||
1227 | valid = valid and (requiredSkill == nil or QuestieConfig.showProfessionQuests); |
||
1228 | if valid then valid = valid and checkRequirements(class, race, requiredClasses,requiredRaces); end |
||
1229 | if valid and not QuestieHandledQuests[requiredQuest] and not QuestieSeenQuests[v] then |
||
1230 | hashes[v] = locationMeta; |
||
1231 | end |
||
1232 | end |
||
1233 | end |
||
1234 | end |
||
1235 | end |
||
1236 | end |
||
1237 | end |
||
1238 | return hashes; |
||
1239 | end |
||
1240 | --------------------------------------------------------------------------------------------------- |
||
1241 | --End of filter functions |
||
1242 | --------------------------------------------------------------------------------------------------- |