comparison Bloodhound2.lua @ 0:ff01eb61abab

Initial beta version Updated original addon herb and ore database Fixed the configuration options (maybe - requires testing) Added the 2 new zones in Pandaria (Isle of Giants and Isle of Thunder)
author only1yzerman
date Thu, 09 May 2013 18:53:18 -0400
parents
children 6ab5b23877a6
comparison
equal deleted inserted replaced
-1:000000000000 0:ff01eb61abab
1
2 -------- SINGLE OBJECT IN GLOBAL NAMESPACE
3
4 Bloodhound2 = {};
5
6
7 -------- CREATE OUR INVISIBLE FRAME TO RECEIVE EVENTS AND UPDATES
8
9 local frame = CreateFrame("Frame", nil, UIParent);
10 Bloodhound2.Frame = frame;
11
12
13 -------- DEFINE AND REGISTER EVENT HANDLERS
14
15 local events = {};
16
17 function events:MINIMAP_UPDATE_TRACKING(...)
18 if player and player.Z then
19 Bloodhound2.UpdateMinimap();
20 end
21 end
22
23 frame:SetScript("OnEvent",
24 function(self, event, ...)
25 events[event](self, ...);
26 end);
27
28 local k, v;
29
30 for k, v in pairs(events) do
31 frame:RegisterEvent(k);
32 end
33
34
35
36
37
38
39 ----------------------------------------------------------------------------------------------------
40 -------- STORES A POINTER TO THE MINIMAP LOCALLY SO IT CAN BE CHANGED BY A RE-PARENTING FUNCTION
41 -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD
42 ----------------------------------------------------------------------------------------------------
43 local Minimap = _G.Minimap;
44 Minimap.MinimapName = "Minimap";
45 ----------------------------------------------------------------------------------------------------
46
47
48
49
50
51
52 -------- WORK AROUND WOW BUG THAT CAUSES GetPlayerMapPosition TO RETURN 0,0
53
54 WorldMapFrame:Show()
55 WorldMapFrame:Hide()
56
57
58 -------- HOOK INTO PER-FRAME UPDATE HANDLER
59
60 local player = {}; -- player position
61 local totalElapsed = 0.0; -- time elapsed since last update
62 local updatePeriod = 0.1; -- sec. interval for each minimap update
63 local cpuThrottle = 0.05; -- throttle to 5% usage while moving
64 local minUpdatePeriod = 0.04; -- sec. don't update more often than this
65 local lastzoom = 0; -- previous minimap zoom level
66 local updateTotalTime = 0; -- time spent updating minimap
67 local updateCount = 0; -- number of times minimap updated
68
69 ----------------------------------------------------------------------------------------------------
70 -------- MOVED OnUpdate Script into seperate function so it could be called by re-parent function
71 -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD
72 ----------------------------------------------------------------------------------------------------
73 frame:SetScript("OnUpdate", function(self, elapsed) Bloodhound2.OnUpdateScript(self, elapsed) end);
74 function Bloodhound2.OnUpdateScript(self, elapsed)
75 totalElapsed = totalElapsed + elapsed; -- measure total elapsed time
76
77 if (totalElapsed >= updatePeriod) then -- if enough time has passed
78 totalElapsed = mod(totalElapsed, updatePeriod);
79 local isInInstance, instanceType = IsInInstance()
80
81 if isInInstance ~= nil then
82 Bloodhound2.DrawArrow(0, 0, 0, 0)
83 return
84 end
85
86 local cmap = GetCurrentMapContinent();
87 local zmap = GetCurrentMapZone();
88 SetMapToCurrentZone();
89 local c = GetCurrentMapContinent(); -- get current player position
90 local z = GetCurrentMapZone();
91 local x, y = GetPlayerMapPosition("player");
92 local f = GetPlayerFacing();
93 local m = Minimap:GetZoom();
94 SetMapZoom(cmap, zmap);
95
96 if (c ~= player.C and c ~= 0) then -- reload continent data if continent has changed
97 Bloodhound2.HerbNodes, Bloodhound2.ContinentHerbs = Bloodhound2.ReloadNodes(Bloodhound2.HerbDatabase[c], Bloodhound2.ZoneDatum[c]);
98 Bloodhound2.OreNodes, Bloodhound2.ContinentOre = Bloodhound2.ReloadNodes(Bloodhound2.OreDatabase[c], Bloodhound2.ZoneDatum[c]);
99 end
100
101 if (c ~= player.C or z ~= player.Z or x ~= player.X or y ~= player.Y or f ~= player.F or m ~= lastzoom) then
102 player.C = c;
103 player.Z = z;
104 player.X = x;
105 player.Y = y;
106 player.F = f;
107 lastzoom = m;
108 local t0 = GetTime();
109 Bloodhound2.UpdateMinimap(); -- player has moved or minimap scale has changed
110 local t1 = GetTime() - t0;
111
112 -- calculate and throttle CPU usage to 5%
113 updateTotalTime = updateTotalTime + t1
114
115 if updateCount > 10 then
116 local avgTime = updateTotalTime / updateCount
117 updatePeriod = avgTime / cpuThrottle
118 Print(updateCount);
119
120 if updatePeriod < minUpdatePeriod then
121 updatePeriod = minUpdatePeriod
122 end
123
124 if updateCount >= 100 then
125 updateTotalTime = updateTotalTime / 2
126 updateCount = updateCount / 2
127 end
128 end
129 end
130 end
131 end
132
133 function Bloodhound2.UpdateMinimap()
134 local facing = 0
135
136 if GetCVar("rotateMinimap") ~= "0" then
137 facing = GetPlayerFacing() * 57.2957795;
138 end
139
140 local cf = cos(facing);
141 local sf = sin(facing);
142 local gx, gy = Bloodhound2.CalculateForce(cf, sf);
143 Bloodhound2.DrawArrow(gx, gy, cf, sf);
144 end
145
146
147 -------- DATABASE LOADING
148
149 Bloodhound2.HerbNodes = {};
150 Bloodhound2.OreNodes = {};
151 Bloodhound2.ContinentHerbs = {};
152 Bloodhound2.ContinentOre = {};
153
154 function Bloodhound2.ReloadNodes(database, zoneDatum)
155
156 if (database == nil) then return {}; end
157
158 local nodes = {};
159 local db = {};
160
161 local zoneNode, positions;
162 for zoneNode, positions in pairs(database) do
163 local _, _, zone, node = string.find(zoneNode, "Z(%d+)N(%d+)");
164 local z = tonumber(zone);
165 local datum = zoneDatum[z];
166 local n = tonumber(node);
167 db[n] = true;
168 local pxy = 0
169
170 for _,pos in ipairs(positions) do
171 local xy = pos + pxy
172 pxy = xy
173 local x = floor(xy / 1000);
174 local y = xy - 1000 * x;
175 x, y = Bloodhound2.ZoneDatum.LocalToGlobal(x / 1000.0, y / 1000.0, datum);
176 tinsert(nodes, {Z = z, N = n, X = x, Y = y, TimeStamp = time() - 60 - 3600 * math.random() });
177 end
178 end
179
180 return nodes, db;
181 end
182
183
184 -------- UTILITY FUNCTIONS
185
186 function Print(message)
187 DEFAULT_CHAT_FRAME:AddMessage(message);
188 end
189
190
191
192 -------- ARROW LOADING AND DISPLAY
193
194 local function GetArrowTexture()
195
196 local tex = Bloodhound2.GravityTexture
197
198 if not ( tex ) then
199 tex = Minimap:CreateTexture();
200 tex:SetTexture("Interface\\AddOns\\Bloodhound2\\MinimapArrow");
201 Bloodhound2.GravityTexture = tex
202 end
203
204 return tex
205 end
206
207 function Bloodhound2.DrawArrow(grx, gry, cf, sf)
208
209 local gravityX = grx * cf - gry * sf;
210 local gravityY = gry * cf + grx * sf;
211 local gravityTexture = GetArrowTexture()
212
213 if (gravityX == 0 and gravityY == 0) then
214 gravityTexture:Hide();
215 return;
216 end
217
218 local gravityScale = sqrt(gravityX * gravityX + gravityY * gravityY)
219 gravityX = gravityX / gravityScale
220 gravityY = gravityY / gravityScale
221
222 -- determine rotated and scaled texture coordinates
223 local gy = (gravityX + gravityY) / 2.82843
224 local gx = (gravityX - gravityY) / 2.82843
225
226 gravityTexture:SetTexCoord(
227 0.5 - gx, 0.5 + gy,
228 0.5 + gy, 0.5 + gx,
229 0.5 - gy, 0.5 - gx,
230 0.5 + gx, 0.5 - gy);
231
232 gravityTexture:SetPoint("CENTER", Minimap, "CENTER", 40 * gravityX, -40 * gravityY)
233 gravityTexture:Show()
234 end
235
236
237 -------- "RUBY" MANAGEMENT (REUSE RUBIES AND ONLY CREATE NEW ONES WHEN NEEDED)
238
239 local circles = {};
240 local nextCircle = 1;
241 local circleScale = 1;
242
243 function Bloodhound2.ResetCircles()
244 nextCircle = 1;
245 circleScale = Minimap:GetHeight() * 0.015 / (7 - Minimap:GetZoom());
246 end
247
248 function Bloodhound2.SetCircle(dx, dy, alpha)
249 local circle;
250 if (#circles < nextCircle) then
251 circle = Minimap:CreateTexture();
252 circles[nextCircle] = circle;
253 circle:SetTexture("Interface\\AddOns\\Bloodhound2\\Circle");
254 circle:SetWidth(12);
255 circle:SetHeight(12);
256 circle:SetAlpha(1);
257 else
258 circle = circles[nextCircle];
259 end
260
261 nextCircle = nextCircle + 1;
262 circle:SetPoint("CENTER", Minimap, "CENTER", dx * circleScale, -dy * circleScale);
263 circle:SetAlpha(alpha);
264 circle:Show();
265 end
266
267 function Bloodhound2.HideExtraCircles()
268 for i=nextCircle,#circles,1 do
269 circles[i]:Hide();
270 end
271 end
272
273
274
275 -------- MAIN FUNCTION FOR CALCULATING RECOMMENDED DIRECTION OF TRAVEL
276
277 function Bloodhound2.CalculateForce(cf, sf)
278
279 local c = player.C; -- get player position
280 local z = player.Z;
281 local x = player.X;
282 local y = player.Y;
283
284 if c == 0 or z == 0 then return 0,0 end -- don't draw arrow if using world coordinates
285 if not Bloodhound2.ZoneDatum then return 0,0 end
286
287 local datum = Bloodhound2.ZoneDatum[c][z]; -- get scale and offset for current zone map
288 if datum == nil then return 0,0 end
289
290 local gx, gy = Bloodhound2.ZoneDatum.LocalToGlobal(x, y, datum); -- convert player position to world coordinates
291 local now = time(); -- value to use for time-stamping visited nodes
292 local fx = 0; -- cumulative force, X-component
293 local fy = 0; -- cumulative force, Y-component
294 local multiZone = true; -- whether to include more than the current zone
295 local inspectionRadius = 60;
296
297 if Settings then
298 if Settings.MultiZoneMode==0 then
299 multiZone = IsFlying();
300 elseif Settings.MultiZoneMode==1 then
301 multiZone = true;
302 else
303 multiZone = false;
304 end
305
306 if Settings.InspectionRadius then
307 inspectionRadius = Settings.InspectionRadius;
308 end
309 end
310
311 local settingsFilter = {}; -- which node types to ignore
312 local nodes = {}; -- which nodes to track
313
314 for i=1,GetNumTrackingTypes(),1 do
315 local name, _, active, _ = GetTrackingInfo(i);
316 if (active == 1) then
317 if (name == L["Find Herbs"]) then
318 for k,v in pairs(Settings.HerbFilter) do settingsFilter[k] = v end
319 for k,v in pairs(Bloodhound2.HerbNodes) do tinsert(nodes, v) end
320 elseif (name == L["Find Minerals"]) then
321 for k,v in pairs(Settings.OreFilter) do settingsFilter[k] = v end
322 for k,v in pairs(Bloodhound2.OreNodes) do tinsert(nodes, v) end
323 end
324 end
325 end
326
327 local avoidZones = {}; -- which zones to avoid
328
329 if multiZone then
330 local cmc = GetCurrentMapContinent()
331
332 if not Settings.ZoneFilter[cmc] then
333 Settings.ZoneFilter[cmc] = {}
334 end
335
336 for k,v in pairs(Settings.ZoneFilter[GetCurrentMapContinent()]) do
337 avoidZones[k] = true;
338 end
339 end
340
341 local avoidNodes = {}; -- which node types to ignore
342
343 if settingsFilter then
344 for k,v in pairs(settingsFilter) do
345 avoidNodes[k] = true;
346 end
347 end
348
349 local minimapSize = Minimap:GetWidth() / 2 - 2;
350 Bloodhound2.ResetCircles();
351
352 for key, node in pairs(nodes) do
353 if (avoidNodes[node.N] ~= true) and (avoidZones[node.Z] ~= true) and (multiZone or (node.Z == z)) then
354 local dx = node.X - gx;
355 local dy = node.Y - gy;
356 local rsqrd = dx * dx + dy * dy;
357 local r = sqrt(rsqrd); -- distance to node
358 local age = now - node.TimeStamp; -- time since last inspected
359
360 if (r < inspectionRadius) then
361 node.TimeStamp = now;
362 else
363 --[[
364 The magnitude of the force is proportional to the age and inversely
365 proportional to the square of the distance, and the direction is towards
366 the node. The math for this starts out as
367
368 local force = age / rsqrd
369 local angle = math.atan2(dy, dx)
370 fx = fx + force * math.cos(angle)
371 fy = fy + force * math.sin(angle)
372
373 But cos(angle) is just dx/r and sin(angle) is just dy/r, so we don't
374 actually need atan2, cos, and sin and instead we can write this as
375 ]]
376 local force = age / (r * rsqrd)
377 fx = fx + force * dx
378 fy = fy + force * dy
379 end
380
381 if (r * circleScale < minimapSize) and (age > 60) then -- draw ruby
382 local alpha = r / (minimapSize / circleScale) / 0.7 - 0.3;
383 alpha = max(0, alpha);
384 Bloodhound2.SetCircle(dx * cf - dy * sf, dy * cf + dx * sf, alpha);
385 end
386 end
387 end
388
389 Bloodhound2.HideExtraCircles();
390 return fx, fy;
391 end
392
393
394
395
396
397
398
399 ----------------------------------------------------------------------------------------------------
400 -------- REPARENT THE MINIMAP FOR 3RD PARTY MINIMAPS AND HUDS
401 -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD
402 ----------------------------------------------------------------------------------------------------
403 function Bloodhound2.ReparentMinimap(NewMinimap, MinimapName)
404 Bloodhound2.OnUpdateScript(nil, 1000000)
405 -- Hide the circles currently on the minimap
406 Bloodhound2.ResetCircles();
407 Bloodhound2.HideExtraCircles();
408 -- Hide this minimap's copy of the arrow
409 if Bloodhound2.GravityTexture then
410 Bloodhound2.GravityTexture:Hide();
411 end;
412 -- Store the current set of circles and arrow on this minimap for later
413 Minimap.Bloodhound2Circles = circles;
414 Minimap.Bloodhound2Arrow = Bloodhound2.GravityTexture;
415 -- Pull back (or create for circles) the arrow and circles for this minimap
416 circles = NewMinimap.Bloodhound2Circles or {};
417 ZasCircles = circles;
418 Bloodhound2.GravityTexture = NewMinimap.Bloodhound2Arrow;
419 -- Move Bloodhound2's Local Minimap pointer to the new minimap
420 Minimap = NewMinimap;
421 Minimap.MinimapName = MinimapName;
422 -- Update all points
423 Bloodhound2.UpdateMinimap();
424 end
425 ----------------------------------------------------------------------------------------------------