init
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
-- This file uses models and textures taken from TomTom. The 3d arrow model was created by Guillotine (curse.guillotine@gmail.com) and 2d minimap textures by Cladhaire.
|
||||
|
||||
----------------------------
|
||||
-- Initialize variables --
|
||||
----------------------------
|
||||
-- globals
|
||||
DBM.Arrow = {}
|
||||
|
||||
-- locals
|
||||
local runAwayArrow
|
||||
local targetType
|
||||
local targetPlayer
|
||||
local targetX, targetY
|
||||
local hideTime, hideDistance
|
||||
|
||||
-- cached variables
|
||||
local pi, pi2 = math.pi, math.pi * 2
|
||||
local floor = math.floor
|
||||
local sin, cos, atan2, sqrt, min = math.sin, math.cos, math.atan2, math.sqrt, math.min
|
||||
local GetPlayerMapPosition = GetPlayerMapPosition
|
||||
|
||||
--------------------
|
||||
-- Create Frame --
|
||||
--------------------
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
frame:SetFrameStrata("HIGH")
|
||||
frame:SetWidth(56)
|
||||
frame:SetHeight(42)
|
||||
frame:SetMovable(true)
|
||||
frame:EnableMouse(false)
|
||||
frame:RegisterForDrag("LeftButton", "RightButton")
|
||||
frame:SetScript("OnDragStart", function(self)
|
||||
self:StartMoving()
|
||||
end)
|
||||
frame:SetScript("OnDragStop", function(self)
|
||||
self:StopMovingOrSizing()
|
||||
local point, _, _, x, y = self:GetPoint(1)
|
||||
DBM.Options.ArrowPoint = point
|
||||
DBM.Options.ArrowPosX = x
|
||||
DBM.Options.ArrowPosY = y
|
||||
end)
|
||||
local arrow = frame:CreateTexture(nil, "OVERLAY")
|
||||
arrow:SetTexture("Interface\\AddOns\\DBM-Core\\textures\\arrows\\Arrow.blp")
|
||||
arrow:SetAllPoints(frame)
|
||||
|
||||
---------------------
|
||||
-- Map Utilities --
|
||||
---------------------
|
||||
local SetMapToCurrentZone -- throttled SetMapToCurrentZone function to prevent lag issues with unsupported WorldMap addons
|
||||
do
|
||||
local lastMapUpdate = 0
|
||||
function SetMapToCurrentZone(...)
|
||||
if GetTime() - lastMapUpdate > 1 then
|
||||
lastMapUpdate = GetTime()
|
||||
return _G.SetMapToCurrentZone(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local calculateDistance
|
||||
do
|
||||
local mapSizes = DBM.MapSizes
|
||||
function calculateDistance(x1, y1, x2, y2)
|
||||
local mapName = GetMapInfo()
|
||||
local floors = mapSizes[mapName]
|
||||
if not floors then
|
||||
return
|
||||
end
|
||||
local dims = floors[GetCurrentMapDungeonLevel()]
|
||||
if not dims and levels and GetCurrentMapDungeonLevel() == 0 then -- we are in a known zone but the dungeon level seems to be wrong
|
||||
SetMapToCurrentZone() -- fixes the dungeon level (if it was wrong for some reason)
|
||||
dims = levels[GetCurrentMapDungeonLevel()] -- try again
|
||||
end
|
||||
if not dims then -- we are in an unknown dungeon :(
|
||||
return
|
||||
end
|
||||
local dX = (x1 - x2) * dims[1]
|
||||
local dY = (y1 - y2) * dims[2]
|
||||
return sqrt(dX * dX + dY * dY)
|
||||
end
|
||||
end
|
||||
|
||||
-- GetPlayerFacing seems to return values between -pi and pi instead of 0 - 2pi sometimes since 3.3.3
|
||||
local GetPlayerFacing = function(...)
|
||||
local result = GetPlayerFacing(...)
|
||||
if result < 0 then
|
||||
result = result + pi2
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
------------------------
|
||||
-- Update the arrow --
|
||||
------------------------
|
||||
local updateArrow
|
||||
do
|
||||
local currentCell
|
||||
function updateArrow(direction, distance)
|
||||
local cell = floor(direction / pi2 * 108 + 0.5) % 108
|
||||
if cell ~= currentCell then
|
||||
currentCell = cell
|
||||
local column = cell % 9
|
||||
local row = floor(cell / 9)
|
||||
local xStart = (column * 56) / 512
|
||||
local yStart = (row * 42) / 512
|
||||
local xEnd = ((column + 1) * 56) / 512
|
||||
local yEnd = ((row + 1) * 42) / 512
|
||||
arrow:SetTexCoord(xStart, xEnd, yStart, yEnd)
|
||||
end
|
||||
if distance then
|
||||
if runAwayArrow then
|
||||
local perc = distance / hideDistance
|
||||
arrow:SetVertexColor(1 - perc, perc, 0)
|
||||
if distance >= hideDistance then
|
||||
frame:Hide()
|
||||
end
|
||||
else
|
||||
local perc = min(distance, 100) / 100
|
||||
arrow:SetVertexColor(1, 1 - perc, 0)
|
||||
if distance <= hideDistance then
|
||||
frame:Hide()
|
||||
end
|
||||
end
|
||||
else
|
||||
if runAwayArrow then
|
||||
arrow:SetVertexColor(1, 0.3, 0)
|
||||
else
|
||||
arrow:SetVertexColor(1, 1, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------
|
||||
-- OnUpdate Handler --
|
||||
------------------------
|
||||
do
|
||||
local rotateState = 0
|
||||
-- local skipFrame -- todo: skipping frames makes the arrow laggy, maybe skip frames if frame rate >= 45
|
||||
frame:SetScript("OnUpdate", function(self, elapsed)
|
||||
if WorldMapFrame:IsShown() then -- it doesn't work while the world map frame is shown
|
||||
arrow:Hide()
|
||||
return
|
||||
end
|
||||
-- skipFrame = not skipFrame
|
||||
-- if skipFrame then
|
||||
-- return
|
||||
-- end
|
||||
if hideTime and GetTime() > hideTime then
|
||||
frame:Hide()
|
||||
end
|
||||
arrow:Show()
|
||||
local x, y = GetPlayerMapPosition("player")
|
||||
if x == 0 and y == 0 then
|
||||
SetMapToCurrentZone()
|
||||
x, y = GetPlayerMapPosition("player")
|
||||
if x == 0 and y == 0 then
|
||||
self:Hide() -- hide the arrow if you enter a zone without a map
|
||||
return
|
||||
end
|
||||
end
|
||||
if targetType == "player" then
|
||||
targetX, targetY = GetPlayerMapPosition(targetPlayer)
|
||||
if targetX == 0 and targetY == 0 then
|
||||
self:Hide() -- hide the player if the target doesn't exist. TODO: just hide the texture and add a timeout
|
||||
end
|
||||
elseif targetType == "rotate" then
|
||||
rotateState = rotateState + elapsed
|
||||
targetX = x + cos(rotateState)
|
||||
targetY = y + sin(rotateState)
|
||||
end
|
||||
if not targetX or not targetY then
|
||||
return
|
||||
end
|
||||
local angle = atan2(x - targetX, targetY - y)
|
||||
if angle <= 0 then -- -pi < angle < pi but we need/want a value between 0 and 2 pi
|
||||
if runAwayArrow then
|
||||
angle = -angle -- 0 < angle < pi
|
||||
else
|
||||
angle = pi - angle -- pi < angle < 2pi
|
||||
end
|
||||
else
|
||||
if runAwayArrow then
|
||||
angle = pi2 - angle -- pi < angle < 2pi
|
||||
else
|
||||
angle = pi - angle -- 0 < angle < pi
|
||||
end
|
||||
end
|
||||
updateArrow(angle - GetPlayerFacing(), calculateDistance(x, y, targetX, targetY))
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
----------------------
|
||||
-- Public Methods --
|
||||
----------------------
|
||||
local function show(runAway, x, y, distance, time)
|
||||
local player
|
||||
if type(x) == "string" then
|
||||
player, hideDistance, hideTime = x, y, hideDistance
|
||||
end
|
||||
frame:Show()
|
||||
runAwayArrow = runAway
|
||||
hideDistance = distance or runAway and 100 or 3
|
||||
if time then
|
||||
hideTime = time + GetTime()
|
||||
else
|
||||
hideTime = nil
|
||||
end
|
||||
if player then
|
||||
targetType = "player"
|
||||
targetPlayer = player
|
||||
else
|
||||
targetType = "fixed"
|
||||
targetX, targetY = x, y
|
||||
end
|
||||
end
|
||||
|
||||
function DBM.Arrow:ShowRunTo(...)
|
||||
return show(false, ...)
|
||||
end
|
||||
|
||||
function DBM.Arrow:ShowRunAway(...)
|
||||
return show(true, ...)
|
||||
end
|
||||
|
||||
function DBM.Arrow:Hide(autoHide)
|
||||
frame:Hide()
|
||||
end
|
||||
|
||||
local function endMove()
|
||||
frame:EnableMouse(false)
|
||||
DBM.Arrow:Hide()
|
||||
end
|
||||
|
||||
function DBM.Arrow:Move()
|
||||
targetType = "rotate"
|
||||
runAwayArrow = false
|
||||
hideDistance = 5
|
||||
frame:EnableMouse(true)
|
||||
frame:Show()
|
||||
DBM.Bars:CreateBar(25, DBM_ARROW_MOVABLE, "Interface\\Icons\\Spell_Holy_BorrowedTime")
|
||||
DBM:Unschedule(endMove)
|
||||
DBM:Schedule(25, endMove)
|
||||
end
|
||||
|
||||
function DBM.Arrow:LoadPosition()
|
||||
frame:SetPoint(DBM.Options.ArrowPoint, DBM.Options.ArrowPosX, DBM.Options.ArrowPosY)
|
||||
end
|
||||
Reference in New Issue
Block a user