Mercurial > wow > bloodhound2
view Bloodhound2.lua @ 1:6ab5b23877a6
Changed the layer of the BH arrow so that it is always on top of the rubies.
author | only1yzerman |
---|---|
date | Fri, 10 May 2013 03:45:15 -0400 |
parents | ff01eb61abab |
children | 91131c35a2c3 |
line wrap: on
line source
-------- SINGLE OBJECT IN GLOBAL NAMESPACE Bloodhound2 = {}; -------- CREATE OUR INVISIBLE FRAME TO RECEIVE EVENTS AND UPDATES local frame = CreateFrame("Frame", nil, UIParent); Bloodhound2.Frame = frame; -------- DEFINE AND REGISTER EVENT HANDLERS local events = {}; function events:MINIMAP_UPDATE_TRACKING(...) if player and player.Z then Bloodhound2.UpdateMinimap(); end end frame:SetScript("OnEvent", function(self, event, ...) events[event](self, ...); end); local k, v; for k, v in pairs(events) do frame:RegisterEvent(k); end ---------------------------------------------------------------------------------------------------- -------- STORES A POINTER TO THE MINIMAP LOCALLY SO IT CAN BE CHANGED BY A RE-PARENTING FUNCTION -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD ---------------------------------------------------------------------------------------------------- local Minimap = _G.Minimap; Minimap.MinimapName = "Minimap"; ---------------------------------------------------------------------------------------------------- -------- WORK AROUND WOW BUG THAT CAUSES GetPlayerMapPosition TO RETURN 0,0 WorldMapFrame:Show() WorldMapFrame:Hide() -------- HOOK INTO PER-FRAME UPDATE HANDLER local player = {}; -- player position local totalElapsed = 0.0; -- time elapsed since last update local updatePeriod = 0.1; -- sec. interval for each minimap update local cpuThrottle = 0.05; -- throttle to 5% usage while moving local minUpdatePeriod = 0.04; -- sec. don't update more often than this local lastzoom = 0; -- previous minimap zoom level local updateTotalTime = 0; -- time spent updating minimap local updateCount = 0; -- number of times minimap updated ---------------------------------------------------------------------------------------------------- -------- MOVED OnUpdate Script into seperate function so it could be called by re-parent function -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD ---------------------------------------------------------------------------------------------------- frame:SetScript("OnUpdate", function(self, elapsed) Bloodhound2.OnUpdateScript(self, elapsed) end); function Bloodhound2.OnUpdateScript(self, elapsed) totalElapsed = totalElapsed + elapsed; -- measure total elapsed time if (totalElapsed >= updatePeriod) then -- if enough time has passed totalElapsed = mod(totalElapsed, updatePeriod); local isInInstance, instanceType = IsInInstance() if isInInstance ~= nil then Bloodhound2.DrawArrow(0, 0, 0, 0) return end local cmap = GetCurrentMapContinent(); local zmap = GetCurrentMapZone(); SetMapToCurrentZone(); local c = GetCurrentMapContinent(); -- get current player position local z = GetCurrentMapZone(); local x, y = GetPlayerMapPosition("player"); local f = GetPlayerFacing(); local m = Minimap:GetZoom(); SetMapZoom(cmap, zmap); if (c ~= player.C and c ~= 0) then -- reload continent data if continent has changed Bloodhound2.HerbNodes, Bloodhound2.ContinentHerbs = Bloodhound2.ReloadNodes(Bloodhound2.HerbDatabase[c], Bloodhound2.ZoneDatum[c]); Bloodhound2.OreNodes, Bloodhound2.ContinentOre = Bloodhound2.ReloadNodes(Bloodhound2.OreDatabase[c], Bloodhound2.ZoneDatum[c]); end if (c ~= player.C or z ~= player.Z or x ~= player.X or y ~= player.Y or f ~= player.F or m ~= lastzoom) then player.C = c; player.Z = z; player.X = x; player.Y = y; player.F = f; lastzoom = m; local t0 = GetTime(); Bloodhound2.UpdateMinimap(); -- player has moved or minimap scale has changed local t1 = GetTime() - t0; -- calculate and throttle CPU usage to 5% updateTotalTime = updateTotalTime + t1 if updateCount > 10 then local avgTime = updateTotalTime / updateCount updatePeriod = avgTime / cpuThrottle Print(updateCount); if updatePeriod < minUpdatePeriod then updatePeriod = minUpdatePeriod end if updateCount >= 100 then updateTotalTime = updateTotalTime / 2 updateCount = updateCount / 2 end end end end end function Bloodhound2.UpdateMinimap() local facing = 0 if GetCVar("rotateMinimap") ~= "0" then facing = GetPlayerFacing() * 57.2957795; end local cf = cos(facing); local sf = sin(facing); local gx, gy = Bloodhound2.CalculateForce(cf, sf); Bloodhound2.DrawArrow(gx, gy, cf, sf); end -------- DATABASE LOADING Bloodhound2.HerbNodes = {}; Bloodhound2.OreNodes = {}; Bloodhound2.ContinentHerbs = {}; Bloodhound2.ContinentOre = {}; function Bloodhound2.ReloadNodes(database, zoneDatum) if (database == nil) then return {}; end local nodes = {}; local db = {}; local zoneNode, positions; for zoneNode, positions in pairs(database) do local _, _, zone, node = string.find(zoneNode, "Z(%d+)N(%d+)"); local z = tonumber(zone); local datum = zoneDatum[z]; local n = tonumber(node); db[n] = true; local pxy = 0 for _,pos in ipairs(positions) do local xy = pos + pxy pxy = xy local x = floor(xy / 1000); local y = xy - 1000 * x; x, y = Bloodhound2.ZoneDatum.LocalToGlobal(x / 1000.0, y / 1000.0, datum); tinsert(nodes, {Z = z, N = n, X = x, Y = y, TimeStamp = time() - 60 - 3600 * math.random() }); end end return nodes, db; end -------- UTILITY FUNCTIONS function Print(message) DEFAULT_CHAT_FRAME:AddMessage(message); end -------- ARROW LOADING AND DISPLAY local function GetArrowTexture() local tex = Bloodhound2.GravityTexture if not ( tex ) then tex = Minimap:CreateTexture("Bloodhound2_Arrow", "OVERLAY"); tex:SetTexture("Interface\\AddOns\\Bloodhound2\\MinimapArrow"); Bloodhound2.GravityTexture = tex end return tex end function Bloodhound2.DrawArrow(grx, gry, cf, sf) local gravityX = grx * cf - gry * sf; local gravityY = gry * cf + grx * sf; local gravityTexture = GetArrowTexture() if (gravityX == 0 and gravityY == 0) then gravityTexture:Hide(); return; end local gravityScale = sqrt(gravityX * gravityX + gravityY * gravityY) gravityX = gravityX / gravityScale gravityY = gravityY / gravityScale -- determine rotated and scaled texture coordinates local gy = (gravityX + gravityY) / 2.82843 local gx = (gravityX - gravityY) / 2.82843 gravityTexture:SetTexCoord( 0.5 - gx, 0.5 + gy, 0.5 + gy, 0.5 + gx, 0.5 - gy, 0.5 - gx, 0.5 + gx, 0.5 - gy); gravityTexture:SetPoint("CENTER", Minimap, "CENTER", 40 * gravityX, -40 * gravityY) gravityTexture:Show() end -------- "RUBY" MANAGEMENT (REUSE RUBIES AND ONLY CREATE NEW ONES WHEN NEEDED) local circles = {}; local nextCircle = 1; local circleScale = 1; function Bloodhound2.ResetCircles() nextCircle = 1; circleScale = Minimap:GetHeight() * 0.015 / (7 - Minimap:GetZoom()); end function Bloodhound2.SetCircle(dx, dy, alpha) local circle; if (#circles < nextCircle) then circle = Minimap:CreateTexture("Bloodhound_Circle", "ARTWORK", nil, -7); circles[nextCircle] = circle; circle:SetTexture("Interface\\AddOns\\Bloodhound2\\Circle"); circle:SetWidth(12); circle:SetHeight(12); circle:SetAlpha(1); else circle = circles[nextCircle]; end nextCircle = nextCircle + 1; circle:SetPoint("CENTER", Minimap, "CENTER", dx * circleScale, -dy * circleScale); circle:SetAlpha(alpha); circle:Show(); end function Bloodhound2.HideExtraCircles() for i=nextCircle,#circles,1 do circles[i]:Hide(); end end -------- MAIN FUNCTION FOR CALCULATING RECOMMENDED DIRECTION OF TRAVEL function Bloodhound2.CalculateForce(cf, sf) local c = player.C; -- get player position local z = player.Z; local x = player.X; local y = player.Y; if c == 0 or z == 0 then return 0,0 end -- don't draw arrow if using world coordinates if not Bloodhound2.ZoneDatum then return 0,0 end local datum = Bloodhound2.ZoneDatum[c][z]; -- get scale and offset for current zone map if datum == nil then return 0,0 end local gx, gy = Bloodhound2.ZoneDatum.LocalToGlobal(x, y, datum); -- convert player position to world coordinates local now = time(); -- value to use for time-stamping visited nodes local fx = 0; -- cumulative force, X-component local fy = 0; -- cumulative force, Y-component local multiZone = true; -- whether to include more than the current zone local inspectionRadius = 60; if Settings then if Settings.MultiZoneMode==0 then multiZone = IsFlying(); elseif Settings.MultiZoneMode==1 then multiZone = true; else multiZone = false; end if Settings.InspectionRadius then inspectionRadius = Settings.InspectionRadius; end end local settingsFilter = {}; -- which node types to ignore local nodes = {}; -- which nodes to track for i=1,GetNumTrackingTypes(),1 do local name, _, active, _ = GetTrackingInfo(i); if (active == 1) then if (name == L["Find Herbs"]) then for k,v in pairs(Settings.HerbFilter) do settingsFilter[k] = v end for k,v in pairs(Bloodhound2.HerbNodes) do tinsert(nodes, v) end elseif (name == L["Find Minerals"]) then for k,v in pairs(Settings.OreFilter) do settingsFilter[k] = v end for k,v in pairs(Bloodhound2.OreNodes) do tinsert(nodes, v) end end end end local avoidZones = {}; -- which zones to avoid if multiZone then local cmc = GetCurrentMapContinent() if not Settings.ZoneFilter[cmc] then Settings.ZoneFilter[cmc] = {} end for k,v in pairs(Settings.ZoneFilter[GetCurrentMapContinent()]) do avoidZones[k] = true; end end local avoidNodes = {}; -- which node types to ignore if settingsFilter then for k,v in pairs(settingsFilter) do avoidNodes[k] = true; end end local minimapSize = Minimap:GetWidth() / 2 - 2; Bloodhound2.ResetCircles(); for key, node in pairs(nodes) do if (avoidNodes[node.N] ~= true) and (avoidZones[node.Z] ~= true) and (multiZone or (node.Z == z)) then local dx = node.X - gx; local dy = node.Y - gy; local rsqrd = dx * dx + dy * dy; local r = sqrt(rsqrd); -- distance to node local age = now - node.TimeStamp; -- time since last inspected if (r < inspectionRadius) then node.TimeStamp = now; else --[[ The magnitude of the force is proportional to the age and inversely proportional to the square of the distance, and the direction is towards the node. The math for this starts out as local force = age / rsqrd local angle = math.atan2(dy, dx) fx = fx + force * math.cos(angle) fy = fy + force * math.sin(angle) But cos(angle) is just dx/r and sin(angle) is just dy/r, so we don't actually need atan2, cos, and sin and instead we can write this as ]] local force = age / (r * rsqrd) fx = fx + force * dx fy = fy + force * dy end if (r * circleScale < minimapSize) and (age > 60) then -- draw ruby local alpha = r / (minimapSize / circleScale) / 0.7 - 0.3; alpha = max(0, alpha); Bloodhound2.SetCircle(dx * cf - dy * sf, dy * cf + dx * sf, alpha); end end end Bloodhound2.HideExtraCircles(); return fx, fy; end ---------------------------------------------------------------------------------------------------- -------- REPARENT THE MINIMAP FOR 3RD PARTY MINIMAPS AND HUDS -------- - Added by Zasurus(www.curseforge.com/profiles/Zasurus/) for MiniHugeHUD ---------------------------------------------------------------------------------------------------- function Bloodhound2.ReparentMinimap(NewMinimap, MinimapName) Bloodhound2.OnUpdateScript(nil, 1000000) -- Hide the circles currently on the minimap Bloodhound2.ResetCircles(); Bloodhound2.HideExtraCircles(); -- Hide this minimap's copy of the arrow if Bloodhound2.GravityTexture then Bloodhound2.GravityTexture:Hide(); end; -- Store the current set of circles and arrow on this minimap for later Minimap.Bloodhound2Circles = circles; Minimap.Bloodhound2Arrow = Bloodhound2.GravityTexture; -- Pull back (or create for circles) the arrow and circles for this minimap circles = NewMinimap.Bloodhound2Circles or {}; ZasCircles = circles; Bloodhound2.GravityTexture = NewMinimap.Bloodhound2Arrow; -- Move Bloodhound2's Local Minimap pointer to the new minimap Minimap = NewMinimap; Minimap.MinimapName = MinimapName; -- Update all points Bloodhound2.UpdateMinimap(); end ----------------------------------------------------------------------------------------------------