Added colour for the progress of objectives in the quest tracker.
[QuestHelper.git] / main.lua
blob113c0686725e6009ef43a296a5db02700660ef8b
1 QuestHelper_File["main.lua"] = "Development Version"
3 QuestHelper = CreateFrame("Frame", "QuestHelper", nil)
5 -- Just to make sure it's always 'seen' (there's nothing that can be seen, but still...), and therefore always updating.
6 QuestHelper:SetFrameStrata("TOOLTIP")
8 QuestHelper_SaveVersion = 7
9 QuestHelper_CharVersion = 1
10 QuestHelper_Locale = GetLocale() -- This variable is used only for the collected data, and has nothing to do with displayed text.
11 QuestHelper_Quests = {}
12 QuestHelper_Objectives = {}
14 QuestHelper_Pref =
17 QuestHelper_DefaultPref =
19 filter_level=true,
20 filter_zone=false,
21 filter_done=false,
22 filter_blocked=false, -- Hides blocked objectives, such as quest turn-ins for incomplete quests
23 track=true,
24 track_scale=1,
25 track_level=true,
26 track_qcolour=true,
27 track_ocolour=true,
28 track_size=8,
29 tooltip=true,
30 share = true,
31 scale = 1,
32 solo = false,
33 comm = false,
34 show_ants = true,
35 level = 2,
36 hide = false,
37 cart_wp = true,
38 tomtom_wp = true,
39 flight_time = true,
40 locale = GetLocale(), -- This variable is used for display purposes, and has nothing to do with the collected data.
41 perf_scale = 1, -- How much background processing can the current machine handle? Higher means more load, lower means better performance.
42 map_button = true
45 QuestHelper_FlightInstructors = {}
46 QuestHelper_FlightLinks = {}
47 QuestHelper_FlightRoutes = {}
48 QuestHelper_KnownFlightRoutes = {}
50 QuestHelper.tooltip = CreateFrame("GameTooltip", "QuestHelperTooltip", nil, "GameTooltipTemplate")
51 QuestHelper.objective_objects = {}
52 QuestHelper.user_objectives = {}
53 QuestHelper.quest_objects = {}
54 QuestHelper.player_level = 1
55 QuestHelper.locale = QuestHelper_Locale
57 QuestHelper.faction = (UnitFactionGroup("player") == "Alliance" and 1) or
58 (UnitFactionGroup("player") == "Horde" and 2)
60 assert(QuestHelper.faction)
62 QuestHelper.font = {serif=GameFontNormal:GetFont(), sans=ChatFontNormal:GetFont(), fancy=QuestTitleFont:GetFont()}
64 function QuestHelper:GetFontPath(list_string, font)
65 if list_string then
66 for name in string.gmatch(list_string, "[^;]+") do
67 if font:SetFont(name, 10) then
68 return name
69 elseif font:SetFont("Interface\\AddOns\\QuestHelper\\Fonts\\"..name, 10) then
70 return "Interface\\AddOns\\QuestHelper\\Fonts\\"..name
71 end
72 end
73 end
74 end
76 function QuestHelper:SetLocaleFonts()
77 self.font.sans = nil
78 self.font.serif = nil
79 self.font.fancy = nil
81 local font = self:CreateText(self)
83 if QuestHelper_Locale ~= QuestHelper_Pref.locale then
84 -- Only use alternate fonts if using a language the client wasn't intended for.
85 local replacements = QuestHelper_SubstituteFonts[QuestHelper_Pref.locale]
86 if replacements then
87 self.font.sans = self:GetFontPath(replacements.sans, font)
88 self.font.serif = self:GetFontPath(replacements.serif, font)
89 self.font.fancy = self:GetFontPath(replacements.fancy, font)
90 end
91 end
93 self.font.sans = self.font.sans or self:GetFontPath(QuestHelper_Pref.locale.."_sans.ttf", font)
94 self.font.serif = self.font.serif or self:GetFontPath(QuestHelper_Pref.locale.."_serif.ttf", font) or self.font.sans
95 self.font.fancy = self.font.fancy or self:GetFontPath(QuestHelper_Pref.locale.."_fancy.ttf", font) or self.font.serif
97 self:ReleaseText(font)
99 self.font.sans = self.font.sans or ChatFontNormal:GetFont()
100 self.font.serif = self.font.serif or GameFontNormal:GetFont()
101 self.font.fancy = self.font.fancy or QuestTitleFont:GetFont()
103 -- Need to change the font of the chat frame, for any messages that QuestHelper displays.
104 -- This should do nothing if not using an alternate font.
105 DEFAULT_CHAT_FRAME:SetFont(self.font.sans, select(2, DEFAULT_CHAT_FRAME:GetFont()))
107 if QuestHelperWorldMapButton then
108 QuestHelperWorldMapButton:SetFont(self.font.serif, select(2, QuestHelperWorldMapButton:GetFont()))
112 QuestHelper.route = {}
113 QuestHelper.to_add = {}
114 QuestHelper.to_remove = {}
115 QuestHelper.quest_log = {}
116 QuestHelper.pos = {nil, {}, 0, 0, 1, "You are here.", 0}
117 QuestHelper.sharing = false -- Will be set to true when sharing with at least one user.
119 function QuestHelper.tooltip:GetPrevLines() -- Just a helper to make life easier.
120 local last = self:NumLines()
121 local name = self:GetName()
122 return _G[name.."TextLeft"..last], _G[name.."TextRight"..last]
125 function QuestHelper:SetTargetLocation(i, x, y, toffset)
126 -- Informs QuestHelper that you're going to be at some location in toffset seconds.
127 local c, z = unpack(QuestHelper_ZoneLookup[i])
129 self.target = self:CreateTable()
130 self.target[2] = self:CreateTable()
132 self.target_time = time()+(toffset or 0)
134 x, y = self.Astrolabe:TranslateWorldMapPosition(c, z, x, y, c, 0)
135 self.target[1] = self.zone_nodes[i]
136 self.target[3] = x * self.continent_scales_x[c]
137 self.target[4] = y * self.continent_scales_y[c]
139 for i, n in ipairs(self.target[1]) do
140 local a, b = n.x-self.target[3], n.y-self.target[4]
141 self.target[2][i] = math.sqrt(a*a+b*b)
145 function QuestHelper:UnsetTargetLocation()
146 -- Unsets the target set above.
147 if self.target then
148 self:ReleaseTable(self.target[2])
149 self:ReleaseTable(self.target)
150 self.target = nil
151 self.target_time = nil
155 function QuestHelper:OnEvent(event)
156 if event == "VARIABLES_LOADED" then
157 local file_problem = false
158 local expected_version = GetAddOnMetadata("QuestHelper", "Version")
160 local expected_files =
162 ["upgrade.lua"] = true,
163 ["main.lua"] = true,
164 ["recycle.lua"] = true,
165 ["objective.lua"] = true,
166 ["quest.lua"] = true,
167 ["questlog.lua"] = true,
168 ["utility.lua"] = true,
169 ["dodads.lua"] = true,
170 ["graph.lua"] = true,
171 ["teleport.lua"] = true,
172 ["pathfinding.lua"] = true,
173 ["routing.lua"] = true,
174 ["custom.lua"] = true,
175 ["menu.lua"] = true,
176 ["hidden.lua"] = true,
177 ["nag.lua"] = true,
178 ["comm.lua"] = true,
179 ["mapbutton.lua"] = true,
180 ["help.lua"] = true,
181 ["pattern.lua"] = true,
182 ["flightpath.lua"] = true,
183 ["tracker.lua"] = true,
184 ["objtips.lua"] = true,
185 ["cartographer.lua"] = true,
186 ["tomtom.lua"] = true
189 for file, version in pairs(QuestHelper_File) do
190 if not expected_files[file] then
191 DEFAULT_CHAT_FRAME:AddMessage("Unexpected QuestHelper file: "..file)
192 file_problem = true
193 elseif version ~= expected_version then
194 DEFAULT_CHAT_FRAME:AddMessage("Wrong version of QuestHelper file: "..file.." (found '"..version.."', should be '"..expected_version.."')")
195 if version ~= "Development Version" then
196 -- Developers are allowed to mix dev versions with release versions
197 file_problem = true
202 for file in pairs(expected_files) do
203 if not QuestHelper_File[file] then
204 DEFAULT_CHAT_FRAME:AddMessage("Missing QuestHelper file: "..file)
205 file_problem = true
209 -- Don't need this table anymore.
210 QuestHelper_File = nil
212 if file_problem then
213 DEFAULT_CHAT_FRAME:AddMessage("QuestHelper hasn't been installed properly.")
214 message("QuestHelper hasn't been installed properly.")
215 QuestHelper = nil -- Just in case anybody else is checking for us, we're not home
216 return
219 QHFormatSetLocale(QuestHelper_Pref.locale or GetLocale())
221 if not QuestHelper_UID then
222 QuestHelper_UID = self:CreateUID()
224 QuestHelper_SaveDate = time()
226 QuestHelper_BuildZoneLookup()
228 if QuestHelper_Locale ~= GetLocale() then
229 self:TextOut(QHText("LOCALE_ERROR"))
230 return
233 self.Astrolabe = DongleStub("Astrolabe-0.4")
235 if not self:ZoneSanity() then
236 self:TextOut(QHText("ZONE_LAYOUT_ERROR"))
237 message("QuestHelper: "..QHText("ZONE_LAYOUT_ERROR"))
238 return
241 QuestHelper_UpgradeDatabase(_G)
242 QuestHelper_UpgradeComplete()
244 if QuestHelper_SaveVersion ~= 8 then
245 self:TextOut(QHText("DOWNGRADE_ERROR"))
246 return
249 self.player_level = UnitLevel("player")
251 self:ResetPathing()
253 self:UnregisterEvent("VARIABLES_LOADED")
254 self:RegisterEvent("PLAYER_TARGET_CHANGED")
255 self:RegisterEvent("LOOT_OPENED")
256 self:RegisterEvent("QUEST_COMPLETE")
257 self:RegisterEvent("QUEST_LOG_UPDATE")
258 self:RegisterEvent("QUEST_PROGRESS")
259 self:RegisterEvent("MERCHANT_SHOW")
260 self:RegisterEvent("QUEST_DETAIL")
261 self:RegisterEvent("TAXIMAP_OPENED")
262 self:RegisterEvent("PLAYER_CONTROL_GAINED")
263 self:RegisterEvent("PLAYER_CONTROL_LOST")
264 self:RegisterEvent("PLAYER_LEVEL_UP")
265 self:RegisterEvent("PARTY_MEMBERS_CHANGED")
266 self:RegisterEvent("CHAT_MSG_ADDON")
267 self:RegisterEvent("CHAT_MSG_SYSTEM")
268 self:RegisterEvent("BAG_UPDATE")
269 self:RegisterEvent("GOSSIP_SHOW")
271 self:SetScript("OnUpdate", self.OnUpdate)
273 for key, def in pairs(QuestHelper_DefaultPref) do
274 if QuestHelper_Pref[key] == nil then
275 QuestHelper_Pref[key] = def
279 self:SetLocaleFonts()
281 if QuestHelper_Pref.share and not QuestHelper_Pref.solo then
282 self:EnableSharing()
285 if QuestHelper_Pref.hide then
286 self.map_overlay:Hide()
289 self:HandlePartyChange()
290 self:Nag("all")
292 for locale in pairs(QuestHelper_StaticData) do
293 if locale ~= self.locale then
294 -- Will delete references to locales you don't use.
295 QuestHelper_StaticData[locale] = nil
299 local static = QuestHelper_StaticData[self.locale]
301 if static then
302 if static.flight_instructors then for faction in pairs(static.flight_instructors) do
303 if faction ~= self.faction then
304 -- Will delete references to flight instructors that don't belong to your faction.
305 static.flight_instructors[faction] = nil
307 end end
309 if static.quest then for faction in pairs(static.quest) do
310 if faction ~= self.faction then
311 -- Will delete references to quests that don't belong to your faction.
312 static.quest[faction] = nil
314 end end
317 -- Adding QuestHelper_CharVersion, so I know if I've already converted this characters saved data.
318 if not QuestHelper_CharVersion then
319 -- Changing per-character flight routes, now only storing the flight points they have,
320 -- will attempt to guess the routes from this.
321 local routes = {}
323 for i, l in pairs(QuestHelper_KnownFlightRoutes) do
324 for key in pairs(l) do
325 routes[key] = true
329 QuestHelper_KnownFlightRoutes = routes
331 -- Deleting the player's home again.
332 -- But using the new CharVersion variable I'm adding is cleaner that what I was doing, so I'll go with it.
333 QuestHelper_Home = nil
334 QuestHelper_CharVersion = 1
337 if not QuestHelper_Home then
338 -- Not going to bother complaining about the player's home not being set, uncomment this when the home is used in routing.
339 -- self:TextOut(QHText("HOME_NOT_KNOWN"))
342 self.minimap_dodad = self:CreateMipmapDodad()
344 if QuestHelper_Pref.map_button then
345 QuestHelper:InitMapButton()
348 if QuestHelper_Pref.cart_wp then
349 self:EnableCartographer()
352 if QuestHelper_Pref.tomtom_wp then
353 self:EnableTomTom()
356 self.tracker:SetScale(QuestHelper_Pref.track_scale)
358 if QuestHelper_Pref.track and not QuestHelper_Pref.hide then
359 self.tracker:HideDefaultTracker()
360 self.tracker:Show()
363 local version = GetAddOnMetadata("QuestHelper", "Version") or "Unknown"
364 if QuestHelper_Version ~= version then
365 QuestHelper_Version = version
366 self:ChangeLog()
369 collectgarbage("collect") -- Free everything we aren't using.
371 if self.debug_objectives then
372 for name, data in pairs(self.debug_objectives) do
373 self:LoadDebugObjective(name, data)
378 if event == "GOSSIP_SHOW" then
379 local name, id = UnitName("npc"), self:GetUnitID("npc")
380 if name and id then
381 self:GetObjective("monster", name).o.id = id
382 --self:TextOut("NPC: "..name.." = "..id)
386 if event == "PLAYER_TARGET_CHANGED" then
387 local name, id = UnitName("target"), self:GetUnitID("target")
388 if name and id then
389 self:GetObjective("monster", name).o.id = id
390 --self:TextOut("Target: "..name.." = "..id)
393 if UnitExists("target") and UnitIsVisible("target") and UnitCreatureType("target") ~= "Critter" and not UnitIsPlayer("target") and not UnitPlayerControlled("target") then
394 local index, x, y = self:UnitPosition("target")
396 if index then -- Might not have a position if inside an instance.
397 local w = 0.1
399 -- Modify the weight based on how far they are from us.
400 -- We don't know the exact location (using our own location), so the farther, the less sure we are that it's correct.
401 if CheckInteractDistance("target", 3) then w = 1
402 elseif CheckInteractDistance("target", 2) then w = 0.89
403 elseif CheckInteractDistance("target", 1) or CheckInteractDistance("target", 4) then w = 0.33 end
405 local monster_objective = self:GetObjective("monster", UnitName("target"))
406 self:AppendObjectivePosition(monster_objective, index, x, y, w)
408 monster_objective.o.faction = (UnitFactionGroup("target") == "Alliance" and 1) or
409 (UnitFactionGroup("target") == "Horde" and 2) or nil
411 local level = UnitLevel("target")
412 if level and level >= 1 then
413 local w = monster_objective.o.levelw or 0
414 monster_objective.o.level = ((monster_objective.o.level or 0)*w+level)/(w+1)
415 monster_objective.o.levelw = w+1
421 if event == "LOOT_OPENED" then
422 local target = UnitName("target")
423 if target and UnitIsDead("target") and UnitCreatureType("target") ~= "Critter" and not UnitIsPlayer("target") and not UnitPlayerControlled("target") then
424 local index, x, y = self:UnitPosition("target")
426 local monster_objective = self:GetObjective("monster", target)
427 monster_objective.o.looted = (monster_objective.o.looted or 0) + 1
429 if index then -- Might not have a position if inside an instance.
430 self:AppendObjectivePosition(monster_objective, index, x, y)
433 for i = 1, GetNumLootItems() do
434 local icon, name, number, rarity = GetLootSlotInfo(i)
435 if name then
436 if number and number >= 1 then
437 self:AppendItemObjectiveDrop(self:GetObjective("item", name), name, target, number)
438 else
439 local total = (name:match(COPPER_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) +
440 (name:match(SILVER_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) * 100 +
441 (name:match(GOLD_AMOUNT:gsub("%%d", "%(%%d+%)")) or 0) * 10000
443 if total > 0 then
444 self:AppendObjectiveDrop(self:GetObjective("item", "money"), target, total)
449 else
450 local container = nil
452 -- Go through the players inventory and look for a locked item, we're probably looting it.
453 for bag = 0,NUM_BAG_SLOTS do
454 for slot = 1,GetContainerNumSlots(bag) do
455 local link = GetContainerItemLink(bag, slot)
456 if link and select(3, GetContainerItemInfo(bag, slot)) then
457 if container == nil then
458 -- Found a locked item and haven't previously assigned to container, assign its name, or false if we fail to parse it.
459 container = select(3, string.find(link, "|h%[(.+)%]|h|r")) or false
460 else
461 -- Already tried to assign to a container. If there are multiple locked items, we give up.
462 container = false
468 if container then
469 local container_objective = self:GetObjective("item", container)
470 container_objective.o.opened = (container_objective.o.opened or 0) + 1
472 for i = 1, GetNumLootItems() do
473 local icon, name, number, rarity = GetLootSlotInfo(i)
474 if name and number >= 1 then
475 self:AppendItemObjectiveContainer(self:GetObjective("item", name), container, number)
478 else
479 -- No idea where the items came from.
480 local index, x, y = self:PlayerPosition()
482 if index then
483 for i = 1, GetNumLootItems() do
484 local icon, name, number, rarity = GetLootSlotInfo(i)
485 if name and number >= 1 then
486 self:AppendItemObjectivePosition(self:GetObjective("item", name), name, index, x, y)
494 if event == "CHAT_MSG_SYSTEM" then
495 local home_name = self:convertPattern(ERR_DEATHBIND_SUCCESS_S)(arg1)
496 if home_name then
497 if self.i then
498 self:TextOut(QHText("HOME_CHANGED"))
499 self:TextOut(QHText("WILL_RESET_PATH"))
501 local home = QuestHelper_Home
502 if not home then
503 home = {}
504 QuestHelper_Home = home
507 home[1], home[2], home[3], home[4] = self.i, self.x, self.y, home_name
508 self.defered_graph_reset = true
513 if event == "CHAT_MSG_ADDON" then
514 if arg1 == "QHpr" and (arg3 == "PARTY" or arg3 == "WHISPER") and arg4 ~= UnitName("player") then
515 self:HandleRemoteData(arg2, arg4)
519 if event == "PARTY_MEMBERS_CHANGED" then
520 self:HandlePartyChange()
523 if event == "QUEST_LOG_UPDATE" or
524 event == "PLAYER_LEVEL_UP" or
525 event == "PARTY_MEMBERS_CHANGED" then
526 self.defered_quest_scan = true
529 if event == "QUEST_DETAIL" then
530 if not self.quest_giver then self.quest_giver = {} end
531 local npc = UnitName("npc")
532 if npc then
533 -- Some NPCs aren't actually creatures, and so their positions might not be marked by PLAYER_TARGET_CHANGED.
534 local index, x, y = self:UnitPosition("npc")
536 if index then -- Might not have a position if inside an instance.
537 local npc_objective = self:GetObjective("monster", npc)
538 self:AppendObjectivePosition(npc_objective, index, x, y)
539 self.quest_giver[GetTitleText()] = npc
544 if event == "QUEST_COMPLETE" or event == "QUEST_PROGRESS" then
545 local quest = GetTitleText()
546 if quest then
547 local level, hash = self:GetQuestLevel(quest)
548 if not level or level < 1 then
549 --self:TextOut("Don't know quest level for ".. quest.."!")
550 return
552 local q = self:GetQuest(quest, level, hash)
554 if q.need_hash then
555 q.o.hash = hash
558 local unit = UnitName("npc")
559 if unit then
560 q.o.finish = unit
561 q.o.pos = nil
563 -- Some NPCs aren't actually creatures, and so their positions might not be marked by PLAYER_TARGET_CHANGED.
564 local index, x, y = self:UnitPosition("npc")
565 if index then -- Might not have a position if inside an instance.
566 local npc_objective = self:GetObjective("monster", unit)
567 self:AppendObjectivePosition(npc_objective, index, x, y)
569 elseif not q.o.finish then
570 local index, x, y = self:PlayerPosition()
571 if index then -- Might not have a position if inside an instance.
572 self:AppendObjectivePosition(q, index, x, y)
578 if event == "MERCHANT_SHOW" then
579 local npc_name = UnitName("npc")
580 if npc_name then
581 local npc_objective = self:GetObjective("monster", npc_name)
582 local index = 1
583 while true do
584 local item_name = GetMerchantItemInfo(index)
585 if item_name then
586 index = index + 1
587 local item_objective = self:GetObjective("item", item_name)
588 if not item_objective.o.vendor then
589 item_objective.o.vendor = {npc_name}
590 else
591 local known = false
592 for i, vendor in ipairs(item_objective.o.vendor) do
593 if npc_name == vendor then
594 known = true
595 break
598 if not known then
599 table.insert(item_objective.o.vendor, npc_name)
602 else
603 break
609 if event == "TAXIMAP_OPENED" then
610 self:taxiMapOpened()
613 if event == "PLAYER_CONTROL_GAINED" then
614 self:flightEnded()
617 if event == "PLAYER_CONTROL_LOST" then
618 self:flightBegan()
621 if event == "BAG_UPDATE" then
622 for slot = 1,GetContainerNumSlots(arg1) do
623 local link = GetContainerItemLink(arg1, slot)
624 if link then
625 local id, name = select(3, string.find(link, "|Hitem:(%d+):.-|h%[(.-)%]|h"))
626 if name then
627 self:GetObjective("item", name).o.id = tonumber(id)
634 local map_shown_decay = 0
635 local delayed_action = 100
636 local update_count = 0
638 function QuestHelper:OnUpdate()
640 update_count = update_count - 1
642 if update_count <= 0 then
644 -- Reset the update count for next time around; this will make sure the body executes every time
645 -- when perf_scale >= 1, and down to 1 in 10 iterations when perf_scale < 1, or when hidden.
646 update_count = update_count + (QuestHelper_Pref.hide and 10 or 1/QuestHelper_Pref.perf_scale)
648 if update_count < 0 then
649 -- Make sure the count doesn't go perpetually negative; don't know what will happen if it underflows.
650 update_count = 0
653 if self.Astrolabe.WorldMapVisible then
654 -- We won't trust that the zone returned by Astrolabe is correct until map_shown_decay is 0.
655 map_shown_decay = 2
656 elseif map_shown_decay > 0 then
657 map_shown_decay = map_shown_decay - 1
658 else
659 SetMapToCurrentZone()
662 delayed_action = delayed_action - 1
663 if delayed_action <= 0 then
664 delayed_action = 100
665 self:HandlePartyChange()
669 if not self.graph_in_limbo then
670 local nc, nz, nx, ny = self.Astrolabe:GetCurrentPlayerPosition()
672 if nc and nc == self.c and map_shown_decay > 0 and self.z > 0 and self.z ~= nz then
673 -- There's a chance Astrolable will return the wrong zone if you're messing with the world map, if you can
674 -- be seen in that zone but aren't in it.
675 local nnx, nny = self.Astrolabe:TranslateWorldMapPosition(nc, nz, nx, ny, nc, self.z)
676 if nnx > 0 and nny > 0 and nnx < 1 and nny < 1 then
677 nz, nx, ny = self.z, nnx, nny
681 if nc and nc > 0 and nz == 0 and nc == self.c and self.z > 0 then
682 nx, ny = self.Astrolabe:TranslateWorldMapPosition(nc, nz, nx, ny, nc, self.z)
683 if nx and ny and nx > -0.1 and ny > -0.1 and nx < 1.1 and ny < 1.1 then
684 nz = self.z
685 else
686 nc, nz, nx, ny = nil, nil, nil, nil
690 if nc and nz > 0 then
691 if nc > 0 and nz > 0 then
692 self.c, self.z, self.x, self.y = nc or self.c, nz or self.z, nx or self.x, ny or self.y
693 self.i = QuestHelper_IndexLookup[self.c][self.z]
695 if not self.target then
696 self.pos[3], self.pos[4] = self.Astrolabe:TranslateWorldMapPosition(self.c, self.z, self.x, self.y, self.c, 0)
697 assert(self.pos[3])
698 assert(self.pos[4])
699 self.pos[1] = self.zone_nodes[self.i]
700 self.pos[3] = self.pos[3] * self.continent_scales_x[self.c]
701 self.pos[4] = self.pos[4] * self.continent_scales_y[self.c]
702 for i, n in ipairs(self.pos[1]) do
703 if not n.x then
704 for i, j in pairs(n) do self:TextOut("[%q]=%s %s", i, type(j), tostring(j) or "???") end
705 assert(false)
707 local a, b = n.x-self.pos[3], n.y-self.pos[4]
708 self.pos[2][i] = math.sqrt(a*a+b*b)
714 if self.target then
715 self.pos[1], self.pos[3], self.pos[4] = self.target[1], self.target[3], self.target[4]
716 local extra_time = math.max(0, self.target_time-time())
717 for i in ipairs(self.pos[1]) do
718 self.pos[2][i] = self.target[2][i]+extra_time
723 if self.pos[1] then
724 if self.defered_quest_scan then
725 self.defered_quest_scan = false
726 self:ScanQuestLog()
729 self:RunCoroutine()
732 local level = UnitLevel("player")
733 if level >= 58 and self.player_level < 58 then
734 self.defered_graph_reset = true
736 self.player_level = level
738 self:PumpCommMessages()
742 QuestHelper:RegisterEvent("VARIABLES_LOADED")
743 QuestHelper:SetScript("OnEvent", QuestHelper.OnEvent)