comparison ObjectiveTracker/QuestData.lua @ 43:9480bd904f4c

- file name organizing
author Nenue
date Mon, 25 Apr 2016 13:51:58 -0400
parents ObjectiveTracker/Quests.lua@03ed70f846de
children 756e8aeb040b
comparison
equal deleted inserted replaced
42:c73051785f19 43:9480bd904f4c
1 local B = select(2,...).frame
2 local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
3 local _G, ipairs, max, min, unpack, floor, pairs, tostring, type, band = _G, ipairs, max, min, unpack, floor, pairs, tostring, type, bit.band
4 local GetQuestWatchInfo, GetQuestLogCompletionText = GetQuestWatchInfo, GetQuestLogCompletionText
5 local GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle = GetQuestLogLeaderBoard, GetNumQuestLogEntries, GetQuestLogTitle
6 local GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, GetQuestLogSpecialItemCooldown
7 local GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches = GetSuperTrackedQuestID, GetMoney, C_Scenario, GetCVarBool, GetNumQuestWatches
8 local GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup = GetQuestTagInfo, GetMoneyString, GetDistanceSqToQuest, GetQuestFactionGroup
9 local QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY = QUEST_TAG_ACCOUNT, LE_QUEST_FACTION_HORDE, LE_QUEST_FREQUENCY_DAILY, LE_QUEST_FREQUENCY_WEEKLY
10 local QUEST_TAG_TCOORDS, IsQuestSequenced = QUEST_TAG_TCOORDS, IsQuestSequenced
11 local Default, Quest = T.DefaultHandler, T.Quest
12 local format, wipe, select = format, table.wipe, select
13 local wipeall = B.wipeall
14 local lprint, iprint, tprint = B.print('Line'), B.print('Info'), B.print('Tracker')
15 local print = tprint
16 local fprint = B.print('Frame')
17
18
19 local superTrackQuestID, playerMoney, inScenario, showPOIs
20 Quest.Update = function(self, reason, ...)
21 local print = self.print
22 print('QuestTracker:Update() received')
23 T.UpdateActionButtons()
24 Default.Update(self, reason, ...)
25 end
26
27 T.Quest.numButtons = 0
28 local usedButtons = T.Quest.itemButtons
29 local freeButtons = T.Quest.freeButtons
30
31 Quest.UpdateObjectives = function(self, block)
32 local print = lprint
33 print('|cFF'..self.internalColor..'UpdateObjectives()')
34 local info = block.info
35
36 print((info.isAccount and 'isAccount' or ''), (info.isFaction and 'isFaction' or ''), (info.isDaily and 'isDaily' or ''), (info.isWeekly and 'isWeekly' or ''), info.tagID, info.tagName)
37
38 local displayObjectives = true
39 local block_schema = 'default'
40 if info.isAccount then
41 if info.isFaction then
42 print(' faction', info.tagID)
43 block_schema = 'faction_'..info.tagID
44 else
45 print(' account', info.isAccount, info.isFaction)
46 block_schema = 'account'
47 end
48 elseif info.isDaily then
49 print(' daily', info.frequency)
50 block_schema = 'daily'
51 elseif info.isWeekly then
52 print(' weekly', info.frequency)
53 block_schema = 'weekly'
54 end
55 local completionText
56 if info.isComplete then
57 if info.isAutoComplete then
58 local questID, popupType = GetAutoQuestPopUp(info.logIndex)
59 if popupType == 'COMPLETE' then
60 print(' :: auto-complete quest :: set the message')
61 self:AddLine(block, T.strings.CLICK_TO_COMPLETE, nil, 'complete')
62 end
63 else
64 if not completionText or info.completionText then
65 info.completionText = GetQuestLogCompletionText(info.logIndex)
66 end
67 end
68 self:AddLine(block, info.completionText, nil, 'complete')
69 displayObjectives = false
70 print('|cFF'..self.internalColor..' :: complete quest :: show instruction: "'.. tostring(info.completionText) .. '"')
71 end
72
73 Default.UpdateObjectives(self, block, block_schema, displayObjectives)
74 return 0, block_schema
75 end
76
77 Quest.UpdateLine = function(handler, block, data)
78 local objectiveType = data.type
79 return data.text, nil, objectiveType
80 end
81
82 -----------------------------
83 --- QUEST
84 local tremove, tinsert = tremove, tinsert
85 local GetQuestLogIndexByID, IsQuestWatched = GetQuestLogIndexByID, IsQuestWatched
86 Quest.QuestBlock = {}
87 Quest.LogBlock = {}
88 Quest.LogInfo = {}
89
90 Quest.OnRemoved = function(block)
91
92 end
93
94 Quest.GetBlock = function(self, index)
95 local block = Default.GetBlock(self, index)
96 block:SetScript('OnEvent', Quest.OnRemoved)
97 block:RegisterEvent('QUEST_REMOVED')
98 return block
99 end
100
101 local GetQuestWatchIndex = GetQuestWatchIndex
102 local numAnimating = 0
103 local blocksChecked = {}
104
105 --- Get a total of things to show, and straighten out the index while we're at it
106 --- Return the number shown, total in log, and the info table to parse
107 Quest.GetNumWatched = function (self, id, added)
108 local print = self.print
109 B.print('Block')('########')
110 B.print('Block')('########')
111 superTrackQuestID = GetSuperTrackedQuestID()
112 playerMoney = GetMoney();
113 inScenario = C_Scenario.IsInScenario();
114 showPOIs = GetCVarBool("questPOI");
115 local numAll = GetNumQuestLogEntries()
116 local numWatched = GetNumQuestWatches()
117 local bottomIndex = 1
118 print('GetNumWatched', self.name, numWatched, 'of', numAll)
119 local start, limit = 1, numAll
120
121 if id and not added then
122 -- if a particular id is supplied, add to checklist
123 if self.InfoBlock[id] then
124 blocksChecked[self.InfoBlock[id]] = self.InfoBlock[id]
125 end
126 end
127
128 numAnimating = 0
129 for logIndex = start, limit do
130 local reason1, reason2 = '', ''
131 local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(logIndex)
132 local watchIndex = GetQuestWatchIndex(logIndex)
133
134 --- Start of crazy audit flagging
135 if watchIndex and watchIndex >= bottomIndex then
136 -- do watch data pointers match?
137 local watchInfo = self.WatchInfo[watchIndex]
138 local watchBlock = self.WatchBlock[watchIndex]
139 if watchInfo and watchInfo.questID ~= questID then
140 print('GetNumWatched', 'trimming WatchInfo ['..watchIndex..'] =/=', questID)
141 self.WatchInfo[watchIndex] = nil
142 end
143 if watchBlock and watchBlock.info.questID ~= questID then
144 print('GetNumWatched', 'trimming WatchBlock ['..watchIndex..'] =/=', watchBlock:GetName())
145 self.WatchBlock[watchIndex] = nil
146 blocksChecked[watchBlock] = watchBlock
147 end
148 end
149
150 -- check log-block pointer
151 local logBlock = self.LogBlock[logIndex]
152 if logBlock then
153 -- check later that the block isn't for a dropped quest
154 if logBlock.info.questID ~= questID then
155 print('GetQuests', 'replace info', logBlock.info.questID, '->', questID)
156 self.LogBlock[logIndex] = nil
157 blocksChecked[logBlock] = logBlock
158 end
159 end
160 --- end of crazy audit flagging
161
162 -- add to watch index if: the questID is non-zero
163 if questID ~= 0 then
164 self.Info[questID] = self:GetInfo(logIndex, watchIndex)
165 print('GetQuests', format('request info |cFF00FF00%2d|r |cFFFFFF00%6d|r |cFFFF4400%3s|r', logIndex, questID, tostring(watchIndex or '')))
166 end
167 end
168
169 --- After GetInfo pass, look for any non-conformant blocks and deal with them
170 for _, block in pairs(blocksChecked) do
171 local logIndex = GetQuestLogIndexByID(block.info.questID, 'player')
172 -- animating blocks have been evaluated
173 if not block.isAnimating then
174 if not logIndex then
175 self:ClearBlock(block)
176 elseif not IsQuestWatched(block.info.logIndex) then
177 self:ClearBlock(block)
178 end
179 end
180 blocksChecked[block] = nil
181 end
182
183 self.numWatched = numWatched
184 self.numAll = numAll
185
186 return numWatched, numAll, self.WatchList
187 end
188
189
190 --- Returns an iterable table from which tracker blocks can be filled out. Data includes:
191 -- All entry-layer GetXInfo return values
192 -- Manifest of line data to be displayed in relation to the tracked object
193 Quest.GetInfo = function (self, logIndex, watchIndex)
194 local print = iprint
195 local title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID, startEvent, displayQuestID, isOnMap, hasLocalPOI, isTask, isStory = GetQuestLogTitle(logIndex)
196 if ( not questID ) then
197 tprint('GetNumWatched', logIndex, watchIndex, '|cFFFF2299no data|r')
198 return
199 end
200
201 Quest.Info[questID] = Quest.Info[questID] or {}
202 local q = Quest.Info[questID]
203 q.questID = questID
204 q.id = questID
205 q.logIndex = logIndex
206 q.watchIndex = watchIndex
207
208 local numObjectives, requiredMoney, isAutoComplete, failureTime, timeElapsed, questType
209 = 0, 0, nil, false, false, 0
210 if watchIndex then
211 local _
212 _,_,_, numObjectives, requiredMoney, _, _, isAutoComplete,
213 failureTime, timeElapsed, questType = GetQuestWatchInfo(watchIndex)
214
215 -- ensure that the entry being populated isn't animating
216 if self.WatchBlock[watchIndex] then
217 local checkIndex = watchIndex
218 while self.WatchBlock[checkIndex + numAnimating] and self.WatchBlock[checkIndex + numAnimating].isAnimating do
219 print(self.WatchBlock[checkIndex + numAnimating]:GetName(), 'is in an animation sequence')
220 numAnimating = numAnimating + 1
221 end
222 end
223
224 self.WatchList[watchIndex + numAnimating] = q
225 --tprint(' |cFF88FF00GetInfo:|r set watch entry', watchIndex)
226 print('GetInfo:', logIndex, watchIndex, '|cFFFF2299'..title..'|r')
227 end
228 self.LogInfo[logIndex] = q
229
230 q.numObjectives = numObjectives
231 q.requiredMoney = requiredMoney
232 q.failureTime = failureTime
233 q.timeElapsed = timeElapsed
234
235
236
237 q.type = 'Quest'
238 q.title = title
239 q.level = level
240 q.displayQuestID = displayQuestID
241 q.suggestedGroup = suggestedGroup
242
243 -- re-use Blizzard logic for consistency
244 local showQuest = true
245 if isTask then showQuest = false end
246 local watchMoney = false;
247 local tagID, typeTag, frequencyTag, completionTag, completionText
248 local isAccount, isFaction, isWeekly, isDaily = false, false, false, false
249 local isBreadcrumb = false
250 local questFailed = false
251 local watchMoney = false
252 local timerInfo, moneyInfo = false, false
253 local objectives = q.objectives or {}
254
255
256 -- Case 1: completed quest or "go to thing" breadcrumb
257 -- * 1 line containing the completion text
258 if ( isComplete and isComplete < 0 ) then
259 isComplete = false
260 questFailed = true
261 elseif ( numObjectives == 0 and playerMoney >= requiredMoney and not startEvent ) then
262 isComplete = true;
263 questFailed = false
264 if ( requiredMoney == 0 ) then
265 isBreadcrumb = true;
266 end
267 end
268 print('QuestFlags', (isComplete and 'isComplete' or ''), (questFailed and 'questFailed' or ''), (isBreadcrumb and 'isBreadcrumb' or ''))
269
270 -- completion message?
271 local isSequenced = IsQuestSequenced(questID)
272 local temp_status = ''
273 if ( isComplete ) then
274 temp_status = 'COMPLETED_OBJECTIVES'
275 objectives = Quest.GetObjectives(questLogIndex, numObjectives, true, isSequenced, isStory)
276 if ( isAutoComplete ) then
277 temp_status = 'AUTOCOMPLETE_OBJECTIVES'
278 completionText = _G.QUEST_WATCH_CLICK_TO_COMPLETE
279 else
280 if ( isBreadcrumb ) then
281 temp_status = 'COMPLETE_BREADCRUMB'
282 completionText = GetQuestLogCompletionText(questLogIndex)
283 else
284 temp_status = 'COMPLETE_READY_FOR_TURN_IN'
285 completionText = _G.QUEST_WATCH_QUEST_READY
286 end
287 end
288 elseif ( questFailed ) then
289 temp_status = 'FAILED'
290 -- Case 2: failed quest
291 -- * 1 status line; hide other info
292 completionText = _G.FAILED
293 else
294
295 temp_status = 'PROGRESS_OBJECTIVES'
296 -- Case 3: quest in progress
297 -- * Multiple objective lines
298 -- * Possible extra lines for money and timer data respectively
299 self.print(' QuestInfo', title, questType, isAutoComplete)
300 objectives = Quest.GetObjectives(logIndex, numObjectives, false, isSequenced, isStory)
301 q.objectives = objectives
302
303 --- anything past here gets appended to existing objectives
304
305 -- money
306 if ( requiredMoney > playerMoney ) then
307
308 temp_status = temp_status .. '_MONEY'
309 local text = GetMoneyString(playerMoney).." / "..GetMoneyString(requiredMoney);
310 moneyInfo = {
311 type = 'money',
312 text = text,
313 finished = false,
314 requiredMoney = requiredMoney,
315 playerMoney = playerMoney,
316 }
317 tinsert(objectives, moneyInfo)
318 end
319
320 -- time limit
321 if ( failureTime ) then
322 temp_status = temp_status .. '_TIMED'
323 if ( timeElapsed and timeElapsed <= failureTime ) then
324 timerInfo = {
325 type = 'timer',
326 finished = false,
327 timeElapsed = timeElapsed,
328 failureTime = failureTime,
329 }
330 tinsert(objectives, timerInfo)
331 end
332 end
333 end
334 q.objectives = objectives
335 q.moneyInfo = moneyInfo
336 q.timerInfo = timerInfo
337 q.completionText = completionText
338
339 -- POI data
340 local POI = false
341 if ( showPOIs ) then
342 POI = {
343 questID = questID,
344 logIndex = logIndex,
345 watchIndex = watchIndex
346 }
347 local poiButton;
348 if ( hasLocalPOI ) then
349
350 if ( isComplete ) then
351 POI.type = 'normal'
352 else
353 POI.type = 'numeric'
354 end
355 elseif ( isComplete ) then
356 POI.type = 'remote'
357 end
358
359 local distance, onContinent = GetDistanceSqToQuest(logIndex)
360 if distance ~= nil and distance > 0 then
361 POI.distance = distance
362 POI.onContinent = onContinent
363 end
364 end
365 q.POI = POI
366
367 --- Block Tags
368 -- completionTag - in progres, complete, failed, autocomplete
369 -- typeTag - account, faction, pvp, dungeon, group
370 -- frequencyTag - daily/weekly
371 local schema = 'default'
372 local questTagID, tagName = GetQuestTagInfo(questID)
373 local tagInfo = {}
374 local tagCoords = {}
375 local factionGroup = GetQuestFactionGroup(questID);
376 if( questTagID and questTagID == QUEST_TAG_ACCOUNT ) then
377 if( factionGroup ) then
378 tagID = "ALLIANCE"
379 schema = 'alliance'
380 if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
381 tagID = "HORDE"
382 schema = 'horde'
383 end
384 isFaction = true
385 else
386 tagID = QUEST_TAG_ACCOUNT
387 isAccount = true
388 end
389 tagInfo['typeTag'] = tagID
390 tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID]
391 elseif ( factionGroup) then
392 tagID = "ALLIANCE"
393 if ( factionGroup == LE_QUEST_FACTION_HORDE ) then
394 tagID = "HORDE"
395 end
396 isFaction = true
397 tagInfo['typeTag'] = tagID
398 tagCoords['typeTag'] = QUEST_TAG_TCOORDS[tagID]
399 end
400
401 if( frequency == LE_QUEST_FREQUENCY_DAILY and (not isComplete or isComplete == 0) ) then
402 tagID = 'DAILY'
403 tagInfo['frequencyTag'] = tagID
404 tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
405 isDaily = true
406 schema = 'daily'
407 elseif( frequency == LE_QUEST_FREQUENCY_WEEKLY and (not isComplete or isComplete == 0) )then
408 tagID = 'WEEKLY'
409 tagInfo['frequencyTag'] = tagID
410 tagCoords['frequencyTag'] = QUEST_TAG_TCOORDS[tagID]
411 isWeekly = true
412 schema = 'weekly'
413 elseif( questTagID ) then
414 tagID = questTagID
415 end
416
417 if( isComplete ) then
418 tagInfo['completionTag'] = 'COMPLETED'
419 elseif ( questFailed ) then
420 tagInfo['completionTag'] = 'FAILED'
421 end
422 tagCoords['completionTag'] = QUEST_TAG_TCOORDS[tagInfo['completionTag']]
423
424 q.tagInfo = tagInfo
425 q.tagCoords = tagCoords
426 -- establishes the primary block tag for view compacting
427 q.tagID = tagID
428 q.tagName = tagName
429
430 -- action button information
431 local link, icon, charges = GetQuestLogSpecialItemInfo(logIndex)
432 local start, duration, enable = GetQuestLogSpecialItemCooldown(logIndex)
433 if link or icon or charges then
434 q.specialItem = {
435 questID = questID,
436 logIndex = questLogIndex,
437 link = link,
438 charges = charges,
439 icon = icon,
440 start = start,
441 duration = duration,
442 enable = enable,
443 }
444 end
445
446 if moneyInfo or timerInfo then
447 numObjectives = #objectives
448 end
449
450 -- raw data
451 q.isComplete = isComplete
452 q.startEvent = startEvent
453 q.isAutoComplete = isAutoComplete
454 q.questType = questType
455 q.isTask = isTask
456 q.isStory = isStory
457 q.isOnMap = isOnMap
458 q.hasLocalPOI = hasLocalPOI
459 q.frequency = frequency
460 q.isComplete = isComplete
461 q.isStory = isStory
462 q.isTask = isTask
463 q.statusKey = temp_status
464 q.selected = (questID == superTrackQuestID)
465
466 T.SetRewards(q, questID)
467
468 q.questID = questID
469 q.logIndex = logIndex
470 q.watchIndex = watchIndex
471 q.id = questID
472 q.schema = schema
473
474 if Devian and Devian.InWorkspace() then
475 print('QuestStatus', temp_status, '|cFF00FF00questLogIndex|r:', logIndex, title)
476 local temp ={}
477 local data_txt = '|cFF'..self.internalColor..'values:|r'
478 for k,v in pairs(q) do
479 if type(v) =='number' then
480 data_txt = data_txt .. ' |cFFFFFF00'..k..'|r: ' .. tostring(v)
481 elseif type(v) == 'table' then
482 tinsert(temp, k)
483 end
484 end
485 print('DataStatus',data_txt)
486 sort(temp, function(a,b) return a < b end)
487 for i, k in ipairs(temp) do
488 iprint('GetInfo', questID, ''..k..'|r')
489 for kk,v in pairs(q[k]) do
490 iprint('GetInfo', questID, kk, '=', v)
491 end
492 end
493 end
494
495 return q
496 end
497
498 Quest.GetObjectives = function(logIndex, numObjectives, isComplete, isSequenced, isStory)
499 local print = Quest.print
500 local objectives = {}
501 if not logIndex then
502 return
503 end
504
505 for i = 1, numObjectives do
506 local text, type, finished = GetQuestLogLeaderBoard(i, logIndex)
507
508 local progress = 0
509 if finished then
510 progress = 1
511 elseif text then
512 local quantity, maxQuantity = text:match('^(%d+)/(%d+)')
513 if quantity and maxQuantity then
514 progress = quantity / maxQuantity
515 --print('GetObjectives', 'calculated objective progress:', quantity, '/', maxQuantity, '=', progress)
516 end
517 end
518
519 print('GetObjectives', format('|cFF88FF88#%d %s %s %s', i, tostring(type), tostring(text), tostring(finished)), '('.. tostring(progress)..')')
520
521
522 objectives[i] = {
523 index = i,
524 type = type,
525 text = text,
526 finished = finished,
527 progress = progress
528 }
529 end
530 return objectives
531 end
532
533 local huge, sqrt = math.huge, math.sqrt
534 Quest.GetClosest = function()
535 local minID, minTitle
536 local minDist = huge
537 local numQuests = GetNumQuestLogEntries()
538 for questIndex = 1, numQuests do
539 local distance, onContinent = GetDistanceSqToQuest(questIndex)
540 local title, level, _, _, _, _, _, _, questID = GetQuestLogTitle(questIndex)
541 if onContinent and distance < minDist then
542 minDist = distance
543 minTitle = title
544 minID = questID
545 end
546 end
547
548 print('nearest quest is', minTitle, 'by', sqrt(minDist))
549 return minID, minTitle, minDist
550 end
551
552 Quest.OnTurnIn = function(self, questID, xp, money)
553 end
554
555 Quest.Select = function (handler, block)
556 if block.info.isAutoComplete and block.info.isComplete then
557 ShowQuestComplete(block.info.logIndex)
558 else
559 SetSuperTrackedQuestID(block.info.questID)
560 end
561 end
562
563 Quest.Link = function(handler, block)
564 local questLink = GetQuestLink(block.info.logIndex);
565 if ( questLink ) then
566 ChatEdit_InsertLink(questLink);
567 end
568 end
569
570 Quest.Open = function(handler, block)
571 QuestMapFrame_OpenToQuestDetails(block.info.questID)
572 end
573
574 Quest.Remove = function(handler, block)
575 print('removing', block.info.logIndex, 'from watcher')
576 RemoveQuestWatch(block.info.logIndex)
577 end