Merge branch 'master' of git://cams.pavlovian.net/questhelper
[QuestHelper.git] / help.lua
blob4945bf3cc7d02fdf003dae23da2eae69a60461cc
1 QuestHelper_File["help.lua"] = "Development Version"
2 QuestHelper_Loadtime["help.lua"] = GetTime()
4 local QuestHelper_Version = QuestHelper_File["help.lua"]
6 function QuestHelper:scaleString(val)
7 return self:HighlightText(math.floor(val*100+0.5).."%")
8 end
10 function QuestHelper:genericSetScale(varname, name, mn, mx, input, onchange, ...)
11 if input == "" then
12 self:TextOut(string.format("Current %s scale is %s.", name, self:scaleString(QuestHelper_Pref[varname])))
13 else
14 local scale = tonumber(input)
16 if not scale then
17 local x = string.match(input or "", "^%s*([%d%.]+)%s*%%%s*$")
18 scale = tonumber(x) or 0
19 if not scale then
20 self:TextOut("I don't know how to interpret your input.")
21 return
22 end
23 scale = scale * 0.01
24 end
26 if scale < mn then
27 self:TextOut(string.format("I won't accept a scale less than %s.", self:scaleString(mn)))
28 elseif scale > mx then
29 self:TextOut(string.format("I won't accept a scale more than %s.", self:scaleString(mx)))
30 else
31 QuestHelper_Pref[varname] = scale
32 self:TextOut(string.format("Set %s scale set to %s.", name, self:scaleString(scale)))
33 if onchange then
34 onchange(...)
35 end
36 end
37 end
38 end
40 function QuestHelper:TrackerScale(scale)
41 QuestHelper:genericSetScale("track_scale", "tracker scale", .5, 2, scale,
42 function() QuestHelper.tracker:SetScale(QuestHelper_Pref.track_scale) end)
43 end
45 function QuestHelper:SetLocale(loc)
46 if not loc or loc == "" then
47 self:TextOut(QHText("LOCALE_LIST_BEGIN"))
48 for loc, tbl in pairs(QuestHelper_Translations) do
49 self:TextOut(string.format(" %s%s %s", self:HighlightText(loc),
50 loc == QuestHelper_Pref.locale and " *" or " ",
51 tbl.LOCALE_NAME or "???"))
52 end
53 else
54 for l, tbl in pairs(QuestHelper_Translations) do
55 if string.find(string.lower(l), "^"..string.lower(loc)) or
56 string.find(string.lower(tbl.LOCALE_NAME or ""), "^"..string.lower(loc)) then
57 QuestHelper_Pref.locale = l
58 QHFormatSetLocale(l)
59 self:SetLocaleFonts()
60 self:TextOut(QHFormat("LOCALE_CHANGED", l))
61 return
62 end
63 end
65 self:TextOut(QHFormat("LOCALE_UNKNOWN", tostring(loc) or "UNKNOWN"))
66 end
67 end
69 function QuestHelper:ToggleMetric()
70 QuestHelper_Pref.metric = not QuestHelper_Pref.metric
72 if QuestHelper_Pref.metric then
73 self:TextOut("Distances are now in metres.")
74 else
75 self:TextOut("Distances are now in yards.")
76 end
77 end
79 function QuestHelper:ToggleHide()
80 QuestHelper_Pref.hide = not QuestHelper_Pref.hide
82 -- Desaturate the button texture if QuestHelper is disabled.
83 if self.MapButton then
84 -- This should always be true, but just in case...
85 self.MapButton:GetNormalTexture():SetDesaturated(QuestHelper_Pref.hide)
86 end
88 if QuestHelper_Pref.hide then
89 if QuestHelper_Pref.track then
90 self:HideTracker()
91 end
93 self.map_overlay:Hide()
94 self:TextOut("QuestHelper is now |cffff0000hidden|r.")
95 else
96 if QuestHelper_Pref.track then
97 self:ShowTracker()
98 end
100 self.map_overlay:Show()
101 self.minimap_marker:Show()
102 self:TextOut("QuestHelper is now |cff00ff00shown|r.")
104 QH_Timeslice_Bonus(20) -- Let the corutine do some overtime...
108 function QuestHelper:ToggleShare()
109 QuestHelper_Pref.share = not QuestHelper_Pref.share
110 if QuestHelper_Pref.share then
111 if QuestHelper_Pref.solo then
112 self:TextOut("Objective sharing will been |cff00ff00enabled|r when you disable solo mode.")
113 else
114 self:TextOut("Objective sharing has been |cff00ff00enabled|r.")
115 self:SetShare(true)
117 else
118 self:TextOut("Objective sharing has been |cffff0000disabled|r.")
119 if QuestHelper_Pref.solo then
120 self:TextOut("Objective sharing won't be reenabled when you disable solo mode.")
121 else
122 self:SetShare(false)
127 function QuestHelper:ToggleFlightTimes()
128 QuestHelper_Pref.flight_time = not QuestHelper_Pref.flight_time
129 if QuestHelper_Pref.flight_time then
130 self:TextOut("The flight timer has been |cff00ff00enabled|r.")
131 else
132 self:TextOut("The flight timer has been |cffff0000disabled|r.")
136 function QuestHelper:ToggleTravelTimes()
137 QuestHelper_Pref.travel_time = not QuestHelper_Pref.travel_time
138 if QuestHelper_Pref.travel_time then
139 self:TextOut("The travel timer has been |cff00ff00enabled|r.")
140 else
141 self:TextOut("The travel timer has been |cffff0000disabled|r.")
145 function QuestHelper:ToggleTrack()
146 QuestHelper_Pref.track = not QuestHelper_Pref.track
147 if QuestHelper_Pref.track then
148 self:ShowTracker()
149 self:TextOut("The quest tracker has been |cff00ff00enabled|r.")
150 else
151 self:HideTracker()
152 self:TextOut("The quest tracker has been |cffff0000disabled|r.")
156 function QuestHelper:ToggleBlizzMap()
157 QuestHelper_Pref.blizzmap = not QuestHelper_Pref.blizzmap
158 if QuestHelper_Pref.blizzmap then
159 self:TextOut("The Blizzard quest points have been |cff00ff00enabled|r.")
160 else
161 self:TextOut("The Blizzard quest points have been |cffff0000disabled|r.")
164 if UpdateQuestMapPOI then UpdateQuestMapPOI() end
167 if UpdateQuestMapPOI then
168 local uqmp_def = UpdateQuestMapPOI
169 function UpdateQuestMapPOI(...)
170 if QuestHelper_Pref.blizzmap then
171 return uqmp_def(...)
172 else
173 for i = 1, #QUEST_MAP_POI do
174 QUEST_MAP_POI[i]:Hide()
180 function QuestHelper:ToggleTrackLevel()
181 QuestHelper_Pref.track_level = not QuestHelper_Pref.track_level
182 if QuestHelper_Pref.track_level then
183 self:TextOut("Display of levels in the quest tracker has been |cff00ff00enabled|r.")
184 else
185 self:TextOut("Display of levels in the quest tracker has been |cffff0000disabled|r.")
187 QH_UpdateQuests(true)
188 QH_Tracker_Rescan()
191 function QuestHelper:ToggleTrackQColour()
192 QuestHelper_Pref.track_qcolour = not QuestHelper_Pref.track_qcolour
193 if QuestHelper_Pref.track_qcolour then
194 self:TextOut("Colour for quest difficulty in quest tracker has been |cff00ff00enabled|r.")
195 else
196 self:TextOut("Colour for quest difficulty in quest tracker has been |cffff0000disabled|r.")
198 QH_UpdateQuests(true)
199 QH_Tracker_Rescan()
202 function QuestHelper:ToggleTrackOColour()
203 QuestHelper_Pref.track_ocolour = not QuestHelper_Pref.track_ocolour
204 if QuestHelper_Pref.track_ocolour then
205 self:TextOut("Colour for objective progress in quest tracker has been |cff00ff00enabled|r.")
206 else
207 self:TextOut("Colour for objective progress in quest tracker has been |cffff0000disabled|r.")
209 QH_UpdateQuests(true)
210 QH_Tracker_Rescan()
213 function QuestHelper:ToggleTooltip()
214 QuestHelper_Pref.tooltip = not QuestHelper_Pref.tooltip
215 if QuestHelper_Pref.tooltip then
216 self:TextOut("Objective tooltip information has been |cff00ff00enabled|r.")
217 else
218 self:TextOut("Objective tooltip information has been |cffff0000disabled|r.")
222 function QuestHelper:Purgewarning()
223 QuestHelper:TextOut("I would consider this a tragic loss, and would appreciate it if you sent me your saved data before going through with it.")
224 QuestHelper:TextOut("Enter "..self:HighlightText("/qh nag verbose").." to check and see if you're destroying anything important.")
225 QuestHelper:TextOut("Enter "..self:HighlightText("/qh submit").." for instructions on how to submit your collected data.")
226 QuestHelper:TextOut("See the "..self:HighlightText("How You Can Help").." section on the project website for instructions.")
229 function QuestHelper:Purge(code, force, noreload)
230 if code == self.purge_code or force then
231 QuestHelper_Quests = nil
232 QuestHelper_Objectives = nil
233 QuestHelper_FlightInstructors = nil
234 QuestHelper_FlightRoutes = nil
235 QuestHelper_Locale = nil
236 QuestHelper_UID = nil
237 QuestHelper_Version = nil
238 QuestHelper_SaveVersion = nil
240 QuestHelper_SaveDate = nil
241 QuestHelper_SeenRealms = nil
243 QuestHelper_Collector = nil
244 QuestHelper_Collector_Version = nil
246 if not noreload then ReloadUI() end
247 else
248 if not self.purge_code then self.purge_code = self:CreateUID(8) end
249 QuestHelper:TextOut("THIS COMMAND WILL DELETE ALL YOUR COLLECTED DATA")
250 QuestHelper:Purgewarning()
251 QuestHelper:TextOut("If you're sure you want to go through with this, enter: "..self:HighlightText("/qh purge "..self.purge_code))
255 function QuestHelper:HardReset(code)
256 if code == self.purge_code then
257 self:ResetTrackerPosition() -- do this before we kill off the prefs, since it touches a pref
258 QH_Arrow_Reset()
259 QuestHelper_Pref = nil
260 QuestHelper_ErrorList = nil -- BIZAM
261 QuestHelper_KnownFlightRoutes = nil
262 QuestHelper_Home = nil
263 QuestHelper_CharVersion = nil
264 self:Purge(nil, true)
265 else
266 if not self.purge_code then self.purge_code = self:CreateUID(8) end
267 QuestHelper:TextOut("THIS COMMAND WILL DELETE ALL YOUR COLLECTED DATA AND RESET ALL YOUR PREFERENCES")
268 QuestHelper:Purgewarning()
269 QuestHelper:TextOut("If you're sure you want to go through with this, enter: "..self:HighlightText("/qh hardreset "..self.purge_code))
273 function QuestHelper:ToggleSolo()
274 QuestHelper_Pref.solo = not QuestHelper_Pref.solo
275 if QuestHelper_Pref.solo then
276 if QuestHelper_Pref.share then
277 self:SetShare(false)
278 self:TextOut("Objective sharing has been temporarly |cffff0000disabled|r.")
280 self:TextOut("Solo mode has been |cff00ff00enabled|r.")
281 else
282 self:TextOut("Solo mode has been |cffff0000disabled|r.")
283 if QuestHelper_Pref.share then
284 self:SetShare(true)
285 self:TextOut("Objective sharing has been re|cff00ff00enabled|r.")
290 function QuestHelper:ToggleAnts()
291 if QuestHelper_Pref.show_ants then
292 QuestHelper_Pref.show_ants = false
293 self:TextOut("Ant trails have been |cffff0000disabled|r.")
294 else
295 QuestHelper_Pref.show_ants = true
296 self:TextOut("Ant trails have been |cff00ff00enabled|r.")
300 function QuestHelper:SetZones()
301 if QuestHelper_Pref.zones == "next" then
302 QuestHelper_Pref.zones = "none"
303 self:TextOut("Next zone display has been |cffff0000disabled|r.")
304 else
305 QuestHelper_Pref.zones = "next"
306 self:TextOut("Next zone display has been |cff00ff00enabled|r.")
310 function QuestHelper:LevelOffset(offset)
311 local level = tonumber(offset)
312 if level then
313 if level > 0 then
314 self:TextOut("Allowing quests up to "..self:HighlightText(level).." level"..(level==1 and " " or "s ")..self:HighlightText("above").." you.")
315 elseif level < 0 then
316 self:TextOut("Only allowing quests "..self:HighlightText(-level).." level"..(level==-1 and " " or "s ")..self:HighlightText("below").." you.")
317 else
318 self:TextOut("Only allowing quests "..self:HighlightText("at or below").." your current level.")
321 if not QuestHelper_Pref.filter_level then
322 self:TextOut("Note: This won't have any effect until you turn the level filter on.")
325 if QuestHelper_Pref.level ~= level then
326 QuestHelper_Pref.level = level
327 QH_Route_Filter_Rescan("filter_quest_level")
329 elseif offset == "" then
330 if QuestHelper_Pref.level <= 0 then
331 self:TextOut("Level offset is currently set to "..self:HighlightText(QuestHelper_Pref.level)..".")
332 else
333 self:TextOut("Level offset is currently set to "..self:HighlightText("+"..QuestHelper_Pref.level)..".")
336 if self.party_levels then for n, l in ipairs(self.party_levels) do
337 self:TextOut("Your effective level in a "..self:HighlightText(n).." player quest is "..self:HighlightText(string.format("%.1f", l))..".")
338 end end
340 if QuestHelper_Pref.solo then
341 self:TextOut("Peers aren't considered in your effective level, because you're playing solo.")
343 else
344 self:TextOut("Expected a level offset.")
348 function QuestHelper:GroupOffset(offset)
349 local group = tonumber(offset)
350 if offset == "instance" then group = 5 end
351 if offset == "raid" then group = 10 end
352 if group == 0 then group = 1 end
353 if group then
354 self:TextOut("Allowing quests requiring at most "..self:HighlightText(group).." player"..(group==1 and " " or "s ")..".")
356 if not QuestHelper_Pref.filter_group then
357 self:TextOut("Note: This won't have any effect until you turn the group filter on.")
360 QuestHelper_Pref.filter_group_param = group
361 QH_Route_Filter_Rescan("filter_quest_level")
362 elseif offset == "" then
363 self:TextOut("Group cutoff is currently set to "..self:HighlightText(QuestHelper_Pref.filter_group_param)..".")
364 else
365 self:TextOut("Expected a player count.")
369 function QuestHelper:Filter(input)
370 input = string.upper(input)
371 if input == "ZONE" then
372 QuestHelper_Pref.filter_zone = not QuestHelper_Pref.filter_zone
373 self:TextOut("Filter "..self:HighlightText("zone").." set to "..self:HighlightText(QuestHelper_Pref.filter_zone and "active" or "inactive")..".")
374 QH_Route_Filter_Rescan("filter_zone")
375 elseif input == "DONE" then
376 QuestHelper_Pref.filter_done = not QuestHelper_Pref.filter_done
377 self:TextOut("Filter "..self:HighlightText("done").." set to "..self:HighlightText(QuestHelper_Pref.filter_done and "active" or "inactive")..".")
378 QH_Route_Filter_Rescan("filter_quest_done")
379 elseif input == "LEVEL" then
380 QuestHelper_Pref.filter_level = not QuestHelper_Pref.filter_level
381 self:TextOut("Filter "..self:HighlightText("level").." set to "..self:HighlightText(QuestHelper_Pref.filter_level and "active" or "inactive")..".")
382 QH_Route_Filter_Rescan("filter_quest_level")
383 elseif input == "GROUP" then
384 QuestHelper_Pref.filter_group = not QuestHelper_Pref.filter_group
385 self:TextOut("Filter "..self:HighlightText("group").." set to "..self:HighlightText(QuestHelper_Pref.filter_group and "active" or "inactive")..".")
386 QH_Route_Filter_Rescan("filter_quest_group")
387 elseif input == "BLOCKED" or input == "BLOCK" then
388 QuestHelper_Pref.filter_blocked = not QuestHelper_Pref.filter_blocked
389 self:TextOut("Filter "..self:HighlightText("blocked").." set to "..self:HighlightText(QuestHelper_Pref.filter_blocked and "active" or "inactive")..".")
390 QH_Route_Filter_Rescan("filter_blocked")
391 elseif input == "WATCHED" or input == "WATCH" then
392 QuestHelper_Pref.filter_watched = not QuestHelper_Pref.filter_watched
393 self:TextOut("Filter "..self:HighlightText("watched").." set to "..self:HighlightText(QuestHelper_Pref.filter_watched and "active" or "inactive")..".")
394 QH_Route_Filter_Rescan("filter_quest_watched")
395 elseif input == "WINTERGRASP" or input == "WG" then
396 QuestHelper_Pref.filter_wintergrasp = not QuestHelper_Pref.filter_wintergrasp
397 self:TextOut("Filter "..self:HighlightText("wintergrasp").." set to "..self:HighlightText(QuestHelper_Pref.filter_wintergrasp and "active" or "inactive")..".")
398 QH_Route_Filter_Rescan("filter_quest_wintergrasp")
399 elseif input == "" then
400 self:TextOut("Filter "..self:HighlightText("zone")..": "..self:HighlightText(QuestHelper_Pref.filter_zone and "active" or "inactive"))
401 self:TextOut("Filter "..self:HighlightText("level")..": "..self:HighlightText(QuestHelper_Pref.filter_level and "active" or "inactive"))
402 self:TextOut("Filter "..self:HighlightText("group")..": "..self:HighlightText(QuestHelper_Pref.filter_group and "active" or "inactive"))
403 self:TextOut("Filter "..self:HighlightText("done")..": "..self:HighlightText(QuestHelper_Pref.filter_done and "active" or "inactive"))
404 self:TextOut("Filter "..self:HighlightText("blocked")..": "..self:HighlightText(QuestHelper_Pref.filter_blocked and "active" or "inactive"))
405 self:TextOut("Filter "..self:HighlightText("watched")..": "..self:HighlightText(QuestHelper_Pref.filter_watched and "active" or "inactive"))
406 self:TextOut("Filter "..self:HighlightText("wintergrasp")..": "..self:HighlightText(QuestHelper_Pref.filter_wintergrasp and "active" or "inactive"))
407 else
408 self:TextOut("Don't know what you want filtered, expect "..self:HighlightText("zone")..", "..self:HighlightText("done")..", "..self:HighlightText("level")..", "..self:HighlightText("group")..", "..self:HighlightText("blocked")..", "..self:HighlightText("watched")..", or "..self:HighlightText("wintergrasp")..".")
412 function QuestHelper:ToggleArrow(text)
413 if text == "reset" then QH_Arrow_Reset() return end
415 QuestHelper_Pref.arrow = not QuestHelper_Pref.arrow
416 if QuestHelper_Pref.arrow then
417 QH_Arrow_Show()
418 self:TextOut(QHFormat("SETTINGS_ARROWLINK_ON", QHText("SETTINGS_ARROWLINK_ARROW")))
419 else
420 self:TextOut(QHFormat("SETTINGS_ARROWLINK_OFF", QHText("SETTINGS_ARROWLINK_ARROW")))
424 function QuestHelper:ToggleCartWP()
425 QuestHelper_Pref.cart_wp_new = not QuestHelper_Pref.cart_wp_new
426 if QuestHelper_Pref.cart_wp_new then
427 self:EnableCartographer()
428 if Cartographer_Waypoints then
429 if Waypoint and Waypoint.prototype then
430 self:TextOut("Would use "..self:HighlightText("Cartographer Waypoints").." to show objectives, but another mod is interfering with it.")
431 else
432 self:TextOut(QHFormat("SETTINGS_ARROWLINK_ON", QHText("SETTINGS_ARROWLINK_CART")))
434 else
435 self:TextOut("Would use "..self:HighlightText("Cartographer Waypoints").." to show objectives, except it doesn't seem to be present.")
437 else
438 self:DisableCartographer()
439 self:TextOut(QHFormat("SETTINGS_ARROWLINK_OFF", QHText("SETTINGS_ARROWLINK_CART")))
443 function QuestHelper:ToggleTomTomWP()
444 QuestHelper_Pref.tomtom_wp_new = not QuestHelper_Pref.tomtom_wp_new
445 if QuestHelper_Pref.tomtom_wp_new then
446 self:EnableTomTom()
447 if TomTom then
448 self:TextOut(QHFormat("SETTINGS_ARROWLINK_ON", QHText("SETTINGS_ARROWLINK_TOMTOM")))
449 else
450 self:TextOut("Would use "..self:HighlightText("TomTom").." to show objectives, except it doesn't seem to be present.")
452 else
453 self:DisableTomTom()
454 self:TextOut(QHFormat("SETTINGS_ARROWLINK_OFF", QHText("SETTINGS_ARROWLINK_TOMTOM")))
458 function QuestHelper:PrintVersion()
459 self:TextOut("Version: "..self:HighlightText(GetAddOnMetadata("QuestHelper", "Version") or "Unknown"))
462 local function RecycleStatusString(fmt, usedcount, freetable, usedtable)
463 local freetablecount = QuestHelper:TableSize(freetable)
464 if usedtable then
465 local usedtablecount = QuestHelper:TableSize(usedtable)
466 return string.format(fmt, QuestHelper:ProgressString(string.format("%d/%d", usedtablecount, usedtablecount+freetablecount), ((usedtablecount+freetablecount == 0) and 1) or (1-usedtablecount/(usedtablecount+freetablecount)))) .. string.format(" (%d \"leaked\")", usedcount - usedtablecount)
467 else
468 return string.format(fmt, QuestHelper:ProgressString(string.format("%d/%d", usedcount, usedcount+freetablecount), ((usedcount+freetablecount == 0) and 1) or (1-usedcount/(usedcount+freetablecount))))
472 function QuestHelper:Top(cmd)
473 if cmd and string.find(cmd, "all") then
474 cmd = cmd .. " collected recycle clear boot usage"
477 if cmd and string.find(cmd, "boot") then
478 local bootv = {}
479 for k, v in pairs(QuestHelper_Loadtime) do
480 table.insert(bootv, {time = v, file = k})
482 table.sort(bootv, function (a, b) return a.time < b.time end)
484 if string.find(cmd, "sort") then
485 local boott = {}
486 for i = 1, #bootv - 1 do
487 table.insert(boott, {time = bootv[i + 1].time - bootv[i].time, file = bootv[i].file})
489 table.sort(boott, function(a, b) return a.time < b.time end)
491 for _, v in pairs(boott) do
492 QuestHelper:TextOut(string.format("%s: %f", v.file, v.time))
494 QuestHelper:TextOut(string.format("%s: shrug", bootv[#bootv].file))
495 else
496 for i = 1, #bootv do
497 QuestHelper:TextOut(string.format("%f: %s", bootv[i].time - bootv[1].time, bootv[i].file))
502 local pre_ttf
503 local pre_db
504 if cmd and string.find(cmd, "collected") then
505 pre_ttf = self:DumpTableTypeFrequencies(true)
506 pre_db = DB_DumpItems()
509 if cmd and string.find(cmd, "recycle") then
510 self:DumpTableTypeFrequencies()
511 self:TextOut(RecycleStatusString("Using %s lua tables.", self.used_tables, self.free_tables, self.recycle_tabletyping))
512 self:TextOut(RecycleStatusString("Using %s texture objects.", self.used_textures, self.free_textures))
513 self:TextOut(RecycleStatusString("Using %s font objects.", self.used_text, self.free_text))
514 self:TextOut(RecycleStatusString("Using %s frame objects.", self.used_frames, self.free_frames))
517 if cmd and string.find(cmd, "usage") then
518 self:DumpTableTypeFrequencies()
521 if cmd and string.find(cmd, "cache") then
522 self:DumpCacheData()
525 if cmd and string.find(cmd, "perf") then
526 QH_Timeslice_DumpPerf()
529 local uncd = 0
530 for k, v in pairs(QuestHelper_Collector) do
531 if not v.compressed then uncd = uncd + 1 end
533 uncd = uncd - 1
534 local uncs = ""
535 if uncd > 0 then
536 uncs = string.format(" (%d uncompressed IDs)", uncd)
539 UpdateAddOnMemoryUsage()
540 local pre_gc = GetAddOnMemoryUsage("QuestHelper")
542 collectgarbage("collect")
544 UpdateAddOnMemoryUsage()
545 local post_gc = GetAddOnMemoryUsage("QuestHelper")
547 if cmd and string.find(cmd, "collected") then
548 local post_ttf = self:DumpTableTypeFrequencies(true)
550 local union = {}
551 for k, v in pairs(pre_ttf) do union[k] = (pre_ttf[k] or 0) - (post_ttf[k] or 0) end
552 for k, v in pairs(post_ttf) do union[k] = (pre_ttf[k] or 0) - (post_ttf[k] or 0) end
554 local sorted = {}
555 for k, v in pairs(union) do
556 table.insert(sorted, {k = k, d = v})
559 table.sort(sorted, function(a, b) return a.d < b.d end)
560 for _, v in pairs(sorted) do
561 if v.d > 0 then
562 QuestHelper:TextOut(string.format("%d: %s", v.d, v.k))
566 local post_db = DB_DumpItems()
568 local st = {}
569 for k, v in pairs(pre_db) do
570 if not post_db[k] then
571 table.insert(st, k)
574 table.sort(st)
576 for _, v in ipairs(st) do
577 QuestHelper:TextOut("DB: " .. v)
581 self:TextOut(string.format("QuestHelper is using %dkb (pre-collect %dkb) of RAM (%s/%s/%s/%s)%s", post_gc, pre_gc, QuestHelper_local_version, QuestHelper_toc_version, GetBuildInfo(), GetLocale(), uncs))
583 if cmd and string.find(cmd, "clear") then
584 local cleared = QH_ClearPathcache()
586 collectgarbage("collect")
587 UpdateAddOnMemoryUsage()
588 local new_post_gc = GetAddOnMemoryUsage("QuestHelper")
589 self:TextOut(string.format("QuestHelper is using %dkb/%dkb/%dkb (%d pathcache cleared) of RAM (%s/%s/%s/%s)%s", pre_gc, post_gc, new_post_gc, cleared, QuestHelper_local_version, QuestHelper_toc_version, GetBuildInfo(), GetLocale(), uncs))
591 local cleared = QuestHelper:RecycleClear()
593 collectgarbage("collect")
594 UpdateAddOnMemoryUsage()
595 local new_post_gc_2 = GetAddOnMemoryUsage("QuestHelper")
596 self:TextOut(string.format("QuestHelper is using %dkb/%dkb/%dkb/%dkb (%d recycle cleared) of RAM (%s/%s/%s/%s)%s", pre_gc, post_gc, new_post_gc, new_post_gc_2, cleared, QuestHelper_local_version, QuestHelper_toc_version, GetBuildInfo(), GetLocale(), uncs))
600 function QuestHelper:ToggleMapButton()
601 QuestHelper_Pref.map_button = not QuestHelper_Pref.map_button
603 if QuestHelper_Pref.map_button then
604 QuestHelper:InitMapButton()
605 self:TextOut("Map button has been |cff00ff00enabled|r.")
606 else
607 QuestHelper:HideMapButton()
608 self:TextOut("Map button has been |cffff0000disabled|r. Use '/qh button' to restore it.")
612 function QuestHelper:ChangeLog()
613 self:ShowText(QuestHelper_ChangeLog, string.format("QuestHelper %s ChangeLog", QuestHelper_Version))
616 function QuestHelper:Submit()
617 self:ShowText([[
618 |TInterface\AddOns\QuestHelper\Art\Upload.tga:100:300|t
619 Your data can't be submitted automatically, since AddOns can't interact with anything outside of World of Warcraft.
621 To do this would require me to create some third party software, and I don't want to include such software with QuestHelper, because that's the kind of thing that ill intended people are likely to tamper with.
623 World of Warcraft stores QuestHelper's data in a file named |cff40bbffQuestHelper.lua|r.
625 To find this file, first find the the directory you installed World of Warcraft to. In Windows, this defaults to |cff40bbffC:\Program Files\World of Warcraft|r, and on Mac, I believe this is |cff40bbff/Applications/World of Warcraft|r.
627 If you're using Windows Vista, Windows might protect the Program Files directory from changes, and redirect Warcraft's saved data to |cff40bbffC:\Users\|cffff8000USER|cff40bbff\AppData\Local\VirtualStore\Program Files\World of Warcraft|r, or possibly |cff40bbffC:\Users\Public\Games\World of Warcraft|r.
629 In that directory, the needed file is in |cff40bbffWTF/Account/|cffff8000ACCOUNT|cff40bbff/SavedVariables|r, replacing ACCOUNT with the name of your account, and in that directory, you should find |cff40bbffQuestHelper.lua|r.
631 There are other directories with the names of the realms where your characters are stored, |cffffff00but don't enter them|r. They contain information specific to your characters, such as the flight points they know about, and don't contain the quest information I want.
633 After you find |cff40bbffQuestHelper.lua|r, you can email it to me here: |cff40bbffqhaddon@gmail.com|r
634 ]], "How To Submit Your Data")
637 function QuestHelper:ShowError(params)
638 if params and params == "full" then
639 QuestHelper_ErrorCatcher_GenerateReport()
641 QuestHelper_ErrorCatcher_ReportError()
644 local commands
646 function QuestHelper:Help(argument)
647 local text = ""
648 local argument = argument and argument:upper() or ""
650 for i1, cat in ipairs(commands) do
651 text = string.format("%s|cffffff00%s|r\n\n", text, cat[1])
652 for i, data in ipairs(cat[2]) do
653 if data[1]:find(argument, 1, true) then
654 text = string.format("%s |cffff8000%s|r %s\n", text, data[1], data[2])
656 if #data[3] > 0 then
657 text = string.format("%s\n %s\n", text, #data[3] == 1 and "Example:" or "Examples:")
658 for i, pair in ipairs(data[3]) do
659 text = string.format("%s |cff40bbff%s|r\n %s\n", text, pair[1], pair[2])
663 text = text .. "\n"
666 text = text .. "\n\n"
669 self:ShowText(text == "" and ("No commands containing '"..argument.."'") or text, "QuestHelper Slash Commands")
672 function QuestHelper:Donate(argument)
673 local text = ""
674 local argument = argument and argument:upper() or ""
676 for i1, cat in ipairs(commands) do
677 text = string.format("%s|cffffff00%s|r\n\n", text, cat[1])
678 for i, data in ipairs(cat[2]) do
679 if data[1]:find(argument, 1, true) then
680 text = string.format("%s |cffff8000%s|r %s\n", text, data[1], data[2])
682 if #data[3] > 0 then
683 text = string.format("%s\n %s\n", text, #data[3] == 1 and "Example:" or "Examples:")
684 for i, pair in ipairs(data[3]) do
685 text = string.format("%s |cff40bbff%s|r\n %s\n", text, pair[1], pair[2])
689 text = text .. "\n"
692 text = text .. "\n\n"
695 self:ShowText([[
696 QuestHelper currently survives on |cffff8000your donations|r. I'm trying to make this into a full-time job so I can add more features and fix bugs, and I can't do that without paying the bills.
698 There's a lot of stuff I plan to add if I can get enough donations to live off. Some of the most-requested features include:
700 |cff40bbffReduced memory and CPU usage for smoother gameplay|r
702 |cff40bbffFlying mount support for both Northrend and Outland|r
704 |cff40bbffBetter support for Northrend "phased" quests|r
706 |cff40bbffAchievementHelper, built right into QuestHelper|r
708 |cff40bbffPaths that lead you around obstacles instead of through them|r
710 I can't guarantee these will show up soon, as there's a lot of work involved in them, but every donation - no matter how small - helps!
712 To donate, open up your web browser and go to |cffff8000http://www.quest-helper.com/donate|r. Enter however much you feel comfortable donating, then bask in the knowledge that you're supporting QuestHelper.
714 Thanks!]], "Please Donate!", 500, 20, 10)
717 commands =
719 { "Common commands", {
720 {"HIDDEN",
721 "Compiles a list of objectives that QuestHelper is hiding from you. Depending on the reason, you can also unhide the objective.",
722 {}, QH_Hidden_Menu},
724 {"HIDE",
725 "Hides QuestHelper's modifications to the minimap and world map, and pauses routing calculations.",
726 {}, QuestHelper.ToggleHide, QuestHelper},
728 {"ARROW",
729 "Toggles Questhelper's built-in directional arrow.",
730 {{"/qh arrow reset", "Reset location to the center of the screen."}},
731 QuestHelper.ToggleArrow, QuestHelper},
733 {"METRIC",
734 "Toggles distance units between metres and yards.",
735 {}, QuestHelper.ToggleMetric, QuestHelper},
737 {"CARTWP",
738 "Toggles displaying the current objective using Cartographer Waypoints (must be installed separately).",
739 {}, QuestHelper.ToggleCartWP, QuestHelper},
741 {"TOMTOM",
742 "Toggles displaying the current objective using TomTom (must be installed separately).",
743 {}, QuestHelper.ToggleTomTomWP, QuestHelper},
745 {"FIND",
746 "Search for an item, location, or npc.",
747 {{"/qh find item rune of teleport", "Finds a reagent vendor."},
748 {"/qh find npc bragok", "Finds the Ratchet flight point."},
749 {"/qh find loc stormwind 50 60", "Finds the Stormwind auction house."},
750 {"/qh find loc 50 50", "Finds the center of the zone you're in."},
751 {"/qh find something", "Searches for something in all categories."},
752 {"/qh find", "Lists objectives you manually created so that you can remove them."}}, QuestHelper.PerformSearch, QuestHelper},
754 {"SOLO",
755 "Toggles solo mode. When enabled, assumes your party members don't exist. Objective sharing with party members will also be disabled.",
756 {}, QuestHelper.ToggleSolo, QuestHelper},
759 { "Objective filtering", {
760 {"FILTER",
761 "Automatically ignores/unignores objectives based on criteria.",
763 {"/qh filter level", "Toggle showing objectives that are probably too hard, by considering the levels of you and your party members, and the offset set by the level command."},
764 {"/qh filter group", "Toggle showing objectives that require groups. Automatically disables while grouped."},
766 {"/qh filter zone", "Toggle showing objectives outside the current zone."},
767 {"/qh filter done", "Toggle showing objectives for uncompleted quests."},
769 {"/qh filter blocked", "Toggle showing blocked objectives, such as quest turn-ins for incomplete quests."},
770 {"/qh filter watched", "Toggle limiting to objectives watched in the Quest Log"},
772 {"/qh filter wintergrasp", "Toggle ignoring of PvP Wintergrasp quest objectives while not in Wintergrasp"},
773 }, QuestHelper.Filter, QuestHelper},
775 {"LEVEL",
776 "Adjusts the level offset used by the level filter. Naturally, the level filter must be turned on to have an effect.",
777 {{"/qh level", "See information related to the level filter."},
778 {"/qh level 0", "Only allow objectives at or below your current level."},
779 {"/qh level +2", "Allow objectives up to two levels above your current level."},
780 {"/qh level -1", "Only allow objectives below your current level."}}, QuestHelper.LevelOffset, QuestHelper},
782 {"GROUP",
783 "Adjusts the player cutoff used by the group filter. Naturally, the group filter must be turned on to have an effect.",
784 {{"/qh group", "See information related to the group filter."},
785 {"/qh group 0", "Only allow objectives that can be done solo."},
786 {"/qh group 2", "Allow objectives that require, at most, two groupmembers."},
787 {"/qh group 5", "Allow objectives that require, at most, five groupmembers."},
788 {"/qh group instance", "Equivalent to /qh group 5."},
789 {"/qh group raid", "Equivalent to /qh group 10. All raid quests are currently assumed to be 10-person raids."},
790 }, QuestHelper.GroupOffset, QuestHelper},
792 {"SCALE",
793 "Scales the map icons used by QuestHelper. Will accept values between 50% and 300%.",
794 {{"/qh scale 1", "Uses the default icon size."},
795 {"/qh scale 2", "Makes icons twice their default size."},
796 {"/qh scale 80%", "Makes icons slightly smaller than their default size."}},
797 QuestHelper.genericSetScale, QuestHelper, "scale", "icon scale", .5, 3},
799 {"SHARE",
800 "Toggles objective sharing between QuestHelper users.",
801 {}, QuestHelper.ToggleShare, QuestHelper},
804 { "Interface", {
805 --[[{"BLIZZMAP",
806 "Toggles the visibility of Blizzard's built-in map points.",
807 {}, QuestHelper.ToggleBlizzMap, QuestHelper},]]
809 {"TRACK",
810 "Toggles the visibility of the QuestHelper's replacement quest tracker.",
811 {}, QuestHelper.ToggleTrack, QuestHelper},
813 {"TSCALE",
814 "Scales the quest tracker provided by QuestHelper. Will accept values between 50% and 300%.",
816 QuestHelper.TrackerScale, QuestHelper},
818 {"TRESET",
819 "Reset's the position of the quest tracker provided by QuestHelper, in cause you move it somewhere inaccessable.",
820 {{"/qh treset center", "Resets to the center of the screen, instead of a more normal quest tracker location."}}, QuestHelper.ResetTrackerPosition, QuestHelper},
822 {"TLEVEL",
823 "Toggles display of levels in the quest tracker provided by QuestHelper.",
824 {}, QuestHelper.ToggleTrackLevel, QuestHelper},
826 {"TQCOL",
827 "Toggles display of colours for the difficulty level of quests in the quest tracker provided by QuestHelper.",
828 {}, QuestHelper.ToggleTrackQColour, QuestHelper},
830 {"TOCOL",
831 "Toggles display of colours for objective progress in the quest tracker provided by QuestHelper.",
832 {}, QuestHelper.ToggleTrackOColour, QuestHelper},
834 {"TOOLTIP",
835 "Toggles appending information about tracked items and NPCs to their tooltips.",
836 {}, QuestHelper.ToggleTooltip, QuestHelper},
838 {"FTIME",
839 "Toggles display of flight time estimates.", {}, QuestHelper.ToggleFlightTimes, QuestHelper},
841 {"TRAVELTIME",
842 "Toggles display of travel time estimates.", {}, QuestHelper.ToggleTravelTimes, QuestHelper},
844 {"ANTS",
845 "Toggles the display of trails on the world map on and off.",
846 {}, QuestHelper.ToggleAnts, QuestHelper},
848 {"ZONES",
849 "Changes the display of the quest objective zones on the main map.",
850 {}, QuestHelper.SetZones, QuestHelper},
852 {"LOCALE",
853 "Select the locale to use for displayed messages.",
854 {}, QuestHelper.SetLocale, QuestHelper},
856 {"BUTTON",
857 "Toggles the display of QuestHelper's button on the world map.",
858 {}, QuestHelper.ToggleMapButton, QuestHelper},
860 {"SETTINGS",
861 "Opens the Settings menu at the current cursor location. Note that not all settings can be changed through the menu.",
862 {}, QuestHelper.DoSettingsMenu, QuestHelper},
865 { "Data collection", {
866 {"SUBMIT",
867 "Displays instructions for submitting your collected data.",
868 {}, QuestHelper.Submit, QuestHelper},
870 --[[
871 {"NAG",
872 "Tells you if you have anything that's missing from the static database. It can only check quests from your own faction, as the quests of your opposing faction are ommitted to save memory.",
873 {{"/qh nag verbose", "Prints the specific changes that were found."}}, QuestHelper.Nag, QuestHelper},]]
875 {"PURGE",
876 "Deletes all QuestHelper's collected data.", {}, QuestHelper.Purge, QuestHelper},
878 {"HARDRESET",
879 "Deletes all QuestHelper's collected data and resets QuestHelper preferences.", {}, QuestHelper.HardReset, QuestHelper},
882 { "Performance and debug", {
883 {"PERF",
884 "Sets or shows the route workload. Higher means more agressive route updating, lower means better performance Accepts numbers between 10% and 500%.",
885 {{"/qh perf", "Show current Performance Factor"},
886 {"/qh perf 1", "Sets standard performance"},
887 {"/qh perf 50%", "Does half as much background processing"},
888 {"/qh perf 3", "Computes routes 3 times more aggressively. Better have some good horsepower!"}},
889 QuestHelper.genericSetScale, QuestHelper, "perf_scale_2", "performance factor", .1, 5},
891 {"PERFLOAD",
892 "Sets or shows the initialization workload. Higher numbers will make QuestHelper load faster, lower numbers will result in better framerate while it's loading.",
893 {{"/qh perfload", "Show current Performance Factor"},
894 {"/qh perfload 1", "Sets standard performance"},
895 {"/qh perfload 50%", "Does half as much background processing"},
896 {"/qh perfload 3", "Loads 3 times as quickly."}},
897 QuestHelper.genericSetScale, QuestHelper, "perfload_scale", "boot performance factor", .2, 5},
899 {"TOP",
900 "Displays various performance stats on QuestHelper.",
902 {"/qh top recycle", "Displays detailed information on QuestHelper's recycled item pools"},
903 {"/qh top usage", "Displays detailed information on which table types are most common"},
904 {"/qh top cache", "Displays detailed information on the internal distance cache"},
905 {"/qh top perf", "Displays detailed information on coroutine CPU usage"},
906 }, QuestHelper.Top, QuestHelper},
908 {"ERROR",
909 "Displays the first QuestHelper error that has been generated this session in a form which can be copied out of WoW.",
910 {}, QuestHelper.ShowError, QuestHelper},
912 {"POS",
913 "Prints the player's current position. Exists mainly for my own personal convenience.",
914 {}, function (qh) qh:TextOut(qh:LocationString(qh.i, qh.x, qh.y) .. " " .. qh:Location_RawString(qh:Location_RawRetrieve()) .. " " .. qh:Location_AbsoluteString(qh:Location_AbsoluteRetrieve())) end, QuestHelper},
917 { "Help", {
918 {"HELP",
919 "Displays a list of help commands. Listed commands are filtered by the passed string.",
920 {}, QuestHelper.Help, QuestHelper},
922 {"VERSION",
923 "Displays QuestHelper's version.", {}, QuestHelper.PrintVersion, QuestHelper},
925 {"CHANGES",
926 "Displays a summary of changes recently made to QuestHelper.",
927 {}, QuestHelper.ChangeLog, QuestHelper},
929 --[[{"DONATE",
930 "Displays some instructions and a link for donating.",
931 {}, QuestHelper.Donate, QuestHelper},]]
934 { "Incredibly Experimental And Unsupported", {
935 {"BONFIRES",
936 "Adds waypoints for the Midsummer Bonfires.",
937 {}, QH_AddFires},
941 function QuestHelper_SlashCommand(input)
942 local _, _, command, argument = string.find(input, "^%s*([^%s]-)%s+(.-)%s*$")
943 if not command then
944 command, argument = input, ""
947 command = string.upper(command)
949 for i1, cat in ipairs(commands) do
950 for i, data in ipairs(cat[2]) do
951 if data[1] == command then
952 local st = {}
954 for i = 5,#data do table.insert(st, data[i]) end
955 table.insert(st, argument)
957 if type(data[4]) == "function" then
958 data[4](unpack(st))
959 else
960 QuestHelper:TextOut(data[1].." is not yet implemented.")
963 return
968 QuestHelper:Help()
971 SLASH_QuestHelper1 = "/qh"
972 SLASH_QuestHelper2 = "/questhelper"
973 SlashCmdList["QuestHelper"] = function (text) QuestHelper_SlashCommand(text) end