|
|
|
|
local _, MDT = ...
|
|
|
|
|
local twipe, tinsert, tremove, tgetn = table.wipe, table.insert, table.remove, table.getn
|
|
|
|
|
|
|
|
|
|
-- return true if a is more lower-left than b
|
|
|
|
|
local function is_lower_left(a, b)
|
|
|
|
|
if a[1] < b[1] then return true end
|
|
|
|
|
if a[1] > b[1] then return false end
|
|
|
|
|
if a[2] < b[2] then return true end
|
|
|
|
|
if a[2] > b[2] then return true end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- return true if c is left of line a-b
|
|
|
|
|
local function is_left_of(a, b, c)
|
|
|
|
|
local u1 = b[1] - a[1]
|
|
|
|
|
local v1 = b[2] - a[2]
|
|
|
|
|
local u2 = c[1] - a[1]
|
|
|
|
|
local v2 = c[2] - a[2]
|
|
|
|
|
return u1 * v2 - v1 * u2 < 0
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function convex_hull(pts)
|
|
|
|
|
local lower_left = 1
|
|
|
|
|
for i = 2, #pts do
|
|
|
|
|
if is_lower_left(pts[i], pts[lower_left]) then lower_left = i end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local hull = {}
|
|
|
|
|
local final = 1
|
|
|
|
|
local tries = 0
|
|
|
|
|
repeat
|
|
|
|
|
table.insert(hull, lower_left)
|
|
|
|
|
final = 1
|
|
|
|
|
for j = 2, #pts do
|
|
|
|
|
if lower_left == final or is_left_of(pts[lower_left], pts[final], pts[j]) then final = j end
|
|
|
|
|
end
|
|
|
|
|
lower_left = final
|
|
|
|
|
tries = tries + 1
|
|
|
|
|
until final == hull[1] or tries > 100 --deadlocked here otherwise?!?
|
|
|
|
|
|
|
|
|
|
local hullpts = {}
|
|
|
|
|
for _, index in ipairs(hull) do
|
|
|
|
|
table.insert(hullpts, pts[index])
|
|
|
|
|
end
|
|
|
|
|
return hullpts
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function cross(a, b)
|
|
|
|
|
return a[1] * b[2] - a[2] * b[1]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function area(points)
|
|
|
|
|
local res = cross(points[#points], points[1])
|
|
|
|
|
for i = 1, #points - 1 do
|
|
|
|
|
res = res + cross(points[i], points[i + 1])
|
|
|
|
|
end
|
|
|
|
|
return math.abs(res) / 2
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function centroid(pts)
|
|
|
|
|
local rx = 0
|
|
|
|
|
local ry = 0
|
|
|
|
|
for k, v in pairs(pts) do
|
|
|
|
|
rx = rx + v[1]
|
|
|
|
|
ry = ry + v[2]
|
|
|
|
|
end
|
|
|
|
|
rx = rx / #pts
|
|
|
|
|
ry = ry / #pts
|
|
|
|
|
return { rx, ry }
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function expand_polygon(poly, numCirclePoints)
|
|
|
|
|
local res = {}
|
|
|
|
|
local resIndex = 1
|
|
|
|
|
for i = 1, #poly do
|
|
|
|
|
local x = poly[i][1]
|
|
|
|
|
local y = poly[i][2]
|
|
|
|
|
local r = poly[i][3] * 10
|
|
|
|
|
local adjustedNumPoints = math.max(1, math.floor(numCirclePoints * poly[i][3]))
|
|
|
|
|
|
|
|
|
|
for j = 1, adjustedNumPoints do
|
|
|
|
|
local cx = x + r * math.cos(2 * math.pi / adjustedNumPoints * j)
|
|
|
|
|
local cy = y + r * math.sin(2 * math.pi / adjustedNumPoints * j)
|
|
|
|
|
res[resIndex] = { cx, cy, r }
|
|
|
|
|
resIndex = resIndex + 1
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
---TexturePool
|
|
|
|
|
local activeTextures = {}
|
|
|
|
|
local texturePool = {}
|
|
|
|
|
local function getTexture()
|
|
|
|
|
local size = tgetn(texturePool)
|
|
|
|
|
if size == 0 then
|
|
|
|
|
return MDT.main_frame.mapPanelFrame:CreateTexture(nil, "OVERLAY", nil, 0)
|
|
|
|
|
else
|
|
|
|
|
local tex = texturePool[size]
|
|
|
|
|
tremove(texturePool, size)
|
|
|
|
|
tex:SetRotation(0)
|
|
|
|
|
tex:SetTexCoord(0, 1, 0, 1)
|
|
|
|
|
tex:ClearAllPoints()
|
|
|
|
|
tex.coords = nil
|
|
|
|
|
tex.points = nil
|
|
|
|
|
return tex
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function releaseTexture(tex)
|
|
|
|
|
tex:Hide()
|
|
|
|
|
tinsert(texturePool, tex)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
---ReleaseAllActiveTextures
|
|
|
|
|
function MDT:ReleaseHullTextures()
|
|
|
|
|
for k, tex in pairs(activeTextures) do
|
|
|
|
|
releaseTexture(tex)
|
|
|
|
|
end
|
|
|
|
|
twipe(activeTextures)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--make a pool for fontStrings
|
|
|
|
|
local activeFontStrings = {}
|
|
|
|
|
local fontStringPool = {}
|
|
|
|
|
local frameIndex = 0
|
|
|
|
|
local function getFontString()
|
|
|
|
|
local size = tgetn(fontStringPool)
|
|
|
|
|
if size == 0 then
|
|
|
|
|
local fsFrame = CreateFrame("Frame", "MDTFontStringContainerFrame" .. frameIndex, MDT.main_frame.mapPanelFrame)
|
|
|
|
|
frameIndex = frameIndex + 1
|
|
|
|
|
fsFrame:SetFrameStrata("HIGH")
|
|
|
|
|
fsFrame:SetFrameLevel(100)
|
|
|
|
|
fsFrame:SetWidth(40)
|
|
|
|
|
fsFrame:SetHeight(40)
|
|
|
|
|
local fs = fsFrame:CreateFontString(nil, "OVERLAY", nil, 0)
|
|
|
|
|
fs:SetPoint("CENTER", 0, 0)
|
|
|
|
|
fs:SetJustifyH("CENTER")
|
|
|
|
|
fs:SetJustifyV("MIDDLE")
|
|
|
|
|
fs:SetTextColor(1, 1, 1, 1)
|
|
|
|
|
fs:SetFontObject("GameFontNormalMed3Outline")
|
|
|
|
|
fsFrame.fs = fs
|
|
|
|
|
return fsFrame
|
|
|
|
|
else
|
|
|
|
|
local fsFrame = fontStringPool[size]
|
|
|
|
|
tremove(fontStringPool, size)
|
|
|
|
|
fsFrame.fs:SetText("")
|
|
|
|
|
return fsFrame
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function releaseFontString(fsFrame)
|
|
|
|
|
fsFrame:Hide()
|
|
|
|
|
tinsert(fontStringPool, fsFrame)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:ReleaseHullFontStrings()
|
|
|
|
|
for k, fsFrame in pairs(activeFontStrings) do
|
|
|
|
|
releaseFontString(fsFrame)
|
|
|
|
|
end
|
|
|
|
|
twipe(activeFontStrings)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:DrawHullFontString(hull, pullIdx)
|
|
|
|
|
--2. get centroid of each pull
|
|
|
|
|
local center
|
|
|
|
|
if hull and hull[#hull] then
|
|
|
|
|
if #hull > 2 then
|
|
|
|
|
center = centroid(hull)
|
|
|
|
|
center[1] = center[1]
|
|
|
|
|
center[2] = center[2]
|
|
|
|
|
elseif #hull == 2 then
|
|
|
|
|
local x1 = hull[1][1]
|
|
|
|
|
local y1 = hull[1][2]
|
|
|
|
|
local x2 = hull[2][1]
|
|
|
|
|
local y2 = hull[2][2]
|
|
|
|
|
center = { (x1 + x2) / 2, (y1 + y2) / 2 }
|
|
|
|
|
elseif #hull == 1 then
|
|
|
|
|
local x1 = hull[1][1]
|
|
|
|
|
local y1 = hull[1][2]
|
|
|
|
|
center = { x1, y1 + 15 }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if not center then return end
|
|
|
|
|
local fsFrame = getFontString()
|
|
|
|
|
fsFrame.fs:SetText(pullIdx)
|
|
|
|
|
fsFrame:ClearAllPoints()
|
|
|
|
|
fsFrame:SetSize(40, 40)
|
|
|
|
|
fsFrame:SetPoint("CENTER", MDT.main_frame.mapPanelTile1, "TOPLEFT", center[1], center[2])
|
|
|
|
|
fsFrame:Show()
|
|
|
|
|
tinsert(activeFontStrings, fsFrame)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:DrawHullCircle(x, y, size, color, layer, layerSublevel)
|
|
|
|
|
local circle = getTexture()
|
|
|
|
|
circle:SetDrawLayer(layer, layerSublevel)
|
|
|
|
|
circle:SetTexture("Interface\\AddOns\\MythicDungeonTools\\Textures\\Circle_White")
|
|
|
|
|
circle:SetVertexColor(color.r, color.g, color.b, color.a)
|
|
|
|
|
circle:SetWidth(1.1 * size)
|
|
|
|
|
circle:SetHeight(1.1 * size)
|
|
|
|
|
circle:ClearAllPoints()
|
|
|
|
|
circle:SetPoint("CENTER", MDT.main_frame.mapPanelTile1, "TOPLEFT", x, y)
|
|
|
|
|
circle:Show()
|
|
|
|
|
tinsert(activeTextures, circle)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:DrawHullLine(x, y, a, b, size, color, smooth, layer, layerSublevel, lineFactor)
|
|
|
|
|
local line = getTexture()
|
|
|
|
|
line:SetTexture("Interface\\AddOns\\MythicDungeonTools\\Textures\\Square_White")
|
|
|
|
|
line:SetVertexColor(color.r, color.g, color.b, color.a)
|
|
|
|
|
DrawLine(line, MDT.main_frame.mapPanelTile1, x, y, a, b, size, lineFactor and lineFactor or 1.1, "TOPLEFT")
|
|
|
|
|
line:SetDrawLayer(layer, layerSublevel)
|
|
|
|
|
line:Show()
|
|
|
|
|
line.coords = { x, y, a, b }
|
|
|
|
|
tinsert(activeTextures, line)
|
|
|
|
|
if smooth == true then
|
|
|
|
|
MDT:DrawHullCircle(x, y, size * 0.9, color, layer, layerSublevel)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:DrawHull(vertices, pullColor, pullIdx)
|
|
|
|
|
--if true then return end
|
|
|
|
|
local hull = convex_hull(vertices)
|
|
|
|
|
if hull then
|
|
|
|
|
|
|
|
|
|
-- expand_polygon: higher value = more points = more expensive = smoother outlines
|
|
|
|
|
hull = expand_polygon(hull, 30)
|
|
|
|
|
|
|
|
|
|
hull = convex_hull(hull)
|
|
|
|
|
|
|
|
|
|
for i = 1, #hull do
|
|
|
|
|
local a = hull[i]
|
|
|
|
|
local b = hull[1]
|
|
|
|
|
if i ~= #hull then b = hull[i + 1] end
|
|
|
|
|
--layerSublevel go from -8 to 7
|
|
|
|
|
--we rotate through the layerSublevel to avoid collisions
|
|
|
|
|
MDT:DrawHullLine(a[1], a[2], b[1], b[2], 3 * (MDT.scaleMultiplier[MDT:GetDB().currentDungeonIdx] or 1), pullColor,
|
|
|
|
|
true, "ARTWORK", pullIdx % 16 - 8, 1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function getPullVertices(p, blips)
|
|
|
|
|
local vertices = {}
|
|
|
|
|
for enemyIdx, clones in pairs(p) do
|
|
|
|
|
if tonumber(enemyIdx) then
|
|
|
|
|
for _, cloneIdx in pairs(clones) do
|
|
|
|
|
if MDT:IsCloneIncluded(enemyIdx, cloneIdx) then
|
|
|
|
|
for _, blip in pairs(blips) do
|
|
|
|
|
if (blip.enemyIdx == enemyIdx) and (blip.cloneIdx == cloneIdx) then
|
|
|
|
|
local endPoint, endRelativeTo, endRelativePoint, endX, endY = blip:GetPoint()
|
|
|
|
|
table.insert(vertices, { endX, endY, blip.normalScale })
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return vertices
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:DrawAllHulls(pulls)
|
|
|
|
|
MDT:ReleaseHullTextures()
|
|
|
|
|
MDT:ReleaseHullFontStrings()
|
|
|
|
|
local preset = MDT:GetCurrentPreset()
|
|
|
|
|
local blips = MDT:GetDungeonEnemyBlips()
|
|
|
|
|
local vertices
|
|
|
|
|
pulls = pulls or preset.value.pulls
|
|
|
|
|
for pullIdx, p in pairs(pulls) do
|
|
|
|
|
local r, g, b = MDT:DungeonEnemies_GetPullColor(pullIdx, pulls)
|
|
|
|
|
vertices = getPullVertices(p, blips)
|
|
|
|
|
MDT:DrawHull(vertices, { r = r, g = g, b = b, a = 1 }, pullIdx)
|
|
|
|
|
MDT:DrawHullFontString(vertices, pullIdx)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function MDT:FindClosestPull(x, y)
|
|
|
|
|
local preset = MDT:GetCurrentPreset()
|
|
|
|
|
local blips = MDT:GetDungeonEnemyBlips()
|
|
|
|
|
local vertices, hull, center
|
|
|
|
|
local centers = {}
|
|
|
|
|
--1. construct all hulls of pulls in this sublevel
|
|
|
|
|
for pullIdx, p in pairs(preset.value.pulls) do
|
|
|
|
|
vertices = getPullVertices(p, blips)
|
|
|
|
|
hull = convex_hull(vertices)
|
|
|
|
|
--2. get centroid of each pull
|
|
|
|
|
if hull and hull[#hull] then
|
|
|
|
|
if #hull > 2 then
|
|
|
|
|
center = centroid(hull)
|
|
|
|
|
centers[pullIdx] = center
|
|
|
|
|
elseif #hull == 2 then
|
|
|
|
|
local x1 = hull[1][1]
|
|
|
|
|
local y1 = hull[1][2]
|
|
|
|
|
local x2 = hull[2][1]
|
|
|
|
|
local y2 = hull[2][2]
|
|
|
|
|
centers[pullIdx] = { (x1 + x2) / 2, (y1 + y2) / 2 }
|
|
|
|
|
elseif #hull == 1 then
|
|
|
|
|
local x1 = hull[1][1]
|
|
|
|
|
local y1 = hull[1][2]
|
|
|
|
|
centers[pullIdx] = { x1, y1 }
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
--3. find closest centroid
|
|
|
|
|
local centerDist = math.huge
|
|
|
|
|
local centerIndex
|
|
|
|
|
for k, center in pairs(centers) do
|
|
|
|
|
local squaredDist = (x - center[1]) ^ 2 + (y - center[2]) ^ 2
|
|
|
|
|
if squaredDist < centerDist then
|
|
|
|
|
centerDist = squaredDist
|
|
|
|
|
centerIndex = k
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if centerIndex then
|
|
|
|
|
return centerIndex, centers[centerIndex][1], centers[centerIndex][2]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|