Merge branch 'master' into translations
[QuestHelper.git] / dodads.lua
blob75e8f19c43ec27522508c5561cc84486ed095e4d
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 QuestHelper.map_overlay = CreateFrame("FRAME", nil, scrolf)
32 scrolf:SetScrollChild(QuestHelper.map_overlay)
33 QuestHelper.map_overlay:SetAllPoints()
35 QuestHelper.map_overlay_uncropped = scrolf
37 local function ClampLine(x1, y1, x2, y2)
38 if x1 and y1 and x2 and y2 then
39 local x_div, y_div = (x2-x1), (y2-y1)
40 local x_0 = y1-x1/x_div*y_div
41 local x_1 = y1+(1-x1)/x_div*y_div
42 local y_0 = x1-y1/y_div*x_div
43 local y_1 = x1+(1-y1)/y_div*x_div
45 if y1 < 0 then
46 x1 = y_0
47 y1 = 0
48 end
50 if y2 < 0 then
51 x2 = y_0
52 y2 = 0
53 end
55 if y1 > 1 then
56 x1 = y_1
57 y1 = 1
58 end
60 if y2 > 1 then
61 x2 = y_1
62 y2 = 1
63 end
65 if x1 < 0 then
66 y1 = x_0
67 x1 = 0
68 end
70 if x2 < 0 then
71 y2 = x_0
72 x2 = 0
73 end
75 if x1 > 1 then
76 y1 = x_1
77 x1 = 1
78 end
80 if x2 > 1 then
81 y2 = x_1
82 x2 = 1
83 end
85 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
86 return x1, y1, x2, y2
87 end
88 end
89 end
91 local walker_loc
93 function QuestHelper:CreateWorldMapWalker()
94 if not self.Astrolabe or not QuestHelper then return end
95 QuestHelper: Assert(self == QuestHelper)
96 QuestHelper: Assert(self.Astrolabe)
98 local walker = CreateFrame("Button", nil, QuestHelper.map_overlay)
99 walker_loc = walker
100 walker:SetWidth(0)
101 walker:SetHeight(0)
102 walker:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", 0, 0)
103 walker:Show()
105 walker.phase = 0.0
106 walker.dots = {}
107 walker.points = {}
108 walker.origin = {}
109 walker.frame = self
110 walker.map_dodads = {}
111 walker.used_map_dodads = 0
113 function walker:OnUpdate(elapsed)
114 local out = 0
116 if QuestHelper_Pref.show_ants then
117 local points = self.points
119 self.phase = self.phase + elapsed * 0.66
120 while self.phase > 1 do self.phase = self.phase - 1 end
122 local w, h = QuestHelper.map_overlay:GetWidth(), -QuestHelper.map_overlay:GetHeight()
124 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
126 local last_x, last_y = self.frame.Astrolabe:TranslateWorldMapPosition(self.frame.c, self.frame.z, self.frame.x, self.frame.y, c, z)
127 local remainder = self.phase
129 for i, pos in ipairs(points) do
130 local new_x, new_y = unpack(pos)
131 local x1, y1, x2, y2 = ClampLine(last_x, last_y, new_x, new_y)
132 last_x, last_y = new_x, new_y
134 if x1 then
135 local len = math.sqrt((x1-x2)*(x1-x2)*16/9+(y1-y2)*(y1-y2))
137 if len > 0.0001 then
138 local interval = .025/len
139 local p = remainder*interval
141 while p < 1 do
142 out = out + 1
143 local dot = self.dots[out]
144 if not dot then
145 dot = QuestHelper:CreateDotTexture(self)
146 dot:SetDrawLayer("BACKGROUND")
147 self.dots[out] = dot
150 dot:ClearAllPoints()
151 dot:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x1*w*(1-p)+x2*w*p, y1*h*(1-p)+y2*h*p)
153 p = p + interval
156 remainder = (p-1)/interval
162 while #self.dots > out do
163 QuestHelper:ReleaseTexture(table.remove(self.dots))
167 function walker:RouteChanged(route)
168 if route then self.route = route end -- we cache it so we can refer to it later when the world map changes
169 if not self.route then return end
171 local dbgstr = string.format("%s %s %s %s", tostring(self), tostring(self.frame), tostring(QuestHelper), tostring(QuestHelper and QuestHelper.Astrolabe))
172 QuestHelper: Assert(self.frame == QuestHelper, dbgstr)
173 QuestHelper: Assert(QuestHelper.Astrolabe, dbgstr)
175 if self.next_item then
176 self.next_item:MarkAsNext(false)
177 self.next_item = nil
180 if self.frame.Astrolabe.WorldMapVisible then
181 local points = self.points
182 local cur = self.frame.pos
184 while #points > 0 do self.frame:ReleaseTable(table.remove(points)) end
186 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
188 -- I'm not quite sure what the point of this is.
189 --[[
190 if self.frame.target then
191 travel_time = math.max(0, self.frame.target_time-time())
192 cur = self.frame.target
193 local t = self.frame:CreateTable()
194 t[1], t[2] = convertLocationToScreen(cur, c, z)
195 table.insert(points, t)
196 end]]
198 for i, obj in ipairs(self.route) do
199 --QuestHelper:TextOut(string.format("%s", tostring(obj)))
201 --[[
202 local t = QuestHelper:CreateTable()
203 t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
205 table.insert(list, t)]]
207 -- We're ignoring travel time for now.
208 --[[
209 travel_time = travel_time + 60
210 obj.travel_time = travel_time]]
211 if i > 1 then -- skip the start location
212 local t = self.frame:CreateTable()
213 t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
215 table.insert(points, t)
217 --if lotsup then print(obj.ignore, obj.loc.x, obj.loc.y, obj.loc.c) end
219 --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])))
221 --lotsup = false
223 local cur_dodad = 1
224 for i = 2, #self.route do -- 2 because we're skipping the player
225 if not self.route[i].ignore or qh_hackery_show_all_map_nodes then
226 local dodad = self.map_dodads[cur_dodad]
227 if not dodad then
228 self.map_dodads[cur_dodad] = self.frame:CreateWorldMapDodad(self.route[i], i == 2)
229 else
230 self.map_dodads[cur_dodad]:SetObjective(self.route[i], i == 2)
233 if cur_dodad == 1 then
234 self.map_dodads[cur_dodad]:MarkAsNext(true)
235 self.next_item = self.map_dodads[cur_dodad]
237 cur_dodad = cur_dodad + 1
241 if cur_dodad <= self.used_map_dodads then for i = cur_dodad,self.used_map_dodads do
242 self.map_dodads[i]:SetObjective(nil, false)
243 end end
245 self.used_map_dodads = cur_dodad - 1
249 QH_Event("WORLD_MAP_UPDATE", function () walker:RouteChanged() end)
251 QH_Hook(walker, "OnUpdate", walker.OnUpdate)
253 return walker
256 function QuestHelper:GetOverlapObjectives(obj)
257 local w, h = self.map_overlay:GetWidth(), self.map_overlay:GetHeight()
258 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
260 local list = self.overlap_list
262 if not list then
263 list = {}
264 self.overlap_list = list
265 else
266 while table.remove(list) do end
269 local cx, cy = GetCursorPosition()
271 local es = QuestHelper.map_overlay:GetEffectiveScale()
272 local ies = 1/es
274 cx, cy = (cx-self.map_overlay:GetLeft()*es)*ies, (self.map_overlay:GetTop()*es-cy)*ies
276 local s = 10*QuestHelper_Pref.scale
278 for i, o in ipairs(walker_loc.route) do
279 --QuestHelper: Assert(o, string.format("nil dodads pos issue, o %s", tostring(o)))
280 --QuestHelper: Assert(o.pos, string.format("nil dodads pos issue, pos %s", QuestHelper:StringizeTable(o)))
281 if not o.ignore or qh_hackery_show_all_map_nodes then
282 if o == obj then
283 table.insert(list, o)
284 else
285 local x, y = convertLocationToScreen(o.loc, c, z)
287 if x and y and x > 0 and y > 0 and x < 1 and y < 1 then
288 x, y = x*w, y*h
290 if cx >= x-s and cy >= y-s and cx <= x+s and cy <= y+s then
291 table.insert(list, o)
298 table.sort(list, function(a, b) return (a.distance or 0) < (b.distance or 0) end)
300 return list
303 function QuestHelper:AppendObjectiveProgressToTooltip(o, tooltip, font, depth)
304 if o.progress then
305 local prog_sort_table = {}
307 local theme = self:GetColourTheme()
309 local indent = (" "):rep(depth or 0)
311 for user, progress in pairs(o.progress) do
312 table.insert(prog_sort_table, user)
315 table.sort(prog_sort_table, function(a, b)
316 if o.progress[a][3] < o.progress[b][3] then
317 return true
318 elseif o.progress[a][3] == o.progress[b][3] then
319 return a < b
321 return false
322 end)
324 for i, u in ipairs(prog_sort_table) do
325 tooltip:AddDoubleLine(indent..QHFormat("PEER_PROGRESS", u),
326 self:ProgressString(o.progress[u][1].."/"..o.progress[u][2],
327 o.progress[u][3]), unpack(theme.tooltip))
329 if font then
330 local last, name = tooltip:NumLines(), tooltip:GetName()
331 local left, right = _G[name.."TextLeft"..last], _G[name.."TextRight"..last]
333 left:SetFont(font, 13)
334 right:SetFont(font, 13)
338 while table.remove(prog_sort_table) do end
342 function QuestHelper:AppendObjectiveToTooltip(o)
343 local theme = self:GetColourTheme()
345 QuestHelper: Assert(o.map_desc)
346 for _, v in ipairs(o.map_desc) do
347 self.tooltip:AddLine(v, unpack(theme.tooltip))
348 self.tooltip:GetPrevLines():SetFont(self.font.serif, 14)
351 if o.map_desc_chain then
352 self:AppendObjectiveToTooltip(o.map_desc_chain)
353 else
354 self:AppendObjectiveProgressToTooltip(o, self.tooltip, QuestHelper.font.sans)
356 if QuestHelper_Pref.travel_time then
357 self.tooltip:AddDoubleLine(QHText("TRAVEL_ESTIMATE"), QHFormat("TRAVEL_ESTIMATE_VALUE", o.distance or 0), unpack(theme.tooltip))
358 self.tooltip:GetPrevLines():SetFont(self.font.sans, 11)
363 globx = 0.5
364 globy = 0.5
366 function QH_Append_NextObjective(menu)
367 local obj = QuestHelper.minimap_marker.obj
368 if not obj then return end
370 QuestHelper:AddObjectiveOptionsToMenu(obj, menu)
373 local function rightclick_menu(obj)
374 if obj then
375 local menu = QuestHelper:CreateMenu()
376 local list = QuestHelper:GetOverlapObjectives(obj)
377 local item
379 if #list > 1 then
380 QuestHelper:CreateMenuTitle(menu, "Objectives")
382 for i, o in ipairs(list) do
383 local submenu = QuestHelper:CreateMenu()
384 item = QuestHelper:CreateMenuItem(menu, o.map_desc[1])
385 item:SetSubmenu(submenu)
386 item:AddTexture(QuestHelper:CreateIconTexture(item, o.icon_id or 8), true)
387 QuestHelper:AddObjectiveOptionsToMenu(o, submenu)
389 else
390 QuestHelper:CreateMenuTitle(menu, obj.map_desc[1])
391 QuestHelper:AddObjectiveOptionsToMenu(obj, menu)
394 menu:ShowAtCursor()
398 function QuestHelper:CreateWorldMapDodad(objective, nxt)
399 local icon = CreateFrame("Button", nil, QuestHelper.map_overlay)
400 icon:SetFrameStrata("FULLSCREEN")
402 function icon:SetTooltip(list)
403 QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
404 QuestHelper.tooltip:ClearLines()
406 local first = true
408 for i, o in ipairs(list) do
409 if first then
410 first = false
411 else
412 QuestHelper.tooltip:AddLine("|c80ff0000 . . . . . .|r")
413 QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.sans, 8)
416 QuestHelper:AppendObjectiveToTooltip(o)
419 QuestHelper.tooltip:Show()
422 function icon:MarkAsNext(nxt)
423 self.next = nxt
425 QH_Hook(self, "OnUpdate", self.OnUpdate)
428 function icon:SetObjective(objective, nxt)
429 self:SetHeight(20*QuestHelper_Pref.scale)
430 self:SetWidth(20*QuestHelper_Pref.scale)
432 if self.dot then
433 QuestHelper:ReleaseTexture(self.dot)
434 self.dot = nil
437 if self.bg then
438 QuestHelper:ReleaseTexture(self.bg)
439 self.bg = nil
442 if objective then
443 self.objective = objective
445 if nxt then
446 self.bg = QuestHelper:CreateIconTexture(self, 13)
447 elseif objective.map_highlight then
448 self.bg = QuestHelper:CreateIconTexture(self, 14)
449 else
450 self.bg = QuestHelper:CreateIconTexture(self, 16)
453 self.dot = QuestHelper:CreateIconTexture(self, objective.icon_id or 8)
455 self.bg:SetDrawLayer("BACKGROUND")
456 self.bg:SetAllPoints()
457 self.dot:SetPoint("TOPLEFT", self, "TOPLEFT", 3*QuestHelper_Pref.scale, -3*QuestHelper_Pref.scale)
458 self.dot:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3*QuestHelper_Pref.scale, 3*QuestHelper_Pref.scale)
460 QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(objective.loc))
461 --QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, 0, 0, globx, globy)
462 else
463 self.objective = nil
464 self:Hide()
465 self.next = false
466 self:OnUpdate(0)
470 local triangle_r, triangle_g, triangle_b = 1.0, 0.3, 0
471 local triangle_opacity = 0.6
473 function icon:CreateTriangles(solid, tritarget, tristartat, linetarget, linestartat, parent)
474 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
476 local function makeline(ax, ay, bx, by)
477 local tri = linetarget[linestartat]
478 if not tri then
479 tri = CreateLine(parent)
480 table.insert(linetarget, tri)
482 linestartat = linestartat + 1
484 tri:SetLine(ax, ay, bx, by)
485 tri:SetVertexColor(0, 0, 0, 0)
486 tri:Show()
489 for _, v in ipairs(solid) do
490 local adjx, adjy = v[1], v[2]
491 local x, y = convertRawToScreen(v.continent, v[1], v[2], c, z)
492 --print("matchup", c, v.continent, x, y)
493 if x and y then
494 local lx, ly = convertRawToScreen(v.continent, adjx + v[3], adjy + v[4], c, z)
495 local linemode = false
497 local lidx = 5
498 while lidx <= #v do
499 if type(v[lidx]) == "string" then
500 if v[lidx] == "d" then
501 QuestHelper: Assert(type(lidx) == "number") -- what
502 lidx = lidx + 1
503 x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
504 lx, ly = convertRawToScreen(v.continent, adjx + v[lidx + 2], adjy + v[lidx + 3], c, z)
505 lidx = lidx + 4
506 elseif v[lidx] == "l" then
507 linemode = true
508 lidx = lidx + 1
509 x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
510 lx, ly = x, y
511 lidx = lidx + 2
512 else
513 QuestHelper: Assert(false)
515 else
516 if not linemode then
517 local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
519 local tri = tritarget[tristartat]
520 if not tri then
521 tri = CreateTriangle(parent)
522 table.insert(tritarget, tri)
524 tristartat = tristartat + 1
526 tri:SetTriangle(x, y, lx, ly, tx, ty)
527 tri:SetVertexColor(0, 0, 0, 0)
528 tri:Show()
530 lx, ly = tx, ty
531 lidx = lidx + 2
532 else
533 local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
535 makeline(x, y, tx, ty)
537 x, y = tx, ty
538 lidx = lidx + 2
543 if linemode then
544 makeline(x, y, lx, ly)
549 return tristartat, linestartat
552 function icon:SetGlow(list)
553 local w, h = QuestHelper.map_overlay:GetWidth(), QuestHelper.map_overlay:GetHeight()
554 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
555 local zw = QuestHelper.Astrolabe:GetZoneWidth(c, z)
557 local solids = {}
559 local gid = 1
560 for _, v in ipairs(list) do
561 --print(v.cluster, v.cluster and v.cluster.solid)
562 if v.cluster and v.cluster.solid then
563 --print("solidified", #v.cluster.solid)
564 solids[v.cluster.solid] = true
565 else
566 local x, y = convertLocationToScreen(v.loc, c, z)
567 if x and y then
568 if not self.glow_list then
569 self.glow_list = QuestHelper:CreateTable()
571 local glo = self.glow_list[gid]
572 if not glo then
573 glo = QuestHelper:CreateGlowTexture(self)
574 self.glow_list[gid] = glo
576 gid = gid + 1
578 glo:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x*w, -y*h)
579 glo:SetVertexColor(triangle_r, triangle_g, triangle_b, 1)
580 glo:SetWidth(h / 20)
581 glo:SetHeight(h / 20)
582 glo:Show()
587 local tid = 1
588 local lid = 1
590 for k, _ in pairs(solids) do
591 if not self.triangle_list then
592 self.triangle_list = QuestHelper:CreateTable()
594 if not self.line_list then
595 self.line_list = QuestHelper:CreateTable()
598 tid, lid = self:CreateTriangles(k, self.triangle_list, tid, self.line_list, lid, QuestHelper.map_overlay)
600 -- call triangle maker here!
602 if self.triangle_list then
603 while #self.triangle_list >= tid do
604 ReleaseTriangle(table.remove(self.triangle_list))
607 if #self.triangle_list == 0 then
608 QuestHelper:ReleaseTable(self.triangle_list)
609 self.triangle_list = nil
613 if self.glow_list then
614 while #self.glow_list >= gid do
615 QuestHelper:ReleaseTexture(table.remove(self.glow_list))
618 if #self.glow_list == 0 then
619 QuestHelper:ReleaseTable(self.glow_list)
620 self.glow_list = nil
624 if self.line_list then
625 while #self.line_list >= lid do
626 ReleaseLine(table.remove(self.line_list))
629 if #self.line_list == 0 then
630 QuestHelper:ReleaseTable(self.line_list)
631 self.line_list = nil
636 icon.show_glow = false
637 icon.glow_pct = 0.0
638 icon.phase = 0.0
639 icon.old_count = 0
641 function icon:OnUpdate(elapsed)
642 self.phase = (self.phase + elapsed)%6.283185307179586476925286766559005768394338798750211641949889185
644 if self.next and self.objective and self.objective.cluster.solid and QuestHelper_Pref.zones == "next" then
646 local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
647 if self.tri_c ~= c or self.tri_z ~= z then
648 -- not entirely happy with this being here, but, welp
649 if not self.local_triangle_list then
650 self.local_triangle_list = QuestHelper:CreateTable()
652 if not self.local_line_list then
653 self.local_line_list = QuestHelper:CreateTable()
656 local tid, lid = self:CreateTriangles(self.objective.cluster.solid, self.local_triangle_list, 1, self.local_line_list, 1, QuestHelper.map_overlay)
658 if self.local_triangle_list then
659 while #self.local_triangle_list >= tid do
660 ReleaseTriangle(table.remove(self.local_triangle_list))
664 if self.local_line_list then
665 while #self.local_line_list >= lid do
666 ReleaseLine(table.remove(self.local_line_list))
671 self.tri_c, self.tri_z = c, z
672 else
673 if self.local_triangle_list then
674 while #self.local_triangle_list > 0 do
675 ReleaseTriangle(table.remove(self.local_triangle_list))
677 QuestHelper:ReleaseTable(self.local_triangle_list)
678 self.local_triangle_list = nil
681 if self.local_line_list then
682 while #self.local_line_list > 0 do
683 ReleaseLine(table.remove(self.local_line_list))
685 QuestHelper:ReleaseTable(self.local_line_list)
686 self.local_line_list = nil
689 self.tri_c, self.tri_z = nil, nil
692 if self.old_count > 0 then
693 local list = QuestHelper:GetOverlapObjectives(self.objective)
695 if #list ~= self.old_count then
696 self:SetTooltip(list)
697 self.old_count = #list
698 self:SetGlow(list)
702 if self.show_glow then
703 self.glow_pct = math.min(1, self.glow_pct+elapsed*1.5)
704 else
705 self.glow_pct = math.max(0, self.glow_pct-elapsed*0.5)
707 if self.glow_pct == 0 then
708 if self.triangle_list then
709 while #self.triangle_list > 0 do
710 ReleaseTriangle(table.remove(self.triangle_list))
712 QuestHelper:ReleaseTable(self.triangle_list)
713 self.triangle_list = nil
716 if self.glow_list then
717 while #self.glow_list > 0 do
718 QuestHelper:ReleaseTexture(table.remove(self.glow_list))
720 QuestHelper:ReleaseTable(self.glow_list)
721 self.glow_list = nil
724 if self.line_list then
725 while #self.line_list > 0 do
726 ReleaseLine(table.remove(self.line_list))
728 QuestHelper:ReleaseTable(self.line_list)
729 self.line_list = nil
732 if not self.next then
733 QH_Hook(self, "OnUpdate", nil)
738 if self.triangle_list then
739 for _, tri in ipairs(self.triangle_list) do
740 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity/2)
743 if self.line_list then
744 for _, tri in ipairs(self.line_list) do
745 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
748 if self.glow_list then
749 for _, tri in ipairs(self.glow_list) do
750 tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
753 if self.local_triangle_list then
754 for _, tri in ipairs(self.local_triangle_list) do
755 tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity/2)
758 if self.local_line_list then
759 for _, tri in ipairs(self.local_line_list) do
760 tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity)
765 function icon:OnEnter()
766 local list = QuestHelper:GetOverlapObjectives(self.objective)
767 self:SetTooltip(list)
768 self.old_count = #list
770 icon.show_glow = true
772 self:SetGlow(list)
774 QH_Hook(self, "OnUpdate", self.OnUpdate)
777 function icon:OnLeave()
778 QuestHelper.tooltip:Hide()
779 self.show_glow = false
780 self.old_count = 0
783 function icon:OnEvent()
784 if self.objective then
785 QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(self.objective.loc))
786 else
787 self.objective = nil
788 self:Hide()
792 function icon:OnClick()
793 rightclick_menu(self.objective)
796 QH_Hook(icon, "OnClick", icon.OnClick)
797 QH_Hook(icon, "OnEnter", icon.OnEnter)
798 QH_Hook(icon, "OnLeave", icon.OnLeave)
799 QH_Hook(icon, "OnEvent", icon.OnEvent)
801 icon:RegisterForClicks("RightButtonUp")
803 QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end)
805 icon:SetObjective(objective, nxt)
806 return icon
809 local callbacks = {}
810 local last_c, last_z, last_x, last_y, last_desc
812 function QuestHelper:AddWaypointCallback(func, ...)
813 local cb = self:CreateTable()
814 callbacks[cb] = true
815 local len = select("#", ...)
816 cb.len = len
817 cb.func = func
818 for i = 1,len do cb[i] = select(i, ...) end
819 cb[len+1] = last_c
820 cb[len+2] = last_z
821 cb[len+3] = last_x
822 cb[len+4] = last_y
823 cb[len+5] = last_desc
825 if last_c then
826 func(unpack(cb, 1, len+5))
829 return cb
832 function QuestHelper:RemoveWaypointCallback(cb)
833 callbacks[cb] = nil
834 self:ReleaseTable(cb)
837 function QuestHelper:InvokeWaypointCallbacks(c, z, x, y, desc)
838 QuestHelper: Assert(not c or type(c) == "number")
839 QuestHelper: Assert(not z or type(z) == "number")
840 QuestHelper: Assert(not x or type(x) == "number")
841 QuestHelper: Assert(not y or type(y) == "number")
842 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
844 if not c or (x and y) then
845 if c ~= last_c or z ~= last_z or x ~= last_x or y ~= last_y or desc ~= last_desc then
846 last_c, last_z, last_x, last_y, last_desc = c, z, x, y, desc
847 for cb in pairs(callbacks) do
848 local len = cb.len
849 cb[len+1] = c
850 cb[len+2] = z
851 cb[len+3] = x
852 cb[len+4] = y
853 cb[len+5] = desc
854 cb.func(unpack(cb, 1, len+5))
860 function QuestHelper:SetMinimapObject(minimap)
861 Minimap = minimap
862 QuestHelper.Astrolabe:SetMinimapObject(minimap)
863 QuestHelper.minimap_marker:SetParent(minimap)
864 QuestHelper.Astrolabe.processingFrame:SetParent(minimap)
867 --[[ Small parts of the arrow rendering code are thanks to Tomtom, with the following license:
869 -------------------------------------------------------------------------
870 Copyright (c) 2006-2007, James N. Whitehead II
871 All rights reserved.
873 Redistribution and use in source and binary forms, with or without
874 modification, are permitted provided that the following conditions are
875 met:
877 * Redistributions of source code must retain the above copyright
878 notice, this list of conditions and the following disclaimer.
879 * Redistributions in binary form must reproduce the above
880 copyright notice, this list of conditions and the following
881 disclaimer in the documentation and/or other materials provided
882 with the distribution.
883 * The name or alias of the copyright holder may not be used to endorse
884 or promote products derived from this software without specific prior
885 written permission.
887 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
888 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
889 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
890 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
891 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
892 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
893 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
894 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
895 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
896 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
897 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
898 ---------------------------------------------------------------------------]]
900 function QuestHelper:CreateMipmapDodad()
901 local icon = CreateFrame("Button", nil, Minimap)
902 icon:Hide()
903 icon.recalc_timeout = 0
905 icon.arrow = icon:CreateTexture("BACKGROUND")
906 icon.arrow:SetHeight(40)
907 icon.arrow:SetWidth(40)
908 icon.arrow:SetPoint("CENTER", 0, 0)
909 icon.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\MinimapArrow")
910 icon.arrow:Hide()
912 icon.phase = 0
913 icon.target = {0, 0, 0, 0}
915 icon.bg = QuestHelper:CreateIconTexture(icon, 16)
916 icon.bg:SetDrawLayer("BACKGROUND")
917 icon.bg:SetAllPoints()
919 function icon:OnUpdate(elapsed)
920 local c, z, x, y, textdesc
921 if self.obj then
922 c, z = QuestHelper.collect_rc, QuestHelper.collect_rz
923 if c and z then
924 x, y = convertLocationToScreen(self.obj.loc, c, z)
927 if self.obj.map_desc_chain then
928 -- the first line will just be an "enroute" line
929 textdesc = self.obj.map_desc[1] .. "\n" .. self.obj.map_desc_chain.map_desc[1]
930 else
931 textdesc = self.obj.map_desc[1]
935 QuestHelper: Assert(not c or type(c) == "number")
936 QuestHelper: Assert(not z or type(z) == "number")
938 -- Deal with waypoint callbacks
939 if QuestHelper_Pref.hide or UnitIsDeadOrGhost("player") and not QuestHelper.InBrokenInstance then
940 QuestHelper:InvokeWaypointCallbacks()
941 else
942 QuestHelper:InvokeWaypointCallbacks(c, z, x, y, textdesc)
945 if self.obj and not QuestHelper.InBrokenInstance then
946 self:Show() -- really only triggers if the non-broken-instance code is being poked
948 if not QuestHelper_Pref.hide and QuestHelper.Astrolabe:PlaceIconOnMinimap(self, convertLocation(self.obj.loc)) ~= -1 then
949 local edge = QuestHelper.Astrolabe:IsIconOnEdge(self)
951 if edge then
952 self.arrow:Show()
953 self.dot:Hide()
954 self.bg:Hide()
955 else
956 self.arrow:Hide()
957 self.dot:Show()
958 self.bg:Show()
960 self.dot:SetAlpha(QuestHelper_Pref.mini_opacity)
961 self.bg:SetAlpha(QuestHelper_Pref.mini_opacity)
964 if edge then
965 local angle = QuestHelper.Astrolabe:GetDirectionToIcon(self)
966 if GetCVar("rotateMinimap") == "1" then
967 angle = angle + QuestHelper.Astrolabe:GetFacing()
970 if elapsed then
971 if self.phase > 6.283185307179586476925 then
972 self.phase = self.phase-6.283185307179586476925+elapsed*3.5
973 else
974 self.phase = self.phase+elapsed*3.5
978 local scale = 1.0 + 0.1 * math.sin(self.phase)
980 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)
981 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)
983 else
984 self:Hide()
986 else
987 self:Hide()
991 function icon:SetObjective(obj)
992 self:SetHeight(20*QuestHelper_Pref.scale)
993 self:SetWidth(20*QuestHelper_Pref.scale)
995 if obj ~= self.obj then
996 self.obj = obj
998 self.recalc_timeout = 0
1000 if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end
1002 if self.obj then
1003 self.dot = QuestHelper:CreateIconTexture(self, self.obj.icon_id or 8)
1004 self.dot:SetPoint("TOPLEFT", icon, "TOPLEFT", 2, -2)
1005 self.dot:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -2, 2)
1008 self:OnUpdate(0)
1012 function icon:OnEnter()
1013 if self.obj then
1014 QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
1015 QuestHelper.tooltip:ClearLines()
1017 --[[if self.target[5] then
1018 QuestHelper.tooltip:AddLine(QHFormat("WAYPOINT_REASON", self.target[5]), unpack(QuestHelper:GetColourTheme().tooltip))
1019 QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.serif, 14)
1020 end]]
1022 QuestHelper:AppendObjectiveToTooltip(self.obj)
1023 QuestHelper.tooltip:Show()
1027 function icon:OnLeave()
1028 QuestHelper.tooltip:Hide()
1031 function icon:OnClick()
1032 rightclick_menu(self.obj)
1035 function icon:OnEvent()
1036 if self.obj then
1037 self:Show()
1038 else
1039 self:Hide()
1043 QH_Hook(icon, "OnUpdate", icon.OnUpdate)
1044 QH_Hook(icon, "OnEnter", icon.OnEnter)
1045 QH_Hook(icon, "OnLeave", icon.OnLeave)
1046 QH_Hook(icon, "OnClick", icon.OnClick)
1048 icon:RegisterForClicks("RightButtonUp")
1050 QH_Event("PLAYER_ENTERING_WORLD", function () icon:OnEvent() end)
1052 return icon