local _, ns = ... local oUF = ns.oUF or oUF assert(oUF, 'oUF not loaded') local cos, sin, sqrt2, max, atan2, floor = math.cos, math.sin, math.sqrt(2), math.max, math.atan2, math.floor; local tinsert, tremove, tsort, twipe = table.insert, table.remove, table.sort, table.wipe; local SuperVillain = SVUI[1] local playerGUID = UnitGUID("player") local _FRAMES, _PROXIMITY, OnUpdateFrame = {}, {} local GPSMonitorFrame; local function _calc(radius) return 0.5 + cos(radius) / sqrt2, 0.5 + sin(radius) / sqrt2; end local function spin(texture, angle) local LRx, LRy = _calc(angle + 0.785398163); local LLx, LLy = _calc(angle + 2.35619449); local ULx, ULy = _calc(angle + 3.92699082); local URx, URy = _calc(angle - 0.785398163); texture:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy); end local sortFunc = function(a,b) return a[1] < b[1] end local minThrottle = 0.02 local numArrows, inRange, unit, angle, GPS, distance local Update = function(self, elapsed) if self.elapsed and self.elapsed > (self.throttle or minThrottle) then numArrows = 0 twipe(_PROXIMITY) for _, object in next, _FRAMES do if(object:IsShown()) then GPS = object.GPS unit = object.unit if(unit) then if(GPS.PreUpdate) then GPS:PreUpdate(frame) end if unit and GPS.outOfRange then inRange = UnitInRange(unit) end local available = (GPS.OnlyProximity == false and GPS.onMouseOver == false) if(not unit or not (UnitInParty(unit) or UnitInRaid(unit)) or UnitIsUnit(unit, "player") or not UnitIsConnected(unit) or (not GPS.OnlyProximity and ((GPS.onMouseOver and (GetMouseFocus() ~= object)) or (GPS.outOfRange and inRange)))) then GPS:Hide() else distance, angle = SuperVillain:PositionFromPlayer(unit, available) if not angle then GPS:Hide() else if(GPS.OnlyProximity == false) then GPS:Show() else GPS:Hide() end if GPS.Arrow then if(distance > 40) then GPS.Arrow:SetVertexColor(1,0.1,0.1) elseif(distance > 30) then GPS.Arrow:SetVertexColor(0.4,0.8,0.1) else GPS.Arrow:SetVertexColor(0.1,1,0.1) end spin(GPS.Arrow, angle) end if GPS.Text then GPS.Text:SetText(floor(distance)) end if(GPS.OnlyProximity and object.Health.percent and object.Health.percent < 80) then local value = object.Health.percent + distance _PROXIMITY[#_PROXIMITY + 1] = {value, GPS} end if(GPS.PostUpdate) then GPS:PostUpdate(frame, distance, angle) end numArrows = numArrows + 1 end end else GPS:Hide() end end end tsort(_PROXIMITY, sortFunc) if(_PROXIMITY[1] and _PROXIMITY[1][2]) then _PROXIMITY[1][2]:Show() end self.elapsed = 0 self.throttle = max(minThrottle, 0.005 * numArrows) else self.elapsed = (self.elapsed or 0) + elapsed end end local Enable = function(self) local GPS = self.GPS if GPS then tinsert(_FRAMES, self) if not OnUpdateFrame then OnUpdateFrame = CreateFrame("Frame") OnUpdateFrame:SetScript("OnUpdate", Update) end OnUpdateFrame:Show() return true end end local Disable = function(self) local GPS = self.GPS if GPS then for k, frame in next, _FRAMES do if(frame == self) then tremove(_FRAMES, k) GPS:Hide() break end end if #_FRAMES == 0 and OnUpdateFrame then OnUpdateFrame:Hide() end end end oUF:AddElement('GPS', nil, Enable, Disable)