Mercurial > wow > bloodhound2
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 ---------------------------------------------------------------------------------------------------- |
