Fix memory leak/performance issue with the map open
[QuestHelper.git] / dodads.lua
blobc13258ecea58a87bc854c609b77298721e1ffeaa
1 QuestHelper_File["dodads.lua"] = "Development Version"
2 QuestHelper_Loadtime["dodads.lua"] = GetTime()
4 local ofs = 0.000723339 * (GetScreenHeight()/GetScreenWidth() + 1/3) * 70.4;
5 local radius = ofs / 1.166666666666667;
6 local Minimap = _G.Minimap
8 -- These conversions are nasty, and this entire section needs a serious cleanup.
9 local function convertLocation(p)
10 local c, x, y = QuestHelper.Astrolabe:FromAbsoluteContinentPosition(p.c, p.x, p.y)
11 return c, 0, x, y
12 end
14 local function convertLocationToScreen(p, c, z)
15 local pc, _, px, py = convertLocation(p)
16 local ox, oy = QuestHelper.Astrolabe:TranslateWorldMapPosition(pc, 0, px, py, c, z)
17 --QuestHelper:TextOut(string.format("%f/%f/%f to %f/%f/%f to %f/%f %f/%f", p.c, p.x, p.y, pc, px, py, c, z, ox, oy))
18 return ox, oy
19 end
21 local function convertRawToScreen(tc, x, y, c, z)
22 local rc, rx, ry = QuestHelper.Astrolabe:FromAbsoluteContinentPosition(tc, x, y)
23 return QuestHelper.Astrolabe:TranslateWorldMapPosition(rc, 0, rx, ry, c, z)
24 end
26 local scrolf = CreateFrame("SCROLLFRAME", nil, WorldMapButton)
27 scrolf:SetFrameLevel(WorldMapButton:GetFrameLevel()+1)
28 scrolf:SetAllPoints()
29 scrolf:SetFrameStrata("FULLSCREEN")
31 local local_high_parent = CreateFrame("FRAME", nil, scrolf)
32 local_high_parent:SetFrameLevel(2)
33 local_high_parent:SetAllPoints()
35 local local_low_parent = CreateFrame("FRAME", nil, scrolf)
36 local_low_parent:SetFrameLevel(1)
37 local_low_parent:SetAllPoints()
39 QuestHelper.map_overlay = CreateFrame("FRAME", nil, scrolf)
40 scrolf:SetScrollChild(QuestHelper.map_overlay)
41 QuestHelper.map_overlay:SetAllPoints()
43 local function ClampLine(x1, y1, x2, y2)
44 if x1 and y1 and x2 and y2 then
45 local x_div, y_div = (x2-x1), (y2-y1)
46 local x_0 = y1-x1/x_div*y_div
47 local x_1 = y1+(1-x1)/x_div*y_div
48 local y_0 = x1-y1/y_div*x_div
49 local y_1 = x1+(1-y1)/y_div*x_div
51 if y1 < 0 then
52 x1 = y_0
53 y1 = 0
54 end
56 if y2 < 0 then
57 x2 = y_0
58 y2 = 0
59 end
61 if y1 > 1 then
62 x1 = y_1
63 y1 = 1
64 end
66 if y2 > 1 then
67 x2 = y_1
68 y2 = 1
69 end
71 if x1 < 0 then
72 y1 = x_0
73 x1 = 0
74 end
76 if x2 < 0 then
77 y2 = x_0
78 x2 = 0
79 end
81 if x1 > 1 then
82 y1 = x_1
83 x1 = 1
84 end
86 if x2 > 1 then
87 y2 = x_1
88 x2 = 1
89 end
91 if x1 >= 0 and x2 >= 0 and y1 >= 0 and y2 >= 0 and x1 <= 1 and x2 <= 1 and y1 <= 1 and y2 <= 1 then
92 return x1, y1, x2, y2
93 end
94 end
95 end
97 local walker_loc
99 function QuestHelper:CreateWorldMapWalker()
100 local walker = CreateFrame("Button", nil, QuestHelper.map_overlay)
101 walker_loc = walker
102 walker:SetWidth(0)
103 walker:SetHeight(0)
104 walker:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", 0, 0)
105 walker:Show()
107 walker.phase = 0.0
108 walker.dots = {}
109 walker.points = {}
110 walker.origin = {}
111 walker.frame = self
112 walker.map_dodads = {}
113 walker.used_map_dodads = 0
115 QuestHelper: Assert(self == QuestHelper)
116 QuestHelper: Assert(self.Astrolabe)
118 function walker:OnUpdate(elapsed)
119 local out = 0
121 if QuestHelper_Pref.show_ants then
122 local points = self.points
124 self.phase = self.phase + elapsed * 0.66
125 while self.phase > 1 do self.phase = self.phase - 1 end
127 local w, h = QuestHelper.map_overlay:GetWidth(), -QuestHelper.map_overlay:GetHeight()
129 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
131 local last_x, last_y = self.frame.Astrolabe:TranslateWorldMapPosition(self.frame.c, self.frame.z, self.frame.x, self.frame.y, c, z)
132 local remainder = self.phase
134 for i, pos in ipairs(points) do
135 local new_x, new_y = unpack(pos)
136 local x1, y1, x2, y2 = ClampLine(last_x, last_y, new_x, new_y)
137 last_x, last_y = new_x, new_y
139 if x1 then
140 local len = math.sqrt((x1-x2)*(x1-x2)*16/9+(y1-y2)*(y1-y2))
142 if len > 0.0001 then
143 local interval = .025/len
144 local p = remainder*interval
146 while p < 1 do
147 out = out + 1
148 local dot = self.dots[out]
149 if not dot then
150 dot = QuestHelper:CreateDotTexture(self)
151 dot:SetDrawLayer("BACKGROUND")
152 self.dots[out] = dot
155 dot:ClearAllPoints()
156 dot:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x1*w*(1-p)+x2*w*p, y1*h*(1-p)+y2*h*p)
158 p = p + interval
161 remainder = (p-1)/interval
167 while #self.dots > out do
168 QuestHelper:ReleaseTexture(table.remove(self.dots))
172 function walker:RouteChanged(route)
173 if route then self.route = route end -- we cache it so we can refer to it later when the world map changes
174 if not self.route then return end
176 local dbgstr = string.format("%s %s %s %s", tostring(self), tostring(self.frame), tostring(QuestHelper), tostring(QuestHelper and QuestHelper.Astrolabe))
177 QuestHelper: Assert(self.frame == QuestHelper, dbgstr)
178 QuestHelper: Assert(QuestHelper.Astrolabe, dbgstr)
180 if self.next_item then
181 self.next_item:MarkAsNext(false)
184 if self.frame.Astrolabe.WorldMapVisible then
185 local points = self.points
186 local cur = self.frame.pos
188 while #points > 0 do self.frame:ReleaseTable(table.remove(points)) end
190 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
192 -- I'm not quite sure what the point of this is.
193 --[[
194 if self.frame.target then
195 travel_time = math.max(0, self.frame.target_time-time())
196 cur = self.frame.target
197 local t = self.frame:CreateTable()
198 t[1], t[2] = convertLocationToScreen(cur, c, z)
199 table.insert(points, t)
200 end]]
202 for i, obj in ipairs(self.route) do
203 --QuestHelper:TextOut(string.format("%s", tostring(obj)))
205 --[[
206 local t = QuestHelper:CreateTable()
207 t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
209 table.insert(list, t)]]
211 -- We're ignoring travel time for now.
212 --[[
213 travel_time = travel_time + 60
214 obj.travel_time = travel_time]]
215 if i > 1 then -- skip the start location
216 local t = self.frame:CreateTable()
217 t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
219 table.insert(points, t)
221 --if lotsup then print(obj.ignore, obj.loc.x, obj.loc.y, obj.loc.c) end
223 --QuestHelper:TextOut(string.format("%s/%s/%s to %s/%s", tostring(obj.c), tostring(obj.x), tostring(obj.y), tostring(t[1]), tostring(t[2])))
225 --lotsup = false
227 local cur_dodad = 1
228 for i = 2, #self.route do -- 2 because we're skipping the player
229 if not self.route[i].ignore then
230 local dodad = self.map_dodads[cur_dodad]
231 if not dodad then
232 self.map_dodads[cur_dodad] = self.frame:CreateWorldMapDodad(self.route[i], i == 2)
233 else
234 self.map_dodads[cur_dodad]:SetObjective(self.route[i], i == 2)
237 if cur_dodad == 1 then
238 self.map_dodads[cur_dodad]:MarkAsNext(true)
240 cur_dodad = cur_dodad + 1
244 if cur_dodad <= self.used_map_dodads then for i = cur_dodad,self.used_map_dodads do
245 self.map_dodads[i]:SetObjective(nil, false)
246 end end
248 self.used_map_dodads = cur_dodad - 1
252 QH_Event("WORLD_MAP_UPDATE", function () walker:RouteChanged() end)
254 QH_Hook(walker, "OnUpdate", walker.OnUpdate)
256 return walker
259 function QuestHelper:GetOverlapObjectives(obj)
260 local w, h = self.map_overlay:GetWidth(), self.map_overlay:GetHeight()
261 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
263 local list = self.overlap_list
265 if not list then
266 list = {}
267 self.overlap_list = list
268 else
269 while table.remove(list) do end
272 local cx, cy = GetCursorPosition()
274 local es = QuestHelper.map_overlay:GetEffectiveScale()
275 local ies = 1/es
277 cx, cy = (cx-self.map_overlay:GetLeft()*es)*ies, (self.map_overlay:GetTop()*es-cy)*ies
279 local s = 10*QuestHelper_Pref.scale
281 for i, o in ipairs(walker_loc.route) do
282 --QuestHelper: Assert(o, string.format("nil dodads pos issue, o %s", tostring(o)))
283 --QuestHelper: Assert(o.pos, string.format("nil dodads pos issue, pos %s", QuestHelper:StringizeTable(o)))
284 if not o.ignore then
285 if o == obj then
286 table.insert(list, o)
287 else
288 local x, y = convertLocationToScreen(o.loc, c, z)
290 if x and y and x > 0 and y > 0 and x < 1 and y < 1 then
291 x, y = x*w, y*h
293 if cx >= x-s and cy >= y-s and cx <= x+s and cy <= y+s then
294 table.insert(list, o)
301 table.sort(list, function(a, b) return (a.distance or 0) < (b.distance or 0) end)
303 return list
306 function QuestHelper:AppendObjectiveProgressToTooltip(o, tooltip, font, depth)
307 if o.progress then
308 local prog_sort_table = {}
310 local theme = self:GetColourTheme()
312 local indent = (" "):rep(depth or 0)
314 for user, progress in pairs(o.progress) do
315 table.insert(prog_sort_table, user)
318 table.sort(prog_sort_table, function(a, b)
319 if o.progress[a][3] < o.progress[b][3] then
320 return true
321 elseif o.progress[a][3] == o.progress[b][3] then
322 return a < b
324 return false
325 end)
327 for i, u in ipairs(prog_sort_table) do
328 tooltip:AddDoubleLine(indent..QHFormat("PEER_PROGRESS", u),
329 self:ProgressString(o.progress[u][1].."/"..o.progress[u][2],
330 o.progress[u][3]), unpack(theme.tooltip))
332 if font then
333 local last, name = tooltip:NumLines(), tooltip:GetName()
334 local left, right = _G[name.."TextLeft"..last], _G[name.."TextRight"..last]
336 left:SetFont(font, 13)
337 right:SetFont(font, 13)
341 while table.remove(prog_sort_table) do end
345 function QuestHelper:AppendObjectiveToTooltip(o)
346 local theme = self:GetColourTheme()
348 QuestHelper: Assert(o.map_desc)
349 for _, v in ipairs(o.map_desc) do
350 self.tooltip:AddLine(v, unpack(theme.tooltip))
351 self.tooltip:GetPrevLines():SetFont(self.font.serif, 14)
354 if o.map_desc_chain then
355 self:AppendObjectiveToTooltip(o.map_desc_chain)
356 else
357 --[[self:AppendObjectiveProgressToTooltip(o, self.tooltip, QuestHelper.font.sans)
359 self.tooltip:AddDoubleLine(QHText("TRAVEL_ESTIMATE"), QHFormat("TRAVEL_ESTIMATE_VALUE", o.distance or 0), unpack(theme.tooltip))
360 self.tooltip:GetPrevLines():SetFont(self.font.sans, 11)
361 select(2, self.tooltip:GetPrevLines()):SetFont(self.font.sans, 11)]]
365 globx = 0.5
366 globy = 0.5
368 local function rightclick_menu(obj)
369 if obj then
370 local menu = QuestHelper:CreateMenu()
371 local list = QuestHelper:GetOverlapObjectives(obj)
372 local item
374 if #list > 1 then
375 QuestHelper:CreateMenuTitle(menu, "Objectives")
377 for i, o in ipairs(list) do
378 local submenu = QuestHelper:CreateMenu()
379 item = QuestHelper:CreateMenuItem(menu, o.map_desc[1])
380 item:SetSubmenu(submenu)
381 item:AddTexture(QuestHelper:CreateIconTexture(item, o.icon_id or 8), true)
382 QuestHelper:AddObjectiveOptionsToMenu(o, submenu)
384 else
385 QuestHelper:CreateMenuTitle(menu, obj.map_desc[1])
386 QuestHelper:AddObjectiveOptionsToMenu(obj, menu)
389 menu:ShowAtCursor()
393 function QuestHelper:CreateWorldMapDodad(objective, nxt)
394 local icon = CreateFrame("Button", nil, QuestHelper.map_overlay)
395 icon:SetFrameStrata("FULLSCREEN")
397 function icon:SetTooltip(list)
398 QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
399 QuestHelper.tooltip:ClearLines()
401 local first = true
403 for i, o in ipairs(list) do
404 if first then
405 first = false
406 else
407 QuestHelper.tooltip:AddLine("|c80ff0000 . . . . . .|r")
408 QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.sans, 8)
411 QuestHelper:AppendObjectiveToTooltip(o)
414 QuestHelper.tooltip:Show()
417 function icon:MarkAsNext(nxt)
418 self.next = nxt
420 QH_Hook(self, "OnUpdate", self.OnUpdate)
423 function icon:SetObjective(objective, nxt)
424 self:SetHeight(20*QuestHelper_Pref.scale)
425 self:SetWidth(20*QuestHelper_Pref.scale)
427 if self.dot then
428 QuestHelper:ReleaseTexture(self.dot)
429 self.dot = nil
432 if self.bg then
433 QuestHelper:ReleaseTexture(self.bg)
434 self.bg = nil
437 if objective then
438 self.objective = objective
440 if nxt then
441 self.bg = QuestHelper:CreateIconTexture(self, 13)
442 elseif objective.map_highlight then
443 self.bg = QuestHelper:CreateIconTexture(self, 14)
444 else
445 self.bg = QuestHelper:CreateIconTexture(self, 16)
448 self.dot = QuestHelper:CreateIconTexture(self, objective.icon_id or 8)
450 self.bg:SetDrawLayer("BACKGROUND")
451 self.bg:SetAllPoints()
452 self.dot:SetPoint("TOPLEFT", self, "TOPLEFT", 3*QuestHelper_Pref.scale, -3*QuestHelper_Pref.scale)
453 self.dot:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3*QuestHelper_Pref.scale, 3*QuestHelper_Pref.scale)
455 QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(objective.loc))
456 --QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, 0, 0, globx, globy)
457 else
458 self.objective = nil
459 self:Hide()
463 local triangle_r, triangle_g, triangle_b = 1.0, 0.3, 0
464 local triangle_opacity = 0.6
466 function icon:CreateTriangles(solid, tritarget, tristartat, linetarget, linestartat, parent)
467 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
469 local function makeline(ax, ay, bx, by)
470 local tri = linetarget[linestartat]
471 if not tri then
472 tri = CreateLine(parent)
473 table.insert(linetarget, tri)
475 linestartat = linestartat + 1
477 tri:SetLine(ax, ay, bx, by)
478 tri:SetVertexColor(0, 0, 0, 0)
479 tri:Show()
482 for _, v in ipairs(solid) do
483 local adjx, adjy = v[1], v[2]
484 local x, y = convertRawToScreen(v.continent, v[1], v[2], c, z)
485 --print("matchup", c, v.continent, x, y)
486 if x and y then
487 local lx, ly = convertRawToScreen(v.continent, adjx + v[3], adjy + v[4], c, z)
488 local linemode = false
490 local lidx = 5
491 while lidx <= #v do
492 if type(v[lidx]) == "string" then
493 if v[lidx] == "d" then
494 lidx = lidx + 1
495 x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
496 lx, ly = convertRawToScreen(v.continent, adjx + v[lidx + 2], adjy + v[lidx + 3], c, z)
497 lidx = lidx + 4
498 elseif v[lidx] == "l" then
499 linemode = true
500 lidx = lidx + 1
501 x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
502 lx, ly = x, y
503 lidx = lidx + 2
504 else
505 QuestHelper: Assert(false)
507 else
508 if not linemode then
509 local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
511 local tri = tritarget[tristartat]
512 if not tri then
513 tri = CreateTriangle(parent)
514 table.insert(tritarget, tri)
516 tristartat = tristartat + 1
518 tri:SetTriangle(x, y, lx, ly, tx, ty)
519 tri:SetVertexColor(0, 0, 0, 0)
520 tri:Show()
522 lx, ly = tx, ty
523 lidx = lidx + 2
524 else
525 local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
527 makeline(x, y, tx, ty)
529 x, y = tx, ty
530 lidx = lidx + 2
535 if linemode then
536 makeline(x, y, lx, ly)
541 return tristartat, linestartat
544 function icon:SetGlow(list)
545 local w, h = QuestHelper.map_overlay:GetWidth(), QuestHelper.map_overlay:GetHeight()
546 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
547 local zw = QuestHelper.Astrolabe:GetZoneWidth(c, z)
549 local solids = {}
551 local gid = 1
552 for _, v in ipairs(list) do
553 --print(v.cluster, v.cluster and v.cluster.solid)
554 if v.cluster and v.cluster.solid then
555 --print("solidified", #v.cluster.solid)
556 solids[v.cluster.solid] = true
557 else
558 local x, y = convertLocationToScreen(v.loc, c, z)
559 if not self.glow_list then
560 self.glow_list = QuestHelper:CreateTable()
562 local glo = self.glow_list[gid]
563 if not glo then
564 glo = QuestHelper:CreateGlowTexture(self)
565 self.glow_list[gid] = glo
567 gid = gid + 1
569 glo:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x*w, -y*h)
570 glo:SetVertexColor(triangle_r, triangle_g, triangle_b, 1)
571 glo:SetWidth(h / 20)
572 glo:SetHeight(h / 20)
573 glo:Show()
577 local tid = 1
578 local lid = 1
580 for k, _ in pairs(solids) do
581 if not self.triangle_list then
582 self.triangle_list = QuestHelper:CreateTable()
584 if not self.line_list then
585 self.line_list = QuestHelper:CreateTable()
588 tid, lid = self:CreateTriangles(k, self.triangle_list, tid, self.line_list, lid, local_low_parent)
590 -- call triangle maker here!
592 if self.triangle_list then
593 while #self.triangle_list >= tid do
594 ReleaseTriangle(table.remove(self.triangle_list))
597 if #self.triangle_list == 0 then
598 QuestHelper:ReleaseTable(self.triangle_list)
599 self.triangle_list = nil
603 if self.glow_list then
604 while #self.glow_list >= gid do
605 QuestHelper:ReleaseTexture(table.remove(self.glow_list))
608 if #self.glow_list == 0 then
609 QuestHelper:ReleaseTable(self.glow_list)
610 self.glow_list = nil
614 if self.line_list then
615 while #self.line_list >= lid do
616 ReleaseLine(table.remove(self.line_list))
619 if #self.line_list == 0 then
620 QuestHelper:ReleaseTable(self.line_list)
621 self.line_list = nil
626 icon.show_glow = false
627 icon.glow_pct = 0.0
628 icon.phase = 0.0
629 icon.old_count = 0
631 function icon:OnUpdate(elapsed)
632 self.phase = (self.phase + elapsed)%6.283185307179586476925286766559005768394338798750211641949889185
634 if self.next and self.objective and self.objective.cluster.solid then
636 local c, z = GetCurrentMapContinent(), GetCurrentMapZone()
637 if self.tri_c ~= c or self.tri_z ~= z then
638 -- not entirely happy with this being here, but, welp
639 if not self.local_triangle_list then
640 self.local_triangle_list = QuestHelper:CreateTable()
642 if not self.local_line_list then
643 self.local_line_list = QuestHelper:CreateTable()
646 local tid, lid = self:CreateTriangles(self.objective.cluster.solid, self.local_triangle_list, 1, self.local_line_list, 1, local_high_parent)
648 if self.local_triangle_list then
649 while #self.local_triangle_list >= tid do
650 ReleaseTriangle(table.remove(self.local_triangle_list))
654 if self.local_line_list then
655 while #self.local_line_list >= lid do
656 ReleaseLine(table.remove(self.local_line_list))
661 self.tri_c, self.tri_z = c, z
662 else
663 if self.local_triangle_list then
664 while #self.local_triangle_list > 0 do
665 ReleaseTriangle(table.remove(self.local_triangle_list))
667 QuestHelper:ReleaseTable(self.local_triangle_list)
668 self.local_triangle_list = nil
671 if self.local_line_list then
672 while #self.local_line_list > 0 do
673 ReleaseLine(table.remove(self.local_line_list))
675 QuestHelper:ReleaseTable(self.local_line_list)
676 self.local_line_list = nil
679 self.tri_c, self.tri_z = nil, nil
682 if self.old_count > 0 then
683 local list = QuestHelper:GetOverlapObjectives(self.objective)
685 if #list ~= self.old_count then
686 self:SetTooltip(list)
687 self.old_count = #list
688 self:SetGlow(list)
692 if self.show_glow then
693 self.glow_pct = math.min(1, self.glow_pct+elapsed*1.5)
694 else
695 self.glow_pct = math.max(0, self.glow_pct-elapsed*0.5)
697 if self.glow_pct == 0 then
698 if self.triangle_list then
699 while #self.triangle_list > 0 do
700 ReleaseTriangle(table.remove(self.triangle_list))
702 QuestHelper:ReleaseTable(self.triangle_list)
703 self.triangle_list = nil
706 if self.glow_list then
707 while #self.glow_list > 0 do
708 QuestHelper:ReleaseTexture(table.remove(self.glow_list))
710 QuestHelper:ReleaseTable(self.glow_list)
711 self.glow_list = nil
714 if self.line_list then
715 while #self.line_list > 0 do
716 ReleaseLine(table.remove(self.line_list))
718 QuestHelper:ReleaseTable(self.line_list)
719 self.line_list = nil
722 if not self.next then QH_Hook(self, "OnUpdate", nil) end
726 if self.triangle_list then
727 for _, tri in ipairs(self.triangle_list) do
728 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity/2)
731 if self.line_list then
732 for _, tri in ipairs(self.line_list) do
733 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
736 if self.glow_list then
737 for _, tri in ipairs(self.glow_list) do
738 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
741 if self.local_triangle_list then
742 for _, tri in ipairs(self.local_triangle_list) do
743 tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity/2)
746 if self.local_line_list then
747 for _, tri in ipairs(self.local_line_list) do
748 tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity)
753 function icon:OnEnter()
754 local list = QuestHelper:GetOverlapObjectives(self.objective)
755 self:SetTooltip(list)
756 self.old_count = #list
758 icon.show_glow = true
760 self:SetGlow(list)
762 QH_Hook(self, "OnUpdate", self.OnUpdate)
765 function icon:OnLeave()
766 QuestHelper.tooltip:Hide()
767 self.show_glow = false
768 self.old_count = 0
771 function icon:OnEvent()
772 if self.objective then
773 QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(self.objective.loc))
774 else
775 self.objective = nil
776 self:Hide()
780 function icon:OnClick()
781 rightclick_menu(self.objective)
784 QH_Hook(icon, "OnClick", icon.OnClick)
785 QH_Hook(icon, "OnEnter", icon.OnEnter)
786 QH_Hook(icon, "OnLeave", icon.OnLeave)
787 QH_Hook(icon, "OnEvent", icon.OnEvent)
789 icon:RegisterForClicks("RightButtonUp")
791 QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end)
793 icon:SetObjective(objective, nxt)
794 return icon
797 local callbacks = {}
798 local last_c, last_z, last_x, last_y, last_desc
800 function QuestHelper:AddWaypointCallback(func, ...)
801 local cb = self:CreateTable()
802 callbacks[cb] = true
803 local len = select("#", ...)
804 cb.len = len
805 cb.func = func
806 for i = 1,len do cb[i] = select(i, ...) end
807 cb[len+1] = last_c
808 cb[len+2] = last_z
809 cb[len+3] = last_x
810 cb[len+4] = last_y
811 cb[len+5] = last_desc
813 if last_c then
814 func(unpack(cb, 1, len+5))
817 return cb
820 function QuestHelper:RemoveWaypointCallback(cb)
821 callbacks[cb] = nil
822 self:ReleaseTable(cb)
825 function QuestHelper:InvokeWaypointCallbacks(c, z, x, y, desc)
826 QuestHelper: Assert(not c or type(c) == "number")
827 QuestHelper: Assert(not z or type(z) == "number")
828 QuestHelper: Assert(not x or type(x) == "number")
829 QuestHelper: Assert(not y or type(y) == "number")
830 if c == last_c and z == last_z and desc == last_desc and not x and not y then x, y = last_x, last_y end -- sometimes we may not have up-to-date location, but could still in theory be pointing at the same spot
832 if not c or (x and y) then
833 if c ~= last_c or z ~= last_z or x ~= last_x or y ~= last_y or desc ~= last_desc then
834 last_c, last_z, last_x, last_y, last_desc = c, z, x, y, desc
835 for cb in pairs(callbacks) do
836 local len = cb.len
837 cb[len+1] = c
838 cb[len+2] = z
839 cb[len+3] = x
840 cb[len+4] = y
841 cb[len+5] = desc
842 cb.func(unpack(cb, 1, len+5))
848 function QuestHelper:SetMinimapObject(minimap)
849 Minimap = minimap
850 QuestHelper.Astrolabe:SetMinimapObject(minimap)
851 QuestHelper.minimap_marker:SetParent(minimap)
852 QuestHelper.Astrolabe.processingFrame:SetParent(minimap)
855 --[[ Small parts of the arrow rendering code are thanks to Tomtom, with the following license:
857 -------------------------------------------------------------------------
858 Copyright (c) 2006-2007, James N. Whitehead II
859 All rights reserved.
861 Redistribution and use in source and binary forms, with or without
862 modification, are permitted provided that the following conditions are
863 met:
865 * Redistributions of source code must retain the above copyright
866 notice, this list of conditions and the following disclaimer.
867 * Redistributions in binary form must reproduce the above
868 copyright notice, this list of conditions and the following
869 disclaimer in the documentation and/or other materials provided
870 with the distribution.
871 * The name or alias of the copyright holder may not be used to endorse
872 or promote products derived from this software without specific prior
873 written permission.
875 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
876 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
877 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
878 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
879 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
880 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
881 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
882 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
883 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
884 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
885 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
886 ---------------------------------------------------------------------------]]
888 function QuestHelper:CreateMipmapDodad()
889 local icon = CreateFrame("Button", nil, Minimap)
890 icon:Hide()
891 icon.recalc_timeout = 0
893 icon.arrow = icon:CreateTexture("BACKGROUND")
894 icon.arrow:SetHeight(40)
895 icon.arrow:SetWidth(40)
896 icon.arrow:SetPoint("CENTER", 0, 0)
897 icon.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\MinimapArrow")
898 icon.arrow:Hide()
900 icon.phase = 0
901 icon.target = {0, 0, 0, 0}
903 icon.bg = QuestHelper:CreateIconTexture(icon, 16)
904 icon.bg:SetDrawLayer("BACKGROUND")
905 icon.bg:SetAllPoints()
907 function icon:OnUpdate(elapsed)
908 local c, z, x, y, textdesc
909 if self.obj then
910 c, z = QuestHelper.collect_rc, QuestHelper.collect_rz
911 if c and z then
912 x, y = convertLocationToScreen(self.obj.loc, c, z)
915 if self.obj.map_desc_chain then
916 -- the first line will just be an "enroute" line
917 textdesc = self.obj.map_desc[1] .. "\n" .. self.obj.map_desc_chain.map_desc[1]
918 else
919 textdesc = self.obj.map_desc[1]
923 QuestHelper: Assert(not c or type(c) == "number")
924 QuestHelper: Assert(not z or type(z) == "number")
926 -- Deal with waypoint callbacks
927 if QuestHelper_Pref.hide or UnitIsDeadOrGhost("player") and not QuestHelper.InBrokenInstance then
928 QuestHelper:InvokeWaypointCallbacks()
929 else
930 QuestHelper:InvokeWaypointCallbacks(c, z, x, y, textdesc)
933 if self.obj and not QuestHelper.InBrokenInstance then
934 self:Show() -- really only triggers if the non-broken-instance code is being poked
936 if not QuestHelper_Pref.hide and QuestHelper.Astrolabe:PlaceIconOnMinimap(self, convertLocation(self.obj.loc)) ~= -1 then
937 local edge = QuestHelper.Astrolabe:IsIconOnEdge(self)
939 if edge then
940 self.arrow:Show()
941 self.dot:Hide()
942 self.bg:Hide()
943 else
944 self.arrow:Hide()
945 self.dot:Show()
946 self.bg:Show()
949 if edge then
950 local angle = QuestHelper.Astrolabe:GetDirectionToIcon(self)
951 if GetCVar("rotateMinimap") == "1" then
952 angle = angle + QuestHelper.Astrolabe:GetFacing()
955 if elapsed then
956 if self.phase > 6.283185307179586476925 then
957 self.phase = self.phase-6.283185307179586476925+elapsed*3.5
958 else
959 self.phase = self.phase+elapsed*3.5
963 local scale = 1.0 + 0.1 * math.sin(self.phase)
965 local x, y = scale * math.sin(angle + 3.14159 * 0.75) * math.sqrt(0.5), scale * math.cos(angle + 3.14159 * 0.75) * math.sqrt(0.5)
966 self.arrow:SetTexCoord(0.5 - x, 0.5 + y, 0.5 + y, 0.5 + x, 0.5 - y, 0.5 - x, 0.5 + x, 0.5 - y)
968 else
969 self:Hide()
971 else
972 self:Hide()
976 function icon:SetObjective(obj)
977 self:SetHeight(20*QuestHelper_Pref.scale)
978 self:SetWidth(20*QuestHelper_Pref.scale)
980 if obj ~= self.obj then
981 self.obj = obj
983 self.recalc_timeout = 0
985 if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end
987 if self.obj then
988 self.dot = QuestHelper:CreateIconTexture(self, self.obj.icon_id or 8)
989 self.dot:SetPoint("TOPLEFT", icon, "TOPLEFT", 2, -2)
990 self.dot:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -2, 2)
993 self:OnUpdate()
997 function icon:OnEnter()
998 if self.obj then
999 QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
1000 QuestHelper.tooltip:ClearLines()
1002 --[[if self.target[5] then
1003 QuestHelper.tooltip:AddLine(QHFormat("WAYPOINT_REASON", self.target[5]), unpack(QuestHelper:GetColourTheme().tooltip))
1004 QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.serif, 14)
1005 end]]
1007 QuestHelper:AppendObjectiveToTooltip(self.obj)
1008 QuestHelper.tooltip:Show()
1012 function icon:OnLeave()
1013 QuestHelper.tooltip:Hide()
1016 function icon:OnClick()
1017 rightclick_menu(self.obj)
1020 function icon:OnEvent()
1021 if self.obj then
1022 self:Show()
1023 else
1024 self:Hide()
1028 QH_Hook(icon, "OnUpdate", icon.OnUpdate)
1029 QH_Hook(icon, "OnEnter", icon.OnEnter)
1030 QH_Hook(icon, "OnLeave", icon.OnLeave)
1031 QH_Hook(icon, "OnClick", icon.OnClick)
1033 icon:RegisterForClicks("RightButtonUp")
1035 QH_Event("PLAYER_ENTERING_WORLD", function () icon:OnEvent() end)
1037 return icon