maybe this fixes the graph issue
[QuestHelper.git] / main.lua
blob3c4a880d3d8e0635ffa3657a024ebd71405df8b5
1 QuestHelper_File["main.lua"] = "Development Version"
2 QuestHelper_Loadtime["main.lua"] = GetTime()
4 local version_string = QuestHelper_File["main.lua"] -- we pretty much save this only so we can inform the user that they're using a beta version
6 -- Just to make sure it's always 'seen' (there's nothing that can be seen, but still...), and therefore always updating.
7 QuestHelper:SetFrameStrata("TOOLTIP")
9 QuestHelper_SaveVersion = 10
10 QuestHelper_CharVersion = 1
11 QuestHelper_Locale = GetLocale() -- This variable is used only for the collected data, and has nothing to do with displayed text.
12 QuestHelper_Quests = {}
13 QuestHelper_Objectives = {}
15 QuestHelper_Pref =
18 QuestHelper_DefaultPref =
20 filter_level=true,
21 filter_zone=false,
22 filter_done=false,
23 filter_blocked=false, -- Hides blocked objectives, such as quest turn-ins for incomplete quests
24 filter_watched=false, -- Limits to Watched objectives
25 track=true,
26 track_minimized=false,
27 track_scale=1,
28 track_level=true,
29 track_qcolour=true,
30 track_ocolour=true,
31 track_size=10,
32 tooltip=true,
33 share = true,
34 scale = 1,
35 solo = false,
36 comm = false,
37 show_ants = true,
38 level = 3,
39 hide = false,
40 cart_wp_new = false,
41 tomtom_wp_new = false,
42 arrow = true,
43 arrow_locked = false,
44 arrow_arrowsize = 1,
45 arrow_textsize = 1,
46 flight_time = true,
47 locale = GetLocale(), -- This variable is used for display purposes, and has nothing to do with the collected data.
48 perf_scale = 1, -- How much background processing can the current machine handle? Higher means more load, lower means better performance.
49 perfload_scale = 1, -- Performance scale to use on startup
50 map_button = true,
53 -- We do it here also in case things decide they care about preferences before the init function is called. Shouldn't happen, but maybe does.
54 setmetatable(QuestHelper_Pref, {__index=QuestHelper_DefaultPref})
56 QuestHelper_FlightInstructors = {}
57 QuestHelper_FlightLinks = {}
58 QuestHelper_FlightRoutes = {}
59 QuestHelper_KnownFlightRoutes = {}
60 QuestHelper_SeenRealms = {}
62 QuestHelper.tooltip = CreateFrame("GameTooltip", "QuestHelperTooltip", nil, "GameTooltipTemplate")
63 QuestHelper.objective_objects = {}
64 QuestHelper.user_objectives = {}
65 QuestHelper.quest_objects = {}
66 QuestHelper.player_level = 1
67 QuestHelper.locale = QuestHelper_Locale
69 QuestHelper.faction = (UnitFactionGroup("player") == "Alliance" and 1) or
70 (UnitFactionGroup("player") == "Horde" and 2)
72 assert(QuestHelper.faction)
74 QuestHelper.font = {serif=GameFontNormal:GetFont(), sans=ChatFontNormal:GetFont(), fancy=QuestTitleFont:GetFont()}
76 function QuestHelper:GetFontPath(list_string, font)
77 if list_string then
78 for name in string.gmatch(list_string, "[^;]+") do
79 if font:SetFont(name, 10) then
80 return name
81 elseif font:SetFont("Interface\\AddOns\\QuestHelper\\Fonts\\"..name, 10) then
82 return "Interface\\AddOns\\QuestHelper\\Fonts\\"..name
83 end
84 end
85 end
86 end
88 function QuestHelper:SetLocaleFonts()
89 self.font.sans = nil
90 self.font.serif = nil
91 self.font.fancy = nil
93 local font = self:CreateText(self)
95 if QuestHelper_Locale ~= QuestHelper_Pref.locale then
96 -- Only use alternate fonts if using a language the client wasn't intended for.
97 local replacements = QuestHelper_SubstituteFonts[QuestHelper_Pref.locale]
98 if replacements then
99 self.font.sans = self:GetFontPath(replacements.sans, font)
100 self.font.serif = self:GetFontPath(replacements.serif, font)
101 self.font.fancy = self:GetFontPath(replacements.fancy, font)
105 self.font.sans = self.font.sans or self:GetFontPath(QuestHelper_Pref.locale.."_sans.ttf", font)
106 self.font.serif = self.font.serif or self:GetFontPath(QuestHelper_Pref.locale.."_serif.ttf", font) or self.font.sans
107 self.font.fancy = self.font.fancy or self:GetFontPath(QuestHelper_Pref.locale.."_fancy.ttf", font) or self.font.serif
109 self:ReleaseText(font)
111 self.font.sans = self.font.sans or ChatFontNormal:GetFont()
112 self.font.serif = self.font.serif or GameFontNormal:GetFont()
113 self.font.fancy = self.font.fancy or QuestTitleFont:GetFont()
115 -- Need to change the font of the chat frame, for any messages that QuestHelper displays.
116 -- This should do nothing if not using an alternate font.
117 DEFAULT_CHAT_FRAME:SetFont(self.font.sans, select(2, DEFAULT_CHAT_FRAME:GetFont()))
120 QuestHelper.route = {}
121 QuestHelper.to_add = {}
122 QuestHelper.to_remove = {}
123 QuestHelper.quest_log = {}
124 QuestHelper.pos = {nil, {}, 0, 0, 1, "You are here.", 0}
125 QuestHelper.sharing = false -- Will be set to true when sharing with at least one user.
127 function QuestHelper.tooltip:GetPrevLines() -- Just a helper to make life easier.
128 local last = self:NumLines()
129 local name = self:GetName()
130 return _G[name.."TextLeft"..last], _G[name.."TextRight"..last]
133 function QuestHelper:SetTargetLocation(i, x, y, toffset)
134 -- Informs QuestHelper that you're going to be at some location in toffset seconds.
135 local c, z = unpack(QuestHelper_ZoneLookup[i])
137 self.target = self:CreateTable()
138 self.target[2] = self:CreateTable()
140 self.target_time = time()+(toffset or 0)
142 x, y = self.Astrolabe:TranslateWorldMapPosition(c, z, x, y, c, 0)
143 self.target[1] = self.zone_nodes[i]
144 self.target[3] = x * self.continent_scales_x[c]
145 self.target[4] = y * self.continent_scales_y[c]
147 self:SetTargetLocationRecalculate()
150 function QuestHelper:SetTargetLocationRecalculate()
151 if self.target then
152 for i, n in ipairs(self.target[1]) do
153 local a, b = n.x-self.target[3], n.y-self.target[4]
154 self.target[2][i] = math.sqrt(a*a+b*b)
159 function QuestHelper:UnsetTargetLocation()
160 -- Unsets the target set above.
161 if self.target then
162 self:ReleaseTable(self.target[2])
163 self:ReleaseTable(self.target)
164 self.target = nil
165 self.target_time = nil
169 local interruptcount = 0 -- counts how many "played gained control" messages we recieve, used for flight paths
170 local init_cartographer_later = false
172 function QuestHelper:Initialize()
173 QuestHelper_Loadtime["init_start"] = GetTime()
175 -- Use DefaultPref as fallback for unset preference keys.
176 setmetatable(QuestHelper_Pref, {__index=QuestHelper_DefaultPref})
178 local file_problem = false
179 local expected_version = GetAddOnMetadata("QuestHelper", "Version")
181 local expected_files =
183 ["bst_pre.lua"] = true,
184 ["bst_post.lua"] = true,
185 ["bst_astrolabe.lua"] = true,
186 ["bst_ctl.lua"] = true,
187 ["bst_libaboutpanel.lua"] = true,
189 ["manager_event.lua"] = true,
191 ["upgrade.lua"] = true,
192 ["main.lua"] = true,
193 ["recycle.lua"] = true,
194 ["objective.lua"] = true,
195 ["quest.lua"] = true,
196 ["questlog.lua"] = true,
197 ["utility.lua"] = true,
198 ["dodads.lua"] = true,
199 ["teleport.lua"] = true,
200 ["pathfinding.lua"] = true,
201 ["routing.lua"] = true,
202 ["custom.lua"] = true,
203 ["menu.lua"] = true,
204 ["hidden.lua"] = true,
205 ["nag.lua"] = true,
206 ["comm.lua"] = true,
207 ["mapbutton.lua"] = true,
208 ["help.lua"] = true,
209 ["pattern.lua"] = true,
210 ["flightpath.lua"] = true,
211 ["tracker.lua"] = true,
212 ["objtips.lua"] = true,
213 ["cartographer.lua"] = true,
214 ["tomtom.lua"] = true,
215 ["textviewer.lua"] = true,
216 ["error.lua"] = true,
217 ["timeslice.lua"] = true,
218 ["lang.lua"] = true,
219 ["core.lua"] = true,
220 ["tooltip.lua"] = true,
221 ["arrow.lua"] = true,
223 ["static.lua"] = true,
224 ["static_1.lua"] = true,
225 ["static_2.lua"] = true,
226 ["static_deDE.lua"] = true,
227 ["static_deDE_1.lua"] = true,
228 ["static_deDE_2.lua"] = true,
229 ["static_enUS.lua"] = true,
230 ["static_enUS_1.lua"] = true,
231 ["static_enUS_2.lua"] = true,
232 ["static_esES.lua"] = true,
233 ["static_esES_1.lua"] = true,
234 ["static_esES_2.lua"] = true,
235 ["static_esMX.lua"] = true,
236 ["static_esMX_1.lua"] = true,
237 ["static_esMX_2.lua"] = true,
238 ["static_frFR.lua"] = true,
239 ["static_frFR_1.lua"] = true,
240 ["static_frFR_2.lua"] = true,
241 ["static_koKR.lua"] = true,
242 ["static_koKR_1.lua"] = true,
243 ["static_koKR_2.lua"] = true,
244 ["static_ruRU.lua"] = true,
245 ["static_ruRU_1.lua"] = true,
246 ["static_ruRU_2.lua"] = true,
247 ["static_zhTW.lua"] = true,
248 ["static_zhTW_1.lua"] = true,
249 ["static_zhTW_2.lua"] = true,
251 ["collect.lua"] = true,
252 ["collect_achievement.lua"] = true,
253 ["collect_lzw.lua"] = true,
254 ["collect_traveled.lua"] = true,
255 ["collect_zone.lua"] = true,
256 ["collect_location.lua"] = true,
257 ["collect_merger.lua"] = true,
258 ["collect_monster.lua"] = true,
259 ["collect_item.lua"] = true,
260 ["collect_object.lua"] = true,
261 ["collect_loot.lua"] = true,
262 ["collect_patterns.lua"] = true,
263 ["collect_flight.lua"] = true,
264 ["collect_util.lua"] = true,
265 ["collect_quest.lua"] = true,
266 ["collect_equip.lua"] = true,
267 ["collect_notifier.lua"] = true,
268 ["collect_bitstream.lua"] = true,
269 ["collect_spec.lua"] = true,
270 ["collect_upgrade.lua"] = true,
271 ["collect_merchant.lua"] = true,
272 ["collect_warp.lua"] = true,
274 ["filter_core.lua"] = true,
275 ["filter_base.lua"] = true,
277 ["routing_debug.lua"] = true,
278 ["routing_loc.lua"] = true,
279 ["routing_route.lua"] = true,
280 ["routing_core.lua"] = true,
281 ["routing_controller.lua"] = true,
282 ["routing_hidden.lua"] = true,
284 ["director_quest.lua"] = true,
286 ["db_get.lua"] = true,
288 ["graph_core.lua"] = true,
289 ["graph_flightpath.lua"] = true,
292 local uninstallederr = ""
294 for file, version in pairs(QuestHelper_File) do
295 if not expected_files[file] then
296 local errmsg = "Unexpected QuestHelper file: "..file
297 DEFAULT_CHAT_FRAME:AddMessage(errmsg)
298 uninstallederr = uninstallederr .. " " .. errmsg .. "\n"
299 file_problem = true
300 elseif version ~= expected_version then
301 local errmsg = "Wrong version of QuestHelper file: "..file.." (found '"..version.."', should be '"..expected_version.."')"
302 DEFAULT_CHAT_FRAME:AddMessage(errmsg)
303 uninstallederr = uninstallederr .. " " .. errmsg .. "\n"
304 if version ~= "Development Version" and expected_version ~= "Development Version" then
305 -- Developers are allowed to mix dev versions with release versions
306 file_problem = true
311 for file in pairs(expected_files) do
312 if not QuestHelper_File[file] then
313 local errmsg = "Missing QuestHelper file: "..file
314 DEFAULT_CHAT_FRAME:AddMessage(errmsg)
315 uninstallederr = uninstallederr .. " " .. errmsg .. "\n"
316 if not (expected_version == "Development Version" and file:match("static.*")) then file_problem = true end
320 -- Don't need this table anymore.
321 QuestHelper_File = nil
323 if QuestHelper_StaticData and not QuestHelper_StaticData[GetLocale()] then
324 local errmsg = "Static data does not seem to exist"
325 DEFAULT_CHAT_FRAME:AddMessage(errmsg)
327 -- TODO: Are you sure this should be an error? Shouldn't we let people we don't have data for collect their own?
328 uninstallederr = uninstallederr .. " " .. errmsg .. "\n"
329 file_problem = true
332 if file_problem then
333 message(QHText("PLEASE_RESTART"))
334 QuestHelper_ErrorCatcher_ExplicitError(true, "not-installed-properly" .. "\n" .. uninstallederr)
335 QuestHelper = nil -- Just in case anybody else is checking for us, we're not home
336 return
339 if not GetCategoryList or not GetQuestLogSpecialItemInfo or not WatchFrame_RemoveObjectiveHandler then
340 message(QHText("PRIVATE_SERVER"))
341 QuestHelper_ErrorCatcher_ExplicitError(true, "error id cakbep ten T")
342 QuestHelper = nil
343 return
346 if not DongleStub then
347 message(QHText("NOT_UNZIPPED_CORRECTLY"))
348 QuestHelper_ErrorCatcher_ExplicitError(true, "not-unzipped-properly")
349 QuestHelper = nil -- Just in case anybody else is checking for us, we're not home
350 return
353 QuestHelper_ErrorCatcher_CompletelyStarted()
355 if not QuestHelper_StaticData then
356 -- If there is no static data for some mysterious reason, create an empty table so that
357 -- other parts of the code can carry on as usual, using locally collected data if it exists.
358 QuestHelper_StaticData = {}
361 QHFormatSetLocale(QuestHelper_Pref.locale or GetLocale())
363 if not QuestHelper_UID then
364 QuestHelper_UID = self:CreateUID()
366 QuestHelper_SaveDate = time()
368 QuestHelper_BuildZoneLookup()
369 QH_Graph_Init()
370 load_graph_links()
372 if QuestHelper_Locale ~= GetLocale() then
373 self:TextOut(QHText("LOCALE_ERROR"))
374 return
377 if not self:ZoneSanity() then
378 self:TextOut(QHText("ZONE_LAYOUT_ERROR"))
379 message("QuestHelper: "..QHText("ZONE_LAYOUT_ERROR"))
380 return
383 QuestHelper_UpgradeDatabase(_G)
384 QuestHelper_UpgradeComplete()
386 if QuestHelper_SaveVersion ~= 10 then
387 self:TextOut(QHText("DOWNGRADE_ERROR"))
388 return
391 if QuestHelper_IsPolluted(_G) then
392 self:TextOut(QHFormat("NAG_POLLUTED"))
393 self:Purge(nil, true, true)
396 local signature = expected_version .. " on " .. GetBuildInfo()
397 QuestHelper_Quests[signature] = QuestHelper_Quests[signature] or {}
398 QuestHelper_Objectives[signature] = QuestHelper_Objectives[signature] or {}
399 QuestHelper_FlightInstructors[signature] = QuestHelper_FlightInstructors[signature] or {}
400 QuestHelper_FlightRoutes[signature] = QuestHelper_FlightRoutes[signature] or {}
402 QuestHelper_Quests_Local = QuestHelper_Quests[signature]
403 QuestHelper_Objectives_Local = QuestHelper_Objectives[signature]
404 QuestHelper_FlightInstructors_Local = QuestHelper_FlightInstructors[signature]
405 QuestHelper_FlightRoutes_Local = QuestHelper_FlightRoutes[signature]
407 QuestHelper_SeenRealms[GetRealmName()] = true -- some attempt at tracking private servers
409 QH_Collector_Init()
410 DB_Init()
412 self.player_level = UnitLevel("player")
414 self:UnregisterEvent("VARIABLES_LOADED")
415 self:RegisterEvent("PLAYER_TARGET_CHANGED")
416 self:RegisterEvent("LOOT_OPENED")
417 self:RegisterEvent("QUEST_COMPLETE")
418 self:RegisterEvent("QUEST_LOG_UPDATE")
419 self:RegisterEvent("QUEST_PROGRESS")
420 self:RegisterEvent("MERCHANT_SHOW")
421 self:RegisterEvent("QUEST_DETAIL")
422 self:RegisterEvent("TAXIMAP_OPENED")
423 self:RegisterEvent("PLAYER_CONTROL_GAINED")
424 self:RegisterEvent("PLAYER_LEVEL_UP")
425 self:RegisterEvent("PARTY_MEMBERS_CHANGED")
426 self:RegisterEvent("CHAT_MSG_ADDON")
427 self:RegisterEvent("CHAT_MSG_SYSTEM")
428 self:RegisterEvent("BAG_UPDATE")
429 self:RegisterEvent("GOSSIP_SHOW")
430 self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE")
431 self:RegisterEvent("UNIT_LEVEL")
432 self:RegisterEvent("ZONE_CHANGED")
433 self:RegisterEvent("ZONE_CHANGED_INDOORS")
434 self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
436 self:SetLocaleFonts()
438 if QuestHelper_Pref.share and not QuestHelper_Pref.solo then
439 self:EnableSharing()
442 if QuestHelper_Pref.hide then
443 self.map_overlay:Hide()
446 self:HandlePartyChange()
448 self:Nag("all")
450 for locale in pairs(QuestHelper_StaticData) do
451 if locale ~= self.locale then
452 -- Will delete references to locales you don't use.
453 QuestHelper_StaticData[locale] = nil
454 _G["QuestHelper_StaticData_" .. locale] = nil
458 local static = QuestHelper_StaticData[self.locale]
460 if static then
461 if static.flight_instructors then for faction in pairs(static.flight_instructors) do
462 if faction ~= self.faction then
463 -- Will delete references to flight instructors that don't belong to your faction.
464 static.flight_instructors[faction] = nil
466 end end
468 if static.quest then for faction in pairs(static.quest) do
469 if faction ~= self.faction then
470 -- Will delete references to quests that don't belong to your faction.
471 static.quest[faction] = nil
473 end end
476 -- Adding QuestHelper_CharVersion, so I know if I've already converted this characters saved data.
477 if not QuestHelper_CharVersion then
478 -- Changing per-character flight routes, now only storing the flight points they have,
479 -- will attempt to guess the routes from this.
480 local routes = {}
482 for i, l in pairs(QuestHelper_KnownFlightRoutes) do
483 for key in pairs(l) do
484 routes[key] = true
488 QuestHelper_KnownFlightRoutes = routes
490 -- Deleting the player's home again.
491 -- But using the new CharVersion variable I'm adding is cleaner that what I was doing, so I'll go with it.
492 QuestHelper_Home = nil
493 QuestHelper_CharVersion = 1
496 if not QuestHelper_Home then
497 -- Not going to bother complaining about the player's home not being set, uncomment this when the home is used in routing.
498 -- self:TextOut(QHText("HOME_NOT_KNOWN"))
501 if QuestHelper_Pref.map_button then
502 QuestHelper:InitMapButton()
505 if QuestHelper_Pref.cart_wp_new then
506 init_cartographer_later = true
509 if QuestHelper_Pref.tomtom_wp_new then
510 self:EnableTomTom()
513 self.tracker:SetScale(QuestHelper_Pref.track_scale)
515 if QuestHelper_Pref.track and not QuestHelper_Pref.hide then
516 self:ShowTracker()
519 local version = GetAddOnMetadata("QuestHelper", "Version") or "Unknown"
521 local major, minor = (version_string or ""):match("^(%d+)%.(%d+)")
522 major, minor = tonumber(major), tonumber(minor)
524 -- For versions before 0.82, we're changing the default level offset to 3.
525 if major == 0 and minor and minor < 82 and QuestHelper_Pref.level == 2 then
526 QuestHelper_Pref.level = nil
529 -- For versions before 0.84...
530 if major == 0 and minor and minor < 84 then
531 -- remove all keys that match their default setting.
532 for key, val in pairs(QuestHelper_DefaultPref) do
533 if QuestHelper_Pref[key] == val then
534 QuestHelper_Pref[key] = nil
539 self:SetScript("OnUpdate", self.OnUpdate)
541 -- Seems to do its own garbage collection pass before fully loading, so I'll just rely on that
542 --collectgarbage("collect") -- Free everything we aren't using.
544 --[[
545 if self.debug_objectives then
546 for name, data in pairs(self.debug_objectives) do
547 self:LoadDebugObjective(name, data)
549 end]]
551 -- wellllp
552 QH_Arrow_SetScale()
553 QH_Arrow_SetTextScale()
555 --[[
556 QH_Timeslice_Add(function ()
557 self:ResetPathing()
558 self.Routing:Initialize() -- Set up the routing task
559 end, "init")]] -- FUCK YOU BOXBOT
561 --[[ -- This is just an example of how the WoW profiler biases its profiles heavily.
562 function C()
565 function A()
566 q = 0
567 for x = 0, 130000000, 1 do
571 function B()
572 q = 0
573 for x = 0, 12000000, 1 do
578 function B2()
579 q = 0
580 for x = 0, 1200000, 1 do
581 --q = q + x
586 debugprofilestart()
588 local ta = debugprofilestop()
590 local tb = debugprofilestop()
592 local tc = debugprofilestop()
594 QuestHelper:TextOut(string.format("%d %d %d", ta, tb - ta, tc - tb))
595 QuestHelper:TextOut(string.format("%d %d", GetFunctionCPUUsage(A), GetFunctionCPUUsage(B)))
597 --/script SetCVar("scriptProfile", value)]]
599 LibStub("LibAboutPanelQH").new(nil, "QuestHelper")
601 QuestHelper_Loadtime["init_end"] = GetTime()
603 QuestHelper.loading_main = QuestHelper.CreateLoadingCounter()
605 QuestHelper.loading_flightpath = QuestHelper.loading_main:MakeSubcategory(1)
606 QuestHelper.loading_preroll = QuestHelper.loading_main:MakeSubcategory(1)
609 local startup_time
610 local please_donate_enabled = false
611 local please_donate_initted = false
613 function QuestHelper:OnEvent(event)
614 if event == "VARIABLES_LOADED" then
615 local tstart = GetTime()
616 self:Initialize()
617 QH_Timeslice_Increment(GetTime() - tstart, "init")
620 local tstart = GetTime()
622 --[[
623 if event == "GOSSIP_SHOW" then
624 local name, id = UnitName("npc"), self:GetUnitID("npc")
625 if name and id then
626 self:GetObjective("monster", name).o.id = id
627 --self:TextOut("NPC: "..name.." = "..id)
629 end]]
631 --[[if event == "PLAYER_TARGET_CHANGED" then
632 local name, id = UnitName("target"), self:GetUnitID("target")
633 if name and id then
634 self:GetObjective("monster", name).o.id = id
635 --self:TextOut("Target: "..name.." = "..id)
638 if UnitExists("target") and UnitIsVisible("target") and UnitCreatureType("target") ~= "Critter" and not UnitIsPlayer("target") and not UnitPlayerControlled("target") then
639 local index, x, y = self:UnitPosition("target")
641 if index then -- Might not have a position if inside an instance.
642 local w = 0.1
644 -- Modify the weight based on how far they are from us.
645 -- We don't know the exact location (using our own location), so the farther, the less sure we are that it's correct.
646 if CheckInteractDistance("target", 3) then w = 1
647 elseif CheckInteractDistance("target", 2) then w = 0.89
648 elseif CheckInteractDistance("target", 1) or CheckInteractDistance("target", 4) then w = 0.33 end
650 local monster_objective = self:GetObjective("monster", UnitName("target"))
651 self:AppendObjectivePosition(monster_objective, index, x, y, w)
653 monster_objective.o.faction = (UnitFactionGroup("target") == "Alliance" and 1) or
654 (UnitFactionGroup("target") == "Horde" and 2) or nil
656 local level = UnitLevel("target")
657 if level and level >= 1 then
658 local w = monster_objective.o.levelw or 0
659 monster_objective.o.level = ((monster_objective.o.level or 0)*w+level)/(w+1)
660 monster_objective.o.levelw = w+1
664 end]]
666 --[[if event == "LOOT_OPENED" then
667 local target = UnitName("target")
668 if target and UnitIsDead("target") and UnitCreatureType("target") ~= "Critter" and not UnitIsPlayer("target") and not UnitPlayerControlled("target") then
669 local index, x, y = self:UnitPosition("target")
671 local monster_objective = self:GetObjective("monster", target)
672 monster_objective.o.looted = (monster_objective.o.looted or 0) + 1
674 if index then -- Might not have a position if inside an instance.
675 self:AppendObjectivePosition(monster_objective, index, x, y)
678 for i = 1, GetNumLootItems() do
679 local icon, name, number, rarity = GetLootSlotInfo(i)
680 if name then
681 if number and number >= 1 then
682 self:AppendItemObjectiveDrop(self:GetObjective("item", name), name, target, number)
683 else
684 local total = (name:match(COPPER_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) +
685 (name:match(SILVER_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) * 100 +
686 (name:match(GOLD_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) * 10000
688 if total > 0 then
689 self:AppendObjectiveDrop(self:GetObjective("item", "money"), target, total)
694 else
695 local container = nil
697 -- Go through the players inventory and look for a locked item, we're probably looting it.
698 for bag = 0,NUM_BAG_SLOTS do
699 for slot = 1,GetContainerNumSlots(bag) do
700 local link = GetContainerItemLink(bag, slot)
701 if link and select(3, GetContainerItemInfo(bag, slot)) then
702 if container == nil then
703 -- Found a locked item and haven't previously assigned to container, assign its name, or false if we fail to parse it.
704 container = select(3, string.find(link, "|h%[(.+)%]|h|r")) or false
705 else
706 -- Already tried to assign to a container. If there are multiple locked items, we give up.
707 container = false
713 if container then
714 local container_objective = self:GetObjective("item", container)
715 container_objective.o.opened = (container_objective.o.opened or 0) + 1
717 for i = 1, GetNumLootItems() do
718 local icon, name, number, rarity = GetLootSlotInfo(i)
719 if name and number >= 1 then
720 self:AppendItemObjectiveContainer(self:GetObjective("item", name), container, number)
723 else
724 -- No idea where the items came from.
725 local index, x, y = self:PlayerPosition()
727 if index then
728 for i = 1, GetNumLootItems() do
729 local icon, name, number, rarity = GetLootSlotInfo(i)
730 if name and number >= 1 then
731 self:AppendItemObjectivePosition(self:GetObjective("item", name), name, index, x, y)
737 end]]
739 --[[if event == "CHAT_MSG_SYSTEM" then
740 local home_name = self:convertPattern(ERR_DEATHBIND_SUCCESS_S)(arg1)
741 if home_name then
742 if self.i then
743 self:TextOut(QHText("HOME_CHANGED"))
744 self:TextOut(QHText("WILL_RESET_PATH"))
746 local home = QuestHelper_Home
747 if not home then
748 home = {}
749 QuestHelper_Home = home
752 home[1], home[2], home[3], home[4] = self.i, self.x, self.y, home_name
753 self.defered_graph_reset = true
756 end]]
758 --[[if event == "CHAT_MSG_ADDON" then
759 if arg1 == "QHpr" and (arg3 == "PARTY" or arg3 == "WHISPER") and arg4 ~= UnitName("player") then
760 self:HandleRemoteData(arg2, arg4)
762 end]]
764 if event == "PARTY_MEMBERS_CHANGED" or
765 event == "UNIT_LEVEL" or
766 event == "RAID_ROSTER_UPDATE" then
767 QH_Filter_Group_Sync()
768 QH_Route_Filter_Rescan("filter_quest_level")
771 if event == "PLAYER_LEVEL_UP" then
772 self.player_level = arg1
773 QH_Route_Filter_Rescan("filter_quest_level")
777 --[[if event == "QUEST_DETAIL" then
778 if not self.quest_giver then self.quest_giver = {} end
779 local npc = UnitName("npc")
780 if npc then
781 -- Some NPCs aren't actually creatures, and so their positions might not be marked by PLAYER_TARGET_CHANGED.
782 local index, x, y = self:UnitPosition("npc")
784 if index then -- Might not have a position if inside an instance.
785 local npc_objective = self:GetObjective("monster", npc)
786 self:AppendObjectivePosition(npc_objective, index, x, y)
787 self.quest_giver[GetTitleText()] = npc
790 end]]
792 --[[if event == "QUEST_COMPLETE" or event == "QUEST_PROGRESS" then
793 local quest = GetTitleText()
794 if quest then
795 local level, hash = self:GetQuestLevel(quest)
796 if not level or level < 1 then
797 --self:TextOut("Don't know quest level for ".. quest.."!")
798 return
800 local q = self:GetQuest(quest, level, hash)
802 if q.need_hash then
803 q.o.hash = hash
806 local unit = UnitName("npc")
807 if unit then
808 q.o.finish = unit
809 q.o.pos = nil
811 -- Some NPCs aren't actually creatures, and so their positions might not be marked by PLAYER_TARGET_CHANGED.
812 local index, x, y = self:UnitPosition("npc")
813 if index then -- Might not have a position if inside an instance.
814 local npc_objective = self:GetObjective("monster", unit)
815 self:AppendObjectivePosition(npc_objective, index, x, y)
817 elseif not q.o.finish then
818 local index, x, y = self:PlayerPosition()
819 if index then -- Might not have a position if inside an instance.
820 self:AppendObjectivePosition(q, index, x, y)
824 end]]
826 --[[if event == "MERCHANT_SHOW" then
827 local npc_name = UnitName("npc")
828 if npc_name then
829 local npc_objective = self:GetObjective("monster", npc_name)
830 local index = 1
831 while true do
832 local item_name = GetMerchantItemInfo(index)
833 if item_name then
834 index = index + 1
835 local item_objective = self:GetObjective("item", item_name)
836 if not item_objective.o.vendor then
837 item_objective.o.vendor = {npc_name}
838 else
839 local known = false
840 for i, vendor in ipairs(item_objective.o.vendor) do
841 if npc_name == vendor then
842 known = true
843 break
846 if not known then
847 table.insert(item_objective.o.vendor, npc_name)
850 else
851 break
855 end]]
857 if event == "TAXIMAP_OPENED" then
858 self:taxiMapOpened()
861 --[[if event == "PLAYER_CONTROL_GAINED" then
862 interruptcount = interruptcount + 1
863 end]]
865 --[[if event == "BAG_UPDATE" then
866 for slot = 1,GetContainerNumSlots(arg1) do
867 local link = GetContainerItemLink(arg1, slot)
868 if link then
869 local id, name = select(3, string.find(link, "|Hitem:(%d+):.-|h%[(.-)%]|h"))
870 if name then
871 self:GetObjective("item", name).o.id = tonumber(id)
875 end]]
877 if event == "CHAT_MSG_CHANNEL_NOTICE" and please_donate_enabled and not please_donate_initted then
878 please_donate_enabled = QHNagInit()
879 startup_time = GetTime()
880 please_donate_initted = true
882 QHUpdateNagInit()
885 if event == "ZONE_CHANGED" or event == "ZONE_CHANGED_INDOORS" or event == "ZONE_CHANGED_NEW_AREA" then
886 QH_Route_Filter_Rescan()
889 QH_Timeslice_Increment(GetTime() - tstart, "event")
892 local map_shown_decay = 0
893 local delayed_action = 100
894 --local update_count = 0
895 local ontaxi = false
896 local frams = 0
898 function QuestHelper:OnUpdate()
899 local tstart = GetTime()
900 frams = frams + 1
902 if not QuestHelper_Loadtime["onupdate"] then QuestHelper_Loadtime["onupdate"] = GetTime() end
904 if false and frams == 60 then
905 self:ShowText([[
906 This is a |cffff8000beta of QuestHelper|r. Be warned: It may crash. It may lock up. It may give bad advice. It may spew errors. It shouldn't spam people, delete your hard-won epics, or make your computer catch on fire, but technically I'm giving no guarantees. |cffff8000If you want a polished, functioning product, close WoW, download the official QH release from curse.com, and use that.|r
908 Known bugs and issues include:
910 |cff40bbffNo support for "/qh find"|r
912 |cff40bbffNo support for in-party quest synchronization|r
914 These may not be fixed before the official 1.0 release - I'm hoping to get them all finished up in time for 1.1.
916 If you encounter any issue besides the ones listed here, please please please report it, if you're reading this you know how to get in contact with me anyway.
918 Thanks for testing!]], "QuestHelper " .. version_string, 500, 20, 10)
921 if frams == 250 then please_donate_enabled = false end -- TOOK TOO LONG >:(
922 if please_donate_enabled and startup_time and startup_time + 1 < GetTime() then
923 QuestHelper:TextOut(QHText("PLEASE_DONATE"))
924 startup_time = nil
925 please_donate_enabled = false
927 QHUpdateNagTick() -- These probably shouldn't be in OnUpdate. Eventually I'll move them somewhere cleaner.
929 if init_cartographer_later and Cartographer_Waypoints then -- there has to be a better way to do this
930 init_cartographer_later = false
931 if QuestHelper_Pref.cart_wp_new then
932 self:EnableCartographer()
936 if not ontaxi and UnitOnTaxi("player") then
937 self:flightBegan()
938 interruptcount = 0
939 elseif ontaxi and not UnitOnTaxi("player") then
940 self:flightEnded(interruptcount > 1)
942 ontaxi = UnitOnTaxi("player")
944 -- For now I'm ripping out the update_count code
945 --update_count = update_count - 1
946 --if update_count <= 0 then
948 -- Reset the update count for next time around; this will make sure the body executes every time
949 -- when perf_scale >= 1, and down to 1 in 10 iterations when perf_scale < 1, or when hidden.
950 --update_count = update_count + (QuestHelper_Pref.hide and 10 or 1/QuestHelper_Pref.perf_scale)
952 --if update_count < 0 then
953 -- Make sure the count doesn't go perpetually negative; don't know what will happen if it underflows.
954 --update_count = 0
955 --end
957 if self.Astrolabe.WorldMapVisible then
958 -- We won't trust that the zone returned by Astrolabe is correct until map_shown_decay is 0.
959 map_shown_decay = 2
960 elseif map_shown_decay > 0 then
961 map_shown_decay = map_shown_decay - 1
962 else
963 --SetMapToCurrentZone() -- not sure why this existed
966 --[[delayed_action = delayed_action - 1
967 if delayed_action <= 0 then
968 delayed_action = 100
969 self:HandlePartyChange()
970 end]]
972 local nc, nz, nx, ny = self.Astrolabe:GetCurrentPlayerPosition()
973 local tc, tx, ty
975 if nc and nc ~= -1 then -- We just want the raw data here, before we've done anything clever.
976 tc, tx, ty = self.Astrolabe:GetAbsoluteContinentPosition(nc, nz, nx, ny)
977 QuestHelper: Assert(tc and tx and ty) -- is it true? nobody knows! :D
980 if nc and nc == self.c and map_shown_decay > 0 and self.z > 0 and self.z ~= nz then
981 -- There's a chance Astrolable will return the wrong zone if you're messing with the world map, if you can
982 -- be seen in that zone but aren't in it.
983 local nnx, nny = self.Astrolabe:TranslateWorldMapPosition(nc, nz, nx, ny, nc, self.z)
984 if nnx > 0 and nny > 0 and nnx < 1 and nny < 1 then
985 nz, nx, ny = self.z, nnx, nny
989 if nc and nc > 0 and nz == 0 and nc == self.c and self.z > 0 then
990 nx, ny = self.Astrolabe:TranslateWorldMapPosition(nc, nz, nx, ny, nc, self.z)
991 if nx and ny --[[and nx > -0.1 and ny > -0.1 and nx < 1.1 and ny < 1.1]] then -- removing the conditional because I think I can use the data even when it's a little wonky
992 nz = self.z
993 else
994 nc, nz, nx, ny = nil, nil, nil, nil
998 if nc and nz > 0 then
999 self.c, self.z, self.x, self.y = nc, nz, nx, ny
1000 local upd_zone = false
1001 if self.i ~= QuestHelper_IndexLookup[nc][nz] then upd_zone = true end
1002 self.i = QuestHelper_IndexLookup[nc][nz]
1003 if upd_zone then QH_Route_Filter_Rescan("filter_zone") end
1006 if nc and nz and nx and ny and tc and tx and ty then
1007 self.collect_rc, self.collect_rz, self.collect_rx, self.collect_ry = nc, nz, nx, ny
1008 self.collect_ac, self.collect_ax, self.collect_ay = tc, tx, ty
1009 self.collect_delayed = false
1011 local ibi = self.InBrokenInstance
1012 if nc < -77 then self.InBrokenInstance = true else self.InBrokenInstance = false end
1014 if ibi and not self.InBrokenInstance then self.minimap_marker:OnUpdate(0) end -- poke
1015 else
1016 self.collect_delayed = true
1017 self.InBrokenInstance = true
1020 QH_Timeslice_Toggle("routing", not not self.c)
1022 self:PumpCommMessages()
1023 --end
1025 QH_Collector_OnUpdate()
1027 QH_Timeslice_Increment(GetTime() - tstart, "onupdate")
1029 QH_Timeslice_Work()
1032 -- Some or all of these may be nil. c,x,y should be enough for a location - c is the pure continent (currently either 0 or 3 for Azeroth or Outland, or -77 for the DK starting zone) and x,y are the coordinates within that continent.
1033 -- rc and rz are the continent and zone that Questhelper thinks it's within. For various reasons, this isn't perfect. TODO: Base it off the map zone name identifiers instead of the map itself?
1034 function QuestHelper:Location_RawRetrieve()
1035 return self.collect_delayed, self.collect_rc, self.collect_rz, self.collect_rx, self.collect_ry
1037 function QuestHelper:Location_AbsoluteRetrieve()
1038 return self.collect_delayed, self.collect_ac, self.collect_ax, self.collect_ay
1041 QuestHelper:RegisterEvent("VARIABLES_LOADED")
1042 QuestHelper:SetScript("OnEvent", QuestHelper.OnEvent)