Merge branch 'master' into translations
[QuestHelper.git] / arrow.lua
blobbcad4ff951704cb746c9337a679350bfc6d9ba94
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 QH_Event("ZONE_CHANGED_NEW_AREA", function ()
102 if QuestHelper_Pref.arrow and not QuestHelper_Pref.hide then -- TODO TWEAKERY
103 wayframe:Show()
104 OnUpdate()
106 end)
108 QH_Hook(wayframe, "OnDragStart", OnDragStart)
109 QH_Hook(wayframe, "OnDragStop", OnDragStop)
110 wayframe:RegisterForDrag("LeftButton")
112 wayframe.arrow = wayframe:CreateTexture("OVERLAY")
113 --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:
114 wayframe.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image")
115 wayframe.arrow:SetAllPoints()
117 local active_point, arrive_distance, showDownArrow, point_title
118 active_point = {}
120 function QH_Arrow_Show()
121 wayframe:Show()
124 function QH_Arrow_Reset()
125 QuestHelper_Pref.arrow = true
126 wayframe:ClearAllPoints()
127 wayframe:SetPoint("CENTER", 0, 0)
128 QuestHelper_Pref.arrow_locked = false -- they're probably going to want to move it
129 QH_Arrow_Show()
132 function QH_Arrow_SetScale(scale)
133 if scale then
134 QuestHelper_Pref.arrow_arrowsize = scale
135 else
136 scale = QuestHelper_Pref.arrow_arrowsize
139 if not showDownArrow then
140 wayframe:SetHeight(42 * scale)
141 wayframe:SetWidth(56 * scale)
142 else
143 scale = scale * 0.8
144 wayframe:SetHeight(70 * scale)
145 wayframe:SetWidth(53 * scale)
149 function QH_Arrow_SetTextScale(scale)
150 if scale then
151 QuestHelper_Pref.arrow_textsize = scale
152 else
153 scale = QuestHelper_Pref.arrow_textsize
156 wayframe.title:SetFont(default_font_name, default_font_size * scale, default_font_flags)
157 wayframe.status:SetFont(default_font_name, default_font_size * scale, default_font_flags)
158 wayframe.tta:SetFont(default_font_name, default_font_size * scale, default_font_flags)
161 local function wpupdate(c, z, x, y, desc)
162 if c then
163 QuestHelper: Assert(z)
164 QuestHelper: Assert(x)
165 QuestHelper: Assert(y)
166 else
167 QuestHelper: Assert(not z)
168 QuestHelper: Assert(not x)
169 QuestHelper: Assert(not y)
171 active_point.c, active_point.z, active_point.x, active_point.y = c, z, x, y
172 wayframe.title:SetText(desc)
173 wayframe:Show()
174 OnUpdate()
177 QuestHelper:AddWaypointCallback(wpupdate)
179 local status = wayframe.status
180 local tta = wayframe.tta
181 local arrow = wayframe.arrow
182 local last_distance = 0
183 local tta_throttle = 0
184 local speed = 0
185 local speed_count = 0
187 OnUpdate = function()
188 local self = wayframe
189 QuestHelper: Assert(self)
191 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
192 self:Hide()
193 return
196 self:Show()
198 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)
200 local text = ""
202 if dist then
203 -- I had support for miles and kilometers, but decided that distances were rarely large
204 -- enough to warrent it.
205 if QuestHelper_Pref.metric then
206 text = QHFormat("DISTANCE_METRES", math.floor(0.5+dist*0.9144))
207 else
208 text = QHFormat("DISTANCE_YARDS", math.floor(0.5 + dist))
212 status:SetText(text)
214 -- Showing the arrival arrow?
215 if dist and dist <= 10 then
216 if not showDownArrow then
217 showDownArrow = true
218 QH_Arrow_SetScale()
219 arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image_down")
220 arrow:SetVertexColor(0, 1, 0)
223 local cell = math.floor(mod(GetTime() * 20, 55)) -- 20 fps seems to be around the right number
225 local column = cell % 9
226 local row = floor(cell / 9)
228 local xstart = (column * 53) / 512
229 local ystart = (row * 70) / 512
230 local xend = ((column + 1) * 53) / 512
231 local yend = ((row + 1) * 70) / 512
232 arrow:SetTexCoord(xstart,xend,ystart,yend)
233 else
234 if showDownArrow then
235 showDownArrow = false
236 QH_Arrow_SetScale()
237 arrow:SetTexture("Interface\\AddOns\\QuestHelper\\arrow_image")
238 showDownArrow = false
241 local angle = atan2(-dx, -dy) / 360 * (math.pi * 2) -- degrees. seriously what
242 --if angle < 0 then angle = angle + math.pi * 2 end
243 local player = GetPlayerFacing()
244 angle = angle - player
246 local perc = math.abs((math.pi - math.abs(angle)) / math.pi)
247 if perc > 1 then perc = 2 - perc end -- siiigh
249 local gr,gg,gb = 0, 1, 0
250 local mr,mg,mb = 1, 1, 0
251 local br,bg,bb = 1, 0, 0
252 local r,g,b = ColorGradient(perc, br, bg, bb, mr, mg, mb, gr, gg, gb)
253 arrow:SetVertexColor(r,g,b)
256 local cell = floor(angle / (math.pi * 2) * 108 + 0.5) % 108
257 local column = cell % 9
258 local row = floor(cell / 9)
260 local xstart = (column * 56) / 512
261 local ystart = (row * 42) / 512
262 local xend = ((column + 1) * 56) / 512
263 local yend = ((row + 1) * 42) / 512
264 arrow:SetTexCoord(xstart,xend,ystart,yend)
267 -- Calculate the TTA every second (%01d:%02d)
269 --[[
270 if elapsed then
271 tta_throttle = tta_throttle + elapsed
273 if tta_throttle >= 1.0 then
274 -- Calculate the speed in yards per sec at which we're moving
275 local current_speed = (last_distance - dist) / tta_throttle
277 if last_distance == 0 then
278 current_speed = 0
281 if speed_count < 2 then
282 speed = (speed + current_speed) / 2
283 speed_count = speed_count + 1
284 else
285 speed_count = 0
286 speed = current_speed
289 if speed > 0 then
290 local eta = math.abs(dist / speed)
291 tta:SetFormattedText("%01d:%02d", eta / 60, eta % 60)
292 else
293 tta:SetText("")
296 last_distance = dist
297 tta_throttle = 0
303 QH_Hook(wayframe, "OnUpdate", OnUpdate)
306 local function spacer()
307 local htex = QuestHelper:CreateIconTexture(item, 10)
308 htex:SetVertexColor(1, 1, 1, 0)
309 return htex
312 function QH_Arrow_PopulateMenu(menu)
313 local hide = QuestHelper:CreateMenuItem(menu, QuestHelper_Pref.arrow and QHText("QH_BUTTON_HIDE") or QHText("QH_BUTTON_SHOW"))
314 hide:SetFunction(function () QuestHelper:ToggleArrow() end)
315 --hide:AddTexture(spacer(), true)
316 --hide:AddTexture(spacer(), false)
318 local lock = QuestHelper:CreateMenuItem(menu, "Lock")
319 local ltex = QuestHelper:CreateIconTexture(item, 10)
320 lock:SetFunction(function () QuestHelper_Pref.arrow_locked = not QuestHelper_Pref.arrow_locked end)
321 lock:AddTexture(ltex, true)
322 lock:AddTexture(spacer(), false)
323 ltex:SetVertexColor(1, 1, 1, QuestHelper_Pref.arrow_locked and 1 or 0)
325 local scale = QuestHelper:CreateMenuItem(menu, "Arrow Scale")
326 local scale_menu = QuestHelper:CreateMenu()
327 scale:SetSubmenu(scale_menu)
328 scale:AddTexture(spacer(), true)
329 for i = 5, 15 do
330 local it = QuestHelper:CreateMenuItem(scale_menu, string.format("%d%%", i * 10))
331 local ix = i
332 it:SetFunction(function () QH_Arrow_SetScale(ix / 10) end)
333 local icon = QuestHelper:CreateIconTexture(item, 10)
334 if QuestHelper_Pref.arrow_arrowsize == ix / 10 then
335 icon:SetVertexColor(1, 1, 1, 1)
336 else
337 icon:SetVertexColor(1, 1, 1, 0)
339 it:AddTexture(icon)
342 local tscale = QuestHelper:CreateMenuItem(menu, "Text Scale")
343 local tscale_menu = QuestHelper:CreateMenu()
344 tscale:SetSubmenu(tscale_menu)
345 tscale:AddTexture(spacer(), true)
346 for i = 5, 15 do
347 local it = QuestHelper:CreateMenuItem(tscale_menu, string.format("%d%%", i * 10))
348 local ix = i
349 it:SetFunction(function () QH_Arrow_SetTextScale(ix / 10) end)
350 local icon = QuestHelper:CreateIconTexture(item, 10)
351 if QuestHelper_Pref.arrow_textsize == ix / 10 then
352 icon:SetVertexColor(1, 1, 1, 1)
353 else
354 icon:SetVertexColor(1, 1, 1, 0)
356 it:AddTexture(icon)
359 local reset = QuestHelper:CreateMenuItem(menu, QHText("SETTINGS_MENU_ARROW_RESET"))
360 reset:SetFunction(function () QH_Arrow_Reset() end)
363 local function WayFrame_OnClick(self, button)
364 local menu = QuestHelper:CreateMenu()
365 QuestHelper:CreateMenuTitle(menu, QHText("SETTINGS_ARROWLINK_ARROW"))
367 QH_Arrow_PopulateMenu(menu)
369 menu:ShowAtCursor()
372 wayframe:RegisterForClicks("RightButtonUp")
374 QH_OnUpdate(OnUpdate)