Proper support for metric distances.
[QuestHelper.git] / arrow.lua
blobc68a091fa3f677088b503dafcb888a8fd91327a9
1 QuestHelper_File["arrow.lua"] = "Development Version"
2 QuestHelper_Loadtime["arrow.lua"] = GetTime()
4 --[[ This entire file is pretty liberally ganked from TomTom (and then modified) under the following license:
6 -------------------------------------------------------------------------
7 Copyright (c) 2006-2007, James N. Whitehead II
8 All rights reserved.
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions are
12 met:
14 * Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the following
18 disclaimer in the documentation and/or other materials provided
19 with the distribution.
20 * The name or alias of the copyright holder may not be used to endorse
21 or promote products derived from this software without specific prior
22 written permission.
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 ---------------------------------------------------------------------------
37 Thanks, James! <3 ]]
39 local function ColorGradient(perc, ...)
40 local num = select("#", ...)
41 local hexes = type(select(1, ...)) == "string"
43 if perc == 1 then
44 return select(num-2, ...), select(num-1, ...), select(num, ...)
45 end
47 num = num / 3
49 local segment, relperc = math.modf(perc*(num-1))
50 local r1, g1, b1, r2, g2, b2
51 r1, g1, b1 = select((segment*3)+1, ...), select((segment*3)+2, ...), select((segment*3)+3, ...)
52 r2, g2, b2 = select((segment*3)+4, ...), select((segment*3)+5, ...), select((segment*3)+6, ...)
54 if not r2 or not g2 or not b2 then
55 return r1, g1, b1
56 else
57 return r1 + (r2-r1)*relperc,
58 g1 + (g2-g1)*relperc,
59 b1 + (b2-b1)*relperc
60 end
61 end
63 local wayframe = CreateFrame("Button", "QHArrowFrame", UIParent)
64 wayframe:SetPoint("CENTER", -300, 300)
65 wayframe:EnableMouse(true)
66 wayframe:SetMovable(true)
67 wayframe:SetUserPlaced(true)
68 wayframe:Hide()
70 wif = wayframe
72 -- Frame used to control the scaling of the title and friends
73 local titleframe = CreateFrame("Frame", nil, wayframe)
75 wayframe.title = titleframe:CreateFontString("OVERLAY", nil, "GameFontNormalSmall")
76 wayframe.status = titleframe:CreateFontString("OVERLAY", nil, "GameFontNormalSmall")
77 wayframe.tta = titleframe:CreateFontString("OVERLAY", nil, "GameFontNormalSmall")
78 wayframe.title:SetPoint("TOP", wayframe, "BOTTOM", 0, 0)
79 wayframe.status:SetPoint("TOP", wayframe.title, "BOTTOM", 0, 0)
80 wayframe.tta:SetPoint("TOP", wayframe.status, "BOTTOM", 0, 0)
81 local default_font_name, default_font_size, default_font_flags = wayframe.title:GetFont()
84 local r, g, b, a = wayframe.status:GetTextColor()
85 r, g, b = r - 0.2, g - 0.2, b - 0.2
86 wayframe.status:SetTextColor(r, g, b, a)
87 end
89 local OnUpdate
91 local function OnDragStart(self, button)
92 if not QuestHelper_Pref.arrow_locked then -- TODO TWEAKERY
93 self:StartMoving()
94 end
95 end
97 local function OnDragStop(self, button)
98 self:StopMovingOrSizing()
99 end
101 local function OnEvent(self, event, ...)
102 if event == "ZONE_CHANGED_NEW_AREA" and QuestHelper_Pref.arrow and not QuestHelper_Pref.hide then -- TODO TWEAKERY
103 self:Show()
104 OnUpdate(self, nil)
108 wayframe:SetScript("OnDragStart", OnDragStart)
109 wayframe:SetScript("OnDragStop", OnDragStop)
110 wayframe:RegisterForDrag("LeftButton")
111 wayframe:RegisterEvent("ZONE_CHANGED_NEW_AREA")
112 wayframe:SetScript("OnEvent", OnEvent)
114 wayframe.arrow = wayframe:CreateTexture("OVERLAY")
115 --wayframe.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image_down") -- if we don't do this, the image doesn't seem to end up cached. :blizzard:
116 wayframe.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image")
117 wayframe.arrow:SetAllPoints()
119 local active_point, arrive_distance, showDownArrow, point_title
120 active_point = {}
122 function QH_Arrow_Show()
123 wayframe:Show()
126 function QH_Arrow_Reset()
127 QuestHelper_Pref.arrow = true
128 wayframe:ClearAllPoints()
129 wayframe:SetPoint("CENTER", 0, 0)
130 QuestHelper_Pref.arrow_locked = false -- they're probably going to want to move it
131 QH_Arrow_Show()
134 function QH_Arrow_SetScale(scale)
135 if scale then
136 QuestHelper_Pref.arrow_arrowsize = scale
137 else
138 scale = QuestHelper_Pref.arrow_arrowsize
141 if not showDownArrow then
142 wayframe:SetHeight(42 * scale)
143 wayframe:SetWidth(56 * scale)
144 else
145 scale = scale * 0.8
146 wayframe:SetHeight(70 * scale)
147 wayframe:SetWidth(53 * scale)
151 function QH_Arrow_SetTextScale(scale)
152 if scale then
153 QuestHelper_Pref.arrow_textsize = scale
154 else
155 scale = QuestHelper_Pref.arrow_textsize
158 wayframe.title:SetFont(default_font_name, default_font_size * scale, default_font_flags)
159 wayframe.status:SetFont(default_font_name, default_font_size * scale, default_font_flags)
160 wayframe.tta:SetFont(default_font_name, default_font_size * scale, default_font_flags)
163 local function wpupdate(c, z, x, y, desc)
164 if c then
165 QuestHelper: Assert(z)
166 QuestHelper: Assert(x)
167 QuestHelper: Assert(y)
168 else
169 QuestHelper: Assert(not z)
170 QuestHelper: Assert(not x)
171 QuestHelper: Assert(not y)
173 active_point.c, active_point.z, active_point.x, active_point.y = c, z, x, y
174 wayframe.title:SetText(desc)
175 wayframe:Show()
176 OnUpdate(wayframe, nil)
179 QuestHelper:AddWaypointCallback(wpupdate)
181 local status = wayframe.status
182 local tta = wayframe.tta
183 local arrow = wayframe.arrow
184 local last_distance = 0
185 local tta_throttle = 0
186 local speed = 0
187 local speed_count = 0
189 OnUpdate = function(self, elapsed)
190 QuestHelper: Assert(self)
192 if not active_point.c or QuestHelper.collect_rc ~= active_point.c or QuestHelper.collect_delayed or QuestHelper.InBrokenInstance or not QuestHelper_Pref.arrow then
193 self:Hide()
194 return
197 local dist, dx, dy = QuestHelper.Astrolabe:ComputeDistance(QuestHelper.collect_rc, QuestHelper.collect_rz, QuestHelper.collect_rx, QuestHelper.collect_ry, active_point.c, active_point.z, active_point.x, active_point.y)
199 local text = ""
201 if dist then
202 -- I had support for miles and kilometers, but decided that distances were rarely large
203 -- enough to warrent it.
204 if QuestHelper_Pref.metric then
205 text = QHFormat("DISTANCE_METRES", math.floor(0.5+dist*0.9144))
206 else
207 text = QHFormat("DISTANCE_YARDS", math.floor(0.5 + dist))
211 status:SetText(text)
213 -- Showing the arrival arrow?
214 if dist and dist <= 10 then
215 if not showDownArrow then
216 showDownArrow = true
217 QH_Arrow_SetScale()
218 arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image_down")
219 arrow:SetVertexColor(0, 1, 0)
222 local cell = math.floor(mod(GetTime() * 20, 55)) -- 20 fps seems to be around the right number
224 local column = cell % 9
225 local row = floor(cell / 9)
227 local xstart = (column * 53) / 512
228 local ystart = (row * 70) / 512
229 local xend = ((column + 1) * 53) / 512
230 local yend = ((row + 1) * 70) / 512
231 arrow:SetTexCoord(xstart,xend,ystart,yend)
232 else
233 if showDownArrow then
234 showDownArrow = false
235 QH_Arrow_SetScale()
236 arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image")
237 showDownArrow = false
240 local angle = atan2(-dx, -dy) / 360 * (math.pi * 2) -- degrees. seriously what
241 --if angle < 0 then angle = angle + math.pi * 2 end
242 local player = GetPlayerFacing()
243 angle = angle - player
245 local perc = math.abs((math.pi - math.abs(angle)) / math.pi)
246 if perc > 1 then perc = 2 - perc end -- siiigh
248 local gr,gg,gb = 0, 1, 0
249 local mr,mg,mb = 1, 1, 0
250 local br,bg,bb = 1, 0, 0
251 local r,g,b = ColorGradient(perc, br, bg, bb, mr, mg, mb, gr, gg, gb)
252 arrow:SetVertexColor(r,g,b)
255 local cell = floor(angle / (math.pi * 2) * 108 + 0.5) % 108
256 local column = cell % 9
257 local row = floor(cell / 9)
259 local xstart = (column * 56) / 512
260 local ystart = (row * 42) / 512
261 local xend = ((column + 1) * 56) / 512
262 local yend = ((row + 1) * 42) / 512
263 arrow:SetTexCoord(xstart,xend,ystart,yend)
266 -- Calculate the TTA every second (%01d:%02d)
268 --[[
269 if elapsed then
270 tta_throttle = tta_throttle + elapsed
272 if tta_throttle >= 1.0 then
273 -- Calculate the speed in yards per sec at which we're moving
274 local current_speed = (last_distance - dist) / tta_throttle
276 if last_distance == 0 then
277 current_speed = 0
280 if speed_count < 2 then
281 speed = (speed + current_speed) / 2
282 speed_count = speed_count + 1
283 else
284 speed_count = 0
285 speed = current_speed
288 if speed > 0 then
289 local eta = math.abs(dist / speed)
290 tta:SetFormattedText("%01d:%02d", eta / 60, eta % 60)
291 else
292 tta:SetText("")
295 last_distance = dist
296 tta_throttle = 0
302 wayframe:SetScript("OnUpdate", OnUpdate)
305 local function spacer()
306 local htex = QuestHelper:CreateIconTexture(item, 10)
307 htex:SetVertexColor(1, 1, 1, 0)
308 return htex
311 function QH_Arrow_PopulateMenu(menu)
312 local hide = QuestHelper:CreateMenuItem(menu, QuestHelper_Pref.arrow and QHText("QH_BUTTON_HIDE") or QHText("QH_BUTTON_SHOW"))
313 hide:SetFunction(function () QuestHelper:ToggleArrow() end)
314 --hide:AddTexture(spacer(), true)
315 --hide:AddTexture(spacer(), false)
317 local lock = QuestHelper:CreateMenuItem(menu, "Lock")
318 local ltex = QuestHelper:CreateIconTexture(item, 10)
319 lock:SetFunction(function () QuestHelper_Pref.arrow_locked = not QuestHelper_Pref.arrow_locked end)
320 lock:AddTexture(ltex, true)
321 lock:AddTexture(spacer(), false)
322 ltex:SetVertexColor(1, 1, 1, QuestHelper_Pref.arrow_locked and 1 or 0)
324 local scale = QuestHelper:CreateMenuItem(menu, "Arrow Scale")
325 local scale_menu = QuestHelper:CreateMenu()
326 scale:SetSubmenu(scale_menu)
327 scale:AddTexture(spacer(), true)
328 for i = 5, 15 do
329 local it = QuestHelper:CreateMenuItem(scale_menu, string.format("%d%%", i * 10))
330 local ix = i
331 it:SetFunction(function () QH_Arrow_SetScale(ix / 10) end)
332 local icon = QuestHelper:CreateIconTexture(item, 10)
333 if QuestHelper_Pref.arrow_arrowsize == ix / 10 then
334 icon:SetVertexColor(1, 1, 1, 1)
335 else
336 icon:SetVertexColor(1, 1, 1, 0)
338 it:AddTexture(icon)
341 local tscale = QuestHelper:CreateMenuItem(menu, "Text Scale")
342 local tscale_menu = QuestHelper:CreateMenu()
343 tscale:SetSubmenu(tscale_menu)
344 tscale:AddTexture(spacer(), true)
345 for i = 5, 15 do
346 local it = QuestHelper:CreateMenuItem(tscale_menu, string.format("%d%%", i * 10))
347 local ix = i
348 it:SetFunction(function () QH_Arrow_SetTextScale(ix / 10) end)
349 local icon = QuestHelper:CreateIconTexture(item, 10)
350 if QuestHelper_Pref.arrow_textsize == ix / 10 then
351 icon:SetVertexColor(1, 1, 1, 1)
352 else
353 icon:SetVertexColor(1, 1, 1, 0)
355 it:AddTexture(icon)
358 local reset = QuestHelper:CreateMenuItem(menu, QHText("SETTINGS_MENU_ARROW_RESET"))
359 reset:SetFunction(function () QH_Arrow_Reset() end)
362 local function WayFrame_OnClick(self, button)
363 local menu = QuestHelper:CreateMenu()
364 QuestHelper:CreateMenuTitle(menu, QHText("SETTINGS_ARROWLINK_ARROW"))
366 QH_Arrow_PopulateMenu(menu)
368 menu:ShowAtCursor()
371 wayframe:RegisterForClicks("RightButtonUp")
372 wayframe:SetScript("OnClick", WayFrame_OnClick)