vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 local tablet = AceLibrary("Tablet-2.0")
2 local compost = AceLibrary("Compost-2.0")
3 local deformat = AceLibrary("Deformat-2.0")
4 local babbleclass = AceLibrary("Babble-Class-2.0")
5 local crayon = AceLibrary("Crayon-2.0")
6 local tourist = AceLibrary("Tourist-2.0")
7  
8 local L = AceLibrary("AceLocale-2.0"):new("QuestsFu")
9  
10 QuestsFu = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0", "AceConsole-2.0", "AceDB-2.0", "FuBarPlugin-2.0")
11 QuestsFu:RegisterDB("QuestsFuDB")
12 QuestsFu:RegisterDefaults('profile', {
13 showLevelsGame = true,
14 showLevelsTablet = true,
15 showLevelsZone = true,
16 showDifficulty = true,
17 showImpossible = true,
18 showArea = true,
19 showCurrentAreaOnly = false,
20 showClassAnyway = true,
21 showCurrentAreaDescriptionOnly = false,
22 showDescription = true,
23 showCompletedObjectives = false,
24 showInItemTooltip = true,
25 colorObjectives = true,
26 wrapQuests = true,
27 showTextOpt = {
28 total = true,
29 current = true,
30 complete = false,
31 lastmessage = true,
32 },
33 })
34 QuestsFu:RegisterDefaults('char', {
35 hidden = {},
36 watchedQuests = {},
37 })
38  
39 QuestsFu.version = "2.0." .. string.sub("$Revision: 10107 $", 12, -3)
40 QuestsFu.date = string.sub("$Date: 2006-09-04 13:31:04 -0700 (Mon, 04 Sep 2006) $", 8, 17)
41 QuestsFu.hasIcon = true
42 QuestsFu.clickableTooltip = true
43 QuestsFu.cannotHideText = true
44  
45 local optionsTable = {
46 handler = QuestsFu,
47 type = 'group',
48 args = {
49 show = {
50 type = 'group',
51 name = L["OPT_show"],
52 desc = L["OPT_show_d"],
53 args = {
54 text = {
55 type = 'group',
56 name = L["OPT_text"],
57 desc = L["OPT_text_d"],
58 args = {
59 current = {
60 type = 'toggle',
61 name = L["OPT_current"],
62 desc = L["OPT_current_d"],
63 get = "IsShowingTextCurrent",
64 set = "ToggleShowingTextCurrent",
65 },
66 complete = {
67 type = 'toggle',
68 name = L["OPT_complete"],
69 desc = L["OPT_complete_d"],
70 get = "IsShowingTextComplete",
71 set = "ToggleShowingTextComplete",
72 },
73 total = {
74 type = 'toggle',
75 name = L["OPT_total"],
76 desc = L["OPT_total_d"],
77 get = "IsShowingTextTotal",
78 set = "ToggleShowingTextTotal",
79 },
80 lastmessage = {
81 type = 'toggle',
82 name = L["OPT_lastmessage"],
83 desc = L["OPT_lastmessage_d"],
84 get = "IsShowingTextLastMessage",
85 set = "ToggleShowingTextLastMessage",
86 },
87 }
88 },
89 levels = {
90 type = 'group',
91 name = L["OPT_levels"],
92 desc = L["OPT_levels_d"],
93 args = {
94 game = {
95 type = "toggle", name = L["OPT_levels_game"],
96 desc = L["OPT_levels_game_d"],
97 get = "IsShowingLevelsGame",
98 set = "ToggleShowingLevelsGame",
99 },
100 tablet = {
101 type = "toggle", name = L["OPT_levels_tablet"],
102 desc = L["OPT_levels_tablet_d"],
103 get = "IsShowingLevelsTablet",
104 set = "ToggleShowingLevelsTablet",
105 },
106 zone = {
107 type = "toggle", name = L["OPT_levels_zone"],
108 desc = L["OPT_levels_zone_d"],
109 get = "IsShowingLevelsZone",
110 set = "ToggleShowingLevelsZone",
111 },
112 },
113 },
114 diff = {
115 type = 'toggle',
116 name = L["OPT_diff"],
117 desc = L["OPT_diff_d"],
118 get = "IsShowingDifficulty",
119 set = "ToggleShowingDifficulty",
120 },
121 impossible = {
122 type = 'toggle',
123 name = L["OPT_impossible"],
124 desc = L["OPT_impossible_d"],
125 get = "IsShowingImpossible",
126 set = "ToggleShowingImpossible",
127 },
128 area = {
129 type = 'toggle',
130 name = L["OPT_area"],
131 desc = L["OPT_area_d"],
132 get = "IsShowingArea",
133 set = "ToggleShowingArea",
134 },
135 caonly = {
136 type = 'toggle',
137 name = L["OPT_caonly"],
138 desc = L["OPT_caonly_d"],
139 get = "IsShowingCurrentAreaOnly",
140 set = "ToggleShowingCurrentAreaOnly",
141 },
142 classanyway = {
143 type = 'toggle',
144 name = L["OPT_classanyway"],
145 desc = L["OPT_classanyway_d"],
146 get = "IsShowingClassAnyway",
147 set = "ToggleShowingClassAnyway",
148 },
149 description = {
150 type = 'toggle',
151 name = L["OPT_description"],
152 desc = L["OPT_description_d"],
153 get = "IsShowingDescription",
154 set = "ToggleShowingDescription",
155 },
156 cadonly = {
157 type = 'toggle',
158 name = L["OPT_cadonly"],
159 desc = L["OPT_cadonly_d"],
160 get = "IsShowingCurrentAreaDescriptionOnly",
161 set = "ToggleShowingCurrentAreaDescriptionOnly",
162 },
163 completed= {
164 type = 'toggle',
165 name = L["OPT_completed"],
166 desc = L["OPT_completed_d"],
167 get = "IsShowingCompletedObjectives",
168 set = "ToggleShowingCompletedObjectives",
169 },
170 tooltip = {
171 type = 'toggle',
172 name = L["OPT_tooltip"],
173 desc = L["OPT_tooltip_d"],
174 get = "IsShowingInItemTooltip",
175 set = "ToggleShowingInItemTooltip",
176 },
177 colorobj = {
178 type = 'toggle',
179 name = L["OPT_colorobj"],
180 desc = L["OPT_colorobj_d"],
181 get = "IsColoringObjectives",
182 set = "ToggleColoringObjectives",
183 },
184 wrap = {
185 type = 'toggle',
186 name = L["OPT_wrap"],
187 desc = L["OPT_wrap_d"],
188 get = "IsWrappingQuests",
189 set = "ToggleWrappingQuests",
190 },
191 }
192 }
193 }
194 }
195  
196 QuestsFu:RegisterChatCommand({"/questsfu", "/fuq" }, optionsTable)
197 QuestsFu.OnMenuRequest = optionsTable
198  
199 function QuestsFu:ToggleShowingTextComplete()
200 self.db.profile.showTextOpt.complete = not self.db.profile.showTextOpt.complete
201 self:UpdateText()
202 return self.db.profile.showTextOpt.complete
203 end
204 function QuestsFu:ToggleShowingTextCurrent()
205 self.db.profile.showTextOpt.current = not self.db.profile.showTextOpt.current
206 self:UpdateText()
207 return self.db.profile.showTextOpt.current
208 end
209 function QuestsFu:ToggleShowingTextTotal()
210 self.db.profile.showTextOpt.total = not self.db.profile.showTextOpt.total
211 self:UpdateText()
212 return self.db.profile.showTextOpt.total
213 end
214 function QuestsFu:ToggleShowingTextLastMessage()
215 self.db.profile.showTextOpt.lastmessage = not self.db.profile.showTextOpt.lastmessage
216 self:UpdateText()
217 return self.db.profile.showTextOpt.lastmessage
218 end
219  
220 function QuestsFu:IsShowingTextComplete()
221 return self.db.profile.showTextOpt.complete
222 end
223 function QuestsFu:IsShowingTextCurrent()
224 return self.db.profile.showTextOpt.current
225 end
226 function QuestsFu:IsShowingTextTotal()
227 return self.db.profile.showTextOpt.total
228 end
229 function QuestsFu:IsShowingTextLastMessage()
230 return self.db.profile.showTextOpt.lastmessage
231 end
232  
233 function QuestsFu:IsShowingLevelsGame()
234 return self.db.profile.showLevelsGame
235 end
236  
237 function QuestsFu:IsShowingLevelsTablet()
238 return self.db.profile.showLevelsTablet
239 end
240  
241 function QuestsFu:IsShowingLevelsZone()
242 return self.db.profile.showLevelsZone
243 end
244  
245 function QuestsFu:ToggleShowingLevelsGame(silent)
246 self.db.profile.showLevelsGame = not self.db.profile.showLevelsGame
247 if self.db.profile.showLevelsGame then
248 self:RegisterEvent("GOSSIP_SHOW", "OnGossipShow")
249 self:RegisterEvent("QUEST_GREETING", "OnQuestGreeting")
250 self:Hook("GetQuestLogTitle")
251 else
252 self:UnregisterEvent("GOSSIP_SHOW", "OnGossipShow")
253 self:UnregisterEvent("QUEST_GREETING", "OnQuestGreeting")
254 self:Unhook("GetQuestLogTitle")
255 end
256 self:UpdateData()
257 return self.db.profile.showLevelsGame
258 end
259  
260 function QuestsFu:ToggleShowingLevelsTablet(silent)
261 self.db.profile.showLevelsTablet = not self.db.profile.showLevelsTablet
262 self:UpdateTooltip()
263 return self.db.profile.showLevelsTablet
264 end
265  
266 function QuestsFu:ToggleShowingLevelsZone(silent)
267 self.db.profile.showLevelsZone = not self.db.profile.showLevelsZone
268 self:UpdateTooltip()
269 return self.db.profile.showLevelsZone
270 end
271  
272 function QuestsFu:IsShowingDifficulty()
273 return self.db.profile.showDifficulty
274 end
275  
276 function QuestsFu:ToggleShowingDifficulty(silent)
277 self.db.profile.showDifficulty = not self.db.profile.showDifficulty
278 self:UpdateTooltip()
279 return self.db.profile.showDifficulty
280 end
281  
282 function QuestsFu:IsShowingImpossible()
283 return self.db.profile.showImpossible
284 end
285  
286 function QuestsFu:ToggleShowingImpossible(silent)
287 self.db.profile.showImpossible = not self.db.profile.showImpossible
288 self:UpdateTooltip()
289 return self.db.profile.showImpossible
290 end
291  
292 function QuestsFu:IsShowingArea()
293 return self.db.profile.showArea
294 end
295  
296 function QuestsFu:ToggleShowingArea(silent)
297 self.db.profile.showArea = not self.db.profile.showArea
298 self:UpdateTooltip()
299 return self.db.profile.showArea
300 end
301  
302 function QuestsFu:IsShowingCurrentAreaOnly()
303 return self.db.profile.showCurrentAreaOnly
304 end
305  
306 function QuestsFu:ToggleShowingCurrentAreaOnly(silent)
307 self.db.profile.showCurrentAreaOnly = not self.db.profile.showCurrentAreaOnly
308 self:UpdateTooltip()
309 return self.db.profile.showCurrentAreaOnly
310 end
311  
312 function QuestsFu:IsShowingClassAnyway()
313 return self.db.profile.showClassAnyway
314 end
315  
316 function QuestsFu:ToggleShowingClassAnyway(silent)
317 self.db.profile.showClassAnyway = not self.db.profile.showClassAnyway
318 self:UpdateTooltip()
319 return self.db.profile.showClassAnyway
320 end
321  
322 function QuestsFu:IsShowingCurrentAreaDescriptionOnly()
323 return self.db.profile.showCurrentAreaDescriptionOnly
324 end
325  
326 function QuestsFu:ToggleShowingCurrentAreaDescriptionOnly(silent)
327 self.db.profile.showCurrentAreaDescriptionOnly = not self.db.profile.showCurrentAreaDescriptionOnly
328 self:UpdateTooltip()
329 return self.db.profile.showCurrentAreaDescriptionOnly
330 end
331  
332 function QuestsFu:IsShowingDescription()
333 return self.db.profile.showDescription
334 end
335  
336 function QuestsFu:ToggleShowingDescription(silent)
337 self.db.profile.showDescription = not self.db.profile.showDescription
338 self:UpdateTooltip()
339 return self.db.profile.showDescription
340 end
341  
342 function QuestsFu:IsColoringObjectives()
343 return self.db.profile.colorObjectives
344 end
345  
346 function QuestsFu:ToggleColoringObjectives(silent)
347 self.db.profile.colorObjectives = not self.db.profile.colorObjectives
348 self:UpdateTooltip()
349 return self.db.profile.colorObjectives
350 end
351  
352 function QuestsFu:IsShowingCompletedObjectives()
353 return self.db.profile.showCompletedObjectives
354 end
355  
356 function QuestsFu:ToggleShowingCompletedObjectives(silent)
357 self.db.profile.showCompletedObjectives = not self.db.profile.showCompletedObjectives
358 self:UpdateTooltip()
359 return self.db.profile.showCompletedObjectives
360 end
361  
362 function QuestsFu:IsShowingInItemTooltip()
363 return self.db.profile.showInItemTooltip
364 end
365  
366 function QuestsFu:ToggleShowingInItemTooltip(silent)
367 self.db.profile.showInItemTooltip = not self.db.profile.showInItemTooltip
368 self:UpdateTooltip()
369 return self.db.profile.showInItemTooltip
370 end
371  
372 function QuestsFu:IsWrappingQuests()
373 return self.db.profile.wrapQuests
374 end
375  
376 function QuestsFu:ToggleWrappingQuests(silent)
377 self.db.profile.wrapQuests = not self.db.profile.wrapQuests
378 self:UpdateTooltip()
379 return self.db.profile.wrapQuests
380 end
381  
382 function QuestsFu:OnInitialize()
383 if type(self.db.profile.showText) == 'table' then
384 --FuBarPlugin-2.0 appropriated .showText. Switch it out.
385 self.db.profile.showTextOps = self.db.profile.showText
386 self.db.profile.showText = nil
387 end
388  
389 self.numQuests = 0
390 self.numEntries = 0
391 self.zones = {}
392 self.zone_quests = {}
393 self.quests = {}
394 self.items = {}
395 self.mobs = {}
396 self.lastuimessage = ""
397 self.lastquestmessage = ""
398  
399 self.allowedToUpdate = true
400  
401 self.loadedWatchedQuests = false
402 end
403  
404 function QuestsFu:OnEnable()
405 self:RegisterEvent("QUEST_LOG_UPDATE", "OnQuestLogUpdate")
406 self:RegisterEvent("PLAYER_LEVEL_UP", "UpdateTooltip") -- Quest difficulty colors can change on level; just redraw the tooltip in case they have it open while levelling.
407 self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "UpdateTooltip")
408 self:RegisterEvent("UPDATE_MOUSEOVER_UNIT", "OnMouseOverUnit")
409 self:RegisterEvent("UI_INFO_MESSAGE","OnUIInfoMessage")
410 self:Hook("ContainerFrameItemButton_OnEnter", "OnItemTooltip")
411 self:Hook("AddQuestWatch", "OnAddQuestWatch")
412 self:Hook("RemoveQuestWatch", "OnRemoveQuestWatch")
413  
414 self:ScheduleEvent(self.LoadWatchedQuests, 1, self)
415  
416 if self:IsShowingLevelsGame() then
417 self:RegisterEvent("GOSSIP_SHOW", "OnGossipShow")
418 self:RegisterEvent("QUEST_GREETING", "OnQuestGreeting")
419 self:Hook("GetQuestLogTitle")
420 end
421 end
422  
423 function QuestsFu:Disable()
424 metro:Unregister(self.name)
425 end
426  
427 function QuestsFu:MakeTag(level, tag)
428 if tag then
429 if tag == L["ELITE"] then tag = L["TAG_ELITE"]
430 elseif tag == L["DUNGEON"] then tag = L["TAG_DUNGEON"]
431 elseif tag == L["PVP"] then tag = L["TAG_PVP"]
432 elseif tag == L["RAID"] then tag = L["TAG_RAID"]
433 end
434 else
435 tag = ''
436 end
437 return "[" .. level .. tag .. "] "
438 end
439  
440 function QuestsFu:GetQuestLogTitle(index)
441 local questLogTitleText, level, questTag, isHeader, isCollapsed, isComplete = self.hooks["GetQuestLogTitle"].orig(index)
442 if not isHeader and level then
443 if questLogTitleText then
444 questLogTitleText = self:MakeTag(level, questTag) .. questLogTitleText
445 end
446 end
447 return questLogTitleText, level, questTag, isHeader, isCollapsed, isComplete
448 end
449  
450 --This is pretty much how Minimalist does it, which it credits to AutoSelect.
451 function QuestsFu:OnGossipShow()
452 local buttonindex = 1
453 local list, button
454 if (GetGossipAvailableQuests()) then
455 list = compost:Acquire(GetGossipAvailableQuests())
456 for i = 2,getn(list),2 do
457 button = getglobal("GossipTitleButton"..(buttonindex))
458 button:SetText(format('[%d] %s',list[i],list[i-1]))
459 buttonindex = buttonindex + 1
460 end
461 buttonindex = buttonindex + 1
462 compost:Reclaim(list)
463 end
464 if (GetGossipActiveQuests()) then
465 list = compost:Acquire(GetGossipActiveQuests())
466 for i = 2,getn(list),2 do
467 button = getglobal("GossipTitleButton"..(buttonindex))
468 button:SetText(format('[%d] %s',list[i],list[i-1]))
469 buttonindex = buttonindex + 1
470 end
471 compost:Reclaim(list)
472 end
473 end
474  
475 --This is pretty much how Minimalist does it, which it credits to AutoSelect.
476 function QuestsFu:OnQuestGreeting()
477 local numactive,numavailable = GetNumActiveQuests(), GetNumAvailableQuests()
478 local title, level, button
479 local o,GetTitle,GetLevel = 0,GetActiveTitle,GetActiveLevel
480 for i=1, numactive + numavailable do
481 if i == numactive + 1 then
482 o,GetTitle,GetLevel = numactive,GetAvailableTitle,GetAvailableLevel
483 end
484 title,level = GetTitle(i-o), GetLevel(i-o)
485 button = getglobal("QuestTitleButton"..i)
486 button:SetText(format('[%d] %s',level,title))
487 end
488 end
489  
490 function QuestsFu:OnAddQuestWatch(id)
491 self.hooks["AddQuestWatch"].orig(id)
492 self:SaveWatchedQuests()
493 end
494  
495 function QuestsFu:OnRemoveQuestWatch(id)
496 self.hooks["RemoveQuestWatch"].orig(id)
497 self:SaveWatchedQuests()
498 end
499  
500 function QuestsFu:OnUIInfoMessage()
501 self.lastuimessage = arg1
502 self:ScheduleEvent(self.ClearUIInfoMessage, 0.5, self)
503 end
504  
505 function QuestsFu:ClearUIInfoMessage()
506 self.lastuimessage = ""
507 end
508  
509 function QuestsFu:OnQuestLogUpdate()
510 if self.allowedToUpdate then self.lastquestmessage = self.lastuimessage end
511 self.allowedToUpdate = false
512 self:ScheduleEvent("ThrottleUpdate", function(self)
513 self.allowedToUpdate = true
514 self:Update()
515 end, 1, self)
516 end
517  
518 function QuestsFu:OnMouseOverUnit()
519 -- Make sure that this is wanted, and that the tooltip is actually read/writeable.
520 if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
521 --Comes with color codes. Strip 'em out.
522 local thisMob = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|?r?","%1")
523 if self.mobs[thisMob] then
524 self:AddToGameTooltipAndFixHeight(self.mobs[thisMob].quest..": "..self.mobs[thisMob].needed, self.mobs[thisMob].colorr, self.mobs[thisMob].colorg, self.mobs[thisMob].colorb)
525 end
526 end
527 end
528  
529 function QuestsFu:OnItemTooltip()
530 self.hooks["ContainerFrameItemButton_OnEnter"].orig()
531 if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
532 --Comes with color codes. Strip 'em out.
533 local thisItem = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|r","%1")
534 if self.items[thisItem] then
535 self:AddToGameTooltipAndFixHeight(self.items[thisItem].quest..": "..self.items[thisItem].needed, self.items[thisItem].colorr, self.items[thisItem].colorg, self.items[thisItem].colorb)
536 end
537 end
538 end
539  
540 function QuestsFu:CanMessWithGameTooltip()
541 if GameTooltip and getglobal('GameTooltipTextLeft1'):IsVisible() and getglobal('GameTooltipTextLeft1'):GetText() ~= nil then
542 return true
543 else
544 return false
545 end
546 end
547  
548 function QuestsFu:AddToGameTooltipAndFixHeight(text, r, g, b)
549 GameTooltip:AddLine(text, r, g, b)
550  
551 -- Fix up the width of the tooltip
552 length = getglobal(GameTooltip:GetName() .. "TextLeft" .. GameTooltip:NumLines()):GetStringWidth()
553 -- Space for right-border:
554 length = length + 22
555  
556 GameTooltip:SetHeight(GameTooltip:GetHeight() + 14)
557 if length > GameTooltip:GetWidth() then
558 GameTooltip:SetWidth(length)
559 end
560 end
561  
562 function QuestsFu:OnDataUpdate()
563 --UpdateText and UpdateTooltip both need to know things about the questlog. Better to do this once.
564 compost:Reclaim(self.quests, 3)
565 compost:Reclaim(self.zone_quests, 1)
566 self.quests, self.zone_quests = nil, nil
567  
568 local startingQuestLogSelection = GetQuestLogSelection()
569 local numEntries, numQuests = GetNumQuestLogEntries()
570 local numQuestsDone = 0
571 local quests = compost:Acquire()
572 local zones = compost:Erase(self.zones)
573 --LEVELS--local level_quests = {}
574 local zone_quests = compost:Acquire()
575 local items = compost:Erase(self.items)
576 local mobs = compost:Erase(self.mobs)
577 local zoneIndex = "OMG NONE" --The first item in the quest log should always be a header, so this should always be replaced. But just in case.
578  
579 if numEntries > 0 and self.allowedToUpdate then
580 local questid
581 for questid = 1, numEntries do
582 local strQuestLogTitleText, strQuestLevel, strQuestTag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(questid)
583 local q = compost:Acquire()
584  
585 if isHeader then
586 zoneIndex = strQuestLogTitleText
587 table.insert(zones, zoneIndex)
588 zone_quests[zoneIndex] = compost:Acquire()
589 else
590 q.zone = zoneIndex
591 q.tag = strQuestTag
592  
593 SelectQuestLogEntry(questid)
594  
595 if isComplete == 1 then
596 isComplete = L["QUEST_DONE"]
597 numQuestsDone = numQuestsDone + 1
598 elseif isComplete == -1 then
599 isComplete = L["QUEST_FAILED"]
600 else
601 isComplete = nil
602 end
603  
604 q.title = strQuestLogTitleText
605 q.level = strQuestLevel
606 q.complete = isComplete
607  
608 local lb = compost:Acquire()
609 if GetNumQuestLeaderBoards() > 0 then
610 local ii
611 for ii=1, GetNumQuestLeaderBoards() do
612 local desc, qtype, done = GetQuestLogLeaderBoard(ii)
613 local itemName,mobName,numNeeded,numItems,factionName,factionCurrent,factionNeeded
614  
615 if qtype == 'item' then
616 itemName,numItems,numNeeded = deformat(desc, QUEST_OBJECTS_FOUND)
617 desc = itemName
618 elseif qtype == 'monster' then
619 mobName,numItems,numNeeded = deformat(desc, QUEST_MONSTERS_KILLED)
620 if mobName == nil or numItems == nil or numNeeded == nil then
621 --Sometimes we get objectives like "Find Mankrik's Wife: 0/1", which are listed as "monster".
622 mobName, numItems, numNeeded = deformat(desc, QUEST_OBJECTS_FOUND)
623 end
624 desc = mobName
625 elseif qtype == 'reputation' then
626 factionName,factionCurrent,factionNeeded = deformat(desc, QUEST_FACTION_NEEDED)
627 numItems = self:GetReactionLevel(factionCurrent)
628 numNeeded = self:GetReactionLevel(factionNeeded)
629 desc = factionName
630 end
631  
632 local r,g,b
633 if numItems ~= nil then
634 -- This quest involves items!
635 r, g, b = crayon:GetThresholdColor(numItems / numNeeded)
636 end
637  
638 if qtype == 'item' then
639 items[itemName] = compost:AcquireHash('quest', strQuestLogTitleText, 'item', itemName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
640 elseif qtype == 'monster' then
641 mobs[mobName] = compost:AcquireHash('quest', strQuestLogTitleText, 'mob', mobName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
642 end
643  
644 if done then
645 done = L["QUEST_DONE"]
646 elseif numItems and numNeeded then
647 if qtype == 'reputation' then
648 done = string.format("%s/%s",factionCurrent,factionNeeded)
649 else
650 done = string.format("%s/%s",numItems,numNeeded)
651 end
652 else
653 --I think this shouldn't happen. ...but I haven't seen every quest out there.
654 done = ""
655 end
656  
657 table.insert(lb, compost:AcquireHash('description', desc, 'done', done, 'colorr', r, 'colorg', g, 'colorb', b))
658 end
659 else
660 local strQuestDescription, strQuestObjectives = GetQuestLogQuestText(questid)
661 --q.objective = self.superwrap(strQuestObjectives, 50, 0, 2)
662 q.objective = strQuestObjectives
663 end
664 q.leaderboard = lb
665 q.id = questid
666  
667 quests[questid] = q
668 table.insert(zone_quests[zoneIndex], questid)
669 --LEVELS--table.insert(level_quests[tonumber(strQuestLevel)], questid)
670 end
671 end
672 end
673  
674 self.quests = quests
675 self.zones = zones
676 --LEVELS--self.level_quests = level_quests
677 self.zone_quests = zone_quests
678 self.items = items
679 self.mobs = mobs
680 self.numQuests = numQuests
681 self.numEntries = numEntries
682 self.numQuestsDone = numQuestsDone
683  
684 SelectQuestLogEntry(startingQuestLogSelection)
685  
686 self:SaveWatchedQuests() --A watched quest may have gone away because of the update. (The game doesn't call RemoveQuestWatch for it...)
687 end
688  
689 function QuestsFu:OnTextUpdate()
690 local text = ""
691 local maxQuests = 20
692 if self.allowedToUpdate then
693 local r,g,b = GameFontNormal:GetTextColor()
694 local color = string.format("%02X%02X%02X", r * 255, g * 255, b * 255)
695 if self:IsShowingTextComplete() then
696 color = crayon:GetThresholdHexColor(self.numQuestsDone / self.numQuests)
697 text = text .. crayon:Colorize(color,self.numQuestsDone)
698 end
699 if self:IsShowingTextComplete() and (self:IsShowingTextCurrent() or self:IsShowingTextTotal()) then
700 text = text .. crayon:Colorize(color,"/")
701 end
702 if self:IsShowingTextCurrent() then
703 color = crayon:GetThresholdHexColor((maxQuests - self.numQuests) / maxQuests)
704 text = text .. crayon:Colorize(color,self.numQuests)
705 end
706 if self:IsShowingTextCurrent() and self:IsShowingTextTotal() then
707 text = text .. crayon:Colorize(color,"/")
708 end
709 if self:IsShowingTextTotal() then
710 text = text .. crayon:Colorize(color,maxQuests)
711 end
712 if (self:IsShowingTextTotal() or self:IsShowingTextComplete() or self:IsShowingTextCurrent()) and self:IsShowingTextLastMessage() and self.lastquestmessage ~= "" then
713 text = text .. " m: "
714 end
715 if self:IsShowingTextLastMessage() and self.lastquestmessage ~= "" then
716 text = text .. self.lastquestmessage
717 end
718 else
719 text = L["TEXT_LOADING"]
720 end
721 self:SetText(text)
722 end
723  
724 function QuestsFu:OnTooltipUpdate()
725 if self.numQuests > 0 and self.allowedToUpdate then
726 if table.getn(self.zones) then
727 local currentZone = GetZoneText()
728 local zonename, zone
729 local cat
730 if not self:IsShowingArea() then
731 cat = tablet:AddCategory('columns', 2)
732 local sortedQuests = self:SortQuests(self.quests)
733 for _,quest in sortedQuests do
734 self:AddQuestToTooltip(cat, quest, true)
735 end
736 compost:Reclaim(sortedQuests)
737 else
738 for _,zone in self.zones do
739 -- If showing area headers and either not showing only the current area's quests or this is the current area.
740 if self:IsShowingArea() and ((currentZone == zone) or not self:IsShowingCurrentAreaOnly() or (self:IsShowingClassAnyway() and UnitClass("player") == zone)) then
741 local r,g,b = 0.749,1,0.749
742 zonename = zone
743 if zone == UnitClass("player") then
744 r, g, b = babbleclass:GetColor(zone)
745 else
746 if self:IsShowingLevelsZone() and tourist:IsZoneOrInstance(zone) then
747 local high, low = tourist:GetLevel(zone)
748 if high > 0 and low > 0 then
749 zonename = string.format("%s (%d-%d)", zone, high, low)
750 end
751 end
752 if self:IsShowingDifficulty() and tourist:IsZoneOrInstance(zone) then
753 r, g, b = tourist:GetLevelColor(zone)
754 end
755 end
756 cat = tablet:AddCategory(
757 'id', zone,
758 'text', zonename,
759 'columns', 2,
760 'hideBlankLine', true,
761 'showWithoutChildren', true,
762 'checked', true, 'hasCheck', true, 'checkIcon', self.db.char.hidden[zone] and "Interface\\Buttons\\UI-PlusButton-Up" or "Interface\\Buttons\\UI-MinusButton-Up",
763 'func', 'ToggleCategory', 'arg1', self, 'arg2', zone,
764 'textR', r,
765 'textG', g,
766 'textB', b,
767 'child_func', 'QuestClick',
768 'child_arg1', self
769 )
770 end
771 -- If we're not hiding the zone and it's either the current zone or we're not showing only the current zone.
772 if (not self.db.char.hidden[zone]) and ((not self:IsShowingCurrentAreaOnly()) or (currentZone == zone) or (self:IsShowingClassAnyway() and UnitClass("player") == zone)) and (table.getn(self.zone_quests[zone]) > 0) then
773 local questid
774 for _,questid in self.zone_quests[zone] do
775 self:AddQuestToTooltip(cat, self.quests[questid], false)
776 end
777 end
778 end
779 end
780 end
781 end
782 tablet:SetHint(L["TOOLTIP_HINT"])
783 end
784  
785 function QuestsFu:MembersOnQuest(questid)
786 --Return the number of party members on a quest. Returns zero if not in a party.
787 local n = 0
788 local party = GetNumPartyMembers()
789 if party > 0 then
790 for i = 1,party do
791 n = n + (IsUnitOnQuest(questid, "party"..i) and 1 or 0)
792 end
793 end
794 return n
795 end
796  
797 function QuestsFu:AddQuestToTooltip(cat, quest, appendZone)
798 --Are we hiding impossible quests, and is this quest impossible?
799 local questImpossible = (GetDifficultyColor(quest.level) == QuestDifficultyColor.impossible)
800 if not questImpossible or (questImpossible and self:IsShowingImpossible()) then
801 local thisQuest, thisQuestColor
802 local questLevel, questZone = "",""
803 local currentZone = GetZoneText()
804  
805 local questShared = QuestsFu:MembersOnQuest(quest.id)
806  
807 if questShared == 0 then
808 questShared = ""
809 end
810  
811 if appendZone then
812 questZone = format(" (%s)", quest.zone)
813 end
814  
815 if self:IsShowingLevelsTablet() and not self:IsShowingLevelsGame() then
816 questLevel = self:MakeTag(quest.level, quest.tag)
817 end
818  
819 thisQuest = questLevel..quest.title..questZone..((questShared ~= "") and "|c0000ff00<"..questShared..">|r" or '')
820  
821 if self:IsShowingDifficulty() then
822 thisQuestColor = GetDifficultyColor(quest.level)
823 end
824  
825 cat:AddLine(
826 'text', thisQuest, 'wrap', self:IsWrappingQuests(),
827 'text2', quest.complete,
828 'textR', (thisQuestColor and thisQuestColor.r) or 1, 'textG', (thisQuestColor and thisQuestColor.g) or 1, 'textB', (thisQuestColor and thisQuestColor.b) or 1,
829 'text2R', (quest.complete == L["QUEST_FAILED"]) and 1 or 0, 'text2G', (quest.complete == L["QUEST_DONE"]) and 1 or 0, 'text2B', 0,
830 'func', 'QuestClick',
831 'arg1', self,
832 'arg2', quest.id,
833 'indentation', 6,
834 'checked', IsQuestWatched(quest.id),
835 'hasCheck', IsQuestWatched(quest.id)
836 )
837  
838 -- If we're showing descriptions/objectives and it's either the current zone or we're not showing descriptions only for the current zone.
839 if self:IsShowingDescription() and ((currentZone == quest.zone) or not self:IsShowingCurrentAreaDescriptionOnly()) then
840 -- If we know of leaderboard objectives:
841 if table.getn(quest.leaderboard) > 0 then
842 local i, goal
843 for i,goal in quest.leaderboard do
844 if not (goal.done == L["QUEST_DONE"] and not self:IsShowingCompletedObjectives()) then
845 local r,g,b
846 if self:IsColoringObjectives() then
847 r,g,b = goal.colorr, goal.colorg, goal.colorb
848 end
849 cat:AddLine(
850 'text', ' '..goal.description,
851 'text2', goal.done,
852 'textR', r or ((thisQuestColor and thisQuestColor.r) or 1), 'textG', g or ((thisQuestColor and thisQuestColor.g) or 1), 'textB', b or ((thisQuestColor and thisQuestColor.b) or 1),
853 'text2R', r or ((thisQuestColor and thisQuestColor.r) or 1), 'text2G', g or ((thisQuestColor and thisQuestColor.g) or 1), 'text2B', b or ((thisQuestColor and thisQuestColor.b) or 1),
854 'size', tablet:GetNormalFontSize()-2, 'size2', tablet:GetNormalFontSize()-2,
855 'arg2', quest.id,
856 'indentation', 12
857 )
858 end
859 end
860 -- Otherwise, if the quest is incomplete (or complete and we're showing completed objectives), add the generic objective.
861 elseif not (quest.complete and not self:IsShowingCompletedObjectives()) then
862 cat:AddLine(
863 'text', quest.objective,
864 'wrap', true,
865 'textR', (thisQuestColor and thisQuestColor.r) or 1,
866 'textG', (thisQuestColor and thisQuestColor.g) or 1,
867 'textB', (thisQuestColor and thisQuestColor.b) or 1,
868 'size', tablet:GetNormalFontSize()-2,
869 'arg2', quest.id,
870 'indentation', 12
871 )
872 end
873 end
874 end
875 end
876  
877 function QuestsFu:ToggleCategory(id, button)
878 if self.db.char.hidden[id] then
879 self.db.char.hidden[id] = false
880 else
881 self.db.char.hidden[id] = true
882 end
883 -- Refresh in place
884 self:UpdateTooltip()
885 end
886  
887 --TheFly contributed the base of this, and it's still using much of the logic he provided
888 function QuestsFu:QuestClick(questid, button)
889 if IsAltKeyDown() then
890 -- Shift-click toggles quest-watch on this quest.
891 if IsQuestWatched(questid) then
892 RemoveQuestWatch(questid)
893 QuestWatch_Update()
894 else
895 -- Set error if no objectives
896 if GetNumQuestLeaderBoards(questid) == 0 then
897 UIErrorsFrame:AddMessage(QUEST_WATCH_NO_OBJECTIVES, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
898 return
899 end
900 -- Set an error message if trying to show too many quests
901 if GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS then
902 UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
903 return
904 end
905 AddQuestWatch(questid)
906 QuestWatch_Update()
907 end
908 elseif IsShiftKeyDown() and IsControlKeyDown() and ChatFrameEditBox:IsVisible() then
909 -- Add the quest objectives to the chat editbox, if it's open.
910 for i,goal in pairs(self.quests[questid].leaderboard) do
911 ChatFrameEditBox:Insert(string.format("{%s %s} ", goal.description, goal.done))
912 end
913 elseif IsShiftKeyDown() and ChatFrameEditBox:IsVisible() then
914 -- Add quest title to the chat editbox if it's open.
915 ChatFrameEditBox:Insert(self.quests[questid].title)
916 elseif IsControlKeyDown() then
917 -- Share the quest with party members.
918 local wasSelected = GetQuestLogSelection()
919 SelectQuestLogEntry(questid)
920 if (GetQuestLogPushable() and GetNumPartyMembers() > 0) then
921 QuestLogPushQuest()
922 end
923 SelectQuestLogEntry(questid)
924 else
925 if QuestLogFrame:IsVisible() then
926 if self.lastIndex == questid then
927 HideUIPanel(QuestLogFrame)
928 end
929 else
930 ShowUIPanel(QuestLogFrame)
931 end
932 if (self.numEntries > QUESTS_DISPLAYED) then
933 if (questid < self.numEntries - QUESTS_DISPLAYED) then
934 FauxScrollFrame_SetOffset(QuestLogListScrollFrame, questid - 1)
935 QuestLogListScrollFrameScrollBar:SetValue((questid - 1) * QUESTLOG_QUEST_HEIGHT)
936 else
937 FauxScrollFrame_SetOffset(QuestLogListScrollFrame, self.numEntries - QUESTS_DISPLAYED)
938 QuestLogListScrollFrameScrollBar:SetValue((self.numEntries - QUESTS_DISPLAYED) * QUESTLOG_QUEST_HEIGHT)
939 end
940 end
941  
942 SelectQuestLogEntry(questid)
943 QuestLog_SetSelection(questid)
944 self.lastIndex = questid
945 end
946 end
947  
948 function QuestsFu:OnClick()
949 ToggleQuestLog()
950 end
951  
952 function QuestsFu:GetReactionLevel(leveltext)
953 if leveltext == FACTION_STANDING_LABEL1 then --Hated
954 return 1
955 elseif leveltext == FACTION_STANDING_LABEL2 then --Hostile
956 return 2
957 elseif leveltext == FACTION_STANDING_LABEL3 then --Unfriendly
958 return 3
959 elseif leveltext == FACTION_STANDING_LABEL4 then --Neutral
960 return 4
961 elseif leveltext == FACTION_STANDING_LABEL5 then --Friendly
962 return 5
963 elseif leveltext == FACTION_STANDING_LABEL6 then --Honored
964 return 6
965 elseif leveltext == FACTION_STANDING_LABEL7 then --Revered
966 return 7
967 elseif leveltext == FACTION_STANDING_LABEL8 then --Exalted
968 return 8
969 end
970 end
971  
972 function QuestsFu:LoadWatchedQuests()
973 if not (GetNumQuestWatches() > 0) then
974 for _,questId in self.db.char.watchedQuests do
975 AddQuestWatch(questId)
976 end
977 end
978 QuestWatch_Update()
979  
980 self.loadedWatchedQuests = true
981 end
982  
983 function QuestsFu:SaveWatchedQuests()
984 if self.loadedWatchedQuests then
985 self.db.char.watchedQuests = compost:Erase(self.db.char.watchedQuests)
986 for i = 1, GetNumQuestWatches() do
987 table.insert(self.db.char.watchedQuests, GetQuestIndexForWatch(i))
988 end
989 end
990 end
991  
992 -- Sorts a table of quests by level, with quests of the same level ordered
993 -- by elite, dungeon or raid tags, i.e. normal < elite < dungeon < raid.
994 -- Quests of the same level and tag are sorted alphabetically by title.
995 -- Returns a new table of the sorted quests. Original table is unchanged.
996 function QuestsFu:SortQuests(quests)
997 -- Make a copy of the table, without keys
998 local sortedQuests = compost:Acquire()
999 table.foreach(self.quests,
1000 function(k,v)
1001 table.insert(sortedQuests, v)
1002 end
1003 )
1004  
1005 table.sort(sortedQuests,
1006 function(a,b)
1007 local aa = a.level*4
1008 local bb = b.level*4
1009 if a.tag == L["TAG_ELITE"] then aa = aa+1 end
1010 if a.tag == L["TAG_DUNGEON"] then aa = aa+2 end
1011 if a.tag == L["TAG_RAID"] then aa = aa+3 end
1012 if b.tag == L["TAG_ELITE"] then bb = bb+1 end
1013 if b.tag == L["TAG_DUNGEON"] then bb = bb+2 end
1014 if b.tag == L["TAG_RAID"] then bb = bb+3 end
1015 if aa == bb then
1016 return a.title < b.title
1017 end
1018 return aa < bb;
1019 end
1020 )
1021  
1022 return sortedQuests
1023 end