1175 lignes
36 Kio
Lua
1175 lignes
36 Kio
Lua
QuestHelper_File["dodads.lua"] = "4.0.1.$svnversion$"
|
|
QuestHelper_Loadtime["dodads.lua"] = GetTime()
|
|
|
|
local ofs = 0.000723339 * (GetScreenHeight()/GetScreenWidth() + 1/3) * 70.4;
|
|
local radius = ofs / 1.166666666666667;
|
|
local Minimap = _G.Minimap
|
|
|
|
-- These conversions are nasty, and this entire section needs a serious cleanup.
|
|
local function convertLocation(p)
|
|
QuestHelper: Assert(p, "Wait. What? This is checked before calling this function.")
|
|
QuestHelper: Assert(p.c, "p.c is nil")
|
|
QuestHelper: Assert(p.x, "p.x is nil")
|
|
QuestHelper: Assert(p.y, "p.y is nil")
|
|
return QuestHelper.Astrolabe:FromAbsoluteContinentPosition(p.c, p.x, p.y)
|
|
end
|
|
|
|
local function convertLocationToScreen(p, c, z)
|
|
local pc, _, px, py = convertLocation(p)
|
|
local ox, oy = QuestHelper.Astrolabe:TranslateWorldMapPosition(pc, 0, px, py, c, z)
|
|
--QuestHelper:TextOut(string.format("%f/%f/%f to %f/%f/%f to %f/%f %f/%f", p.c, p.x, p.y, pc, px, py, c, z, ox, oy))
|
|
return ox, oy
|
|
end
|
|
|
|
local function convertRawToScreen(tc, x, y, c, z)
|
|
local rc, _, rx, ry = QuestHelper.Astrolabe:FromAbsoluteContinentPosition(tc, x, y)
|
|
return QuestHelper.Astrolabe:TranslateWorldMapPosition(rc, 0, rx, ry, c, z)
|
|
end
|
|
|
|
local scrolf = CreateFrame("SCROLLFRAME", nil, WorldMapButton)
|
|
scrolf:SetFrameLevel(WorldMapButton:GetFrameLevel()+1)
|
|
scrolf:SetAllPoints()
|
|
scrolf:SetFrameStrata("FULLSCREEN")
|
|
|
|
QuestHelper.map_overlay = CreateFrame("FRAME", nil, scrolf)
|
|
scrolf:SetScrollChild(QuestHelper.map_overlay)
|
|
QuestHelper.map_overlay:SetAllPoints()
|
|
|
|
QuestHelper.map_overlay_uncropped = scrolf
|
|
|
|
local function ClampLine(x1, y1, x2, y2)
|
|
if x1 and y1 and x2 and y2 then
|
|
local x_div, y_div = (x2-x1), (y2-y1)
|
|
local x_0 = y1-x1/x_div*y_div
|
|
local x_1 = y1+(1-x1)/x_div*y_div
|
|
local y_0 = x1-y1/y_div*x_div
|
|
local y_1 = x1+(1-y1)/y_div*x_div
|
|
|
|
if y1 < 0 then
|
|
x1 = y_0
|
|
y1 = 0
|
|
end
|
|
|
|
if y2 < 0 then
|
|
x2 = y_0
|
|
y2 = 0
|
|
end
|
|
|
|
if y1 > 1 then
|
|
x1 = y_1
|
|
y1 = 1
|
|
end
|
|
|
|
if y2 > 1 then
|
|
x2 = y_1
|
|
y2 = 1
|
|
end
|
|
|
|
if x1 < 0 then
|
|
y1 = x_0
|
|
x1 = 0
|
|
end
|
|
|
|
if x2 < 0 then
|
|
y2 = x_0
|
|
x2 = 0
|
|
end
|
|
|
|
if x1 > 1 then
|
|
y1 = x_1
|
|
x1 = 1
|
|
end
|
|
|
|
if x2 > 1 then
|
|
y2 = x_1
|
|
x2 = 1
|
|
end
|
|
|
|
if x1 >= 0 and x2 >= 0 and y1 >= 0 and y2 >= 0 and x1 <= 1 and x2 <= 1 and y1 <= 1 and y2 <= 1 then
|
|
return x1, y1, x2, y2
|
|
end
|
|
end
|
|
end
|
|
|
|
local poi = {}
|
|
local poi_changed = false
|
|
|
|
local poi_dodads = {}
|
|
|
|
function QH_POI_Reset()
|
|
while poi[1] do
|
|
QuestHelper:ReleaseTable(table.remove(poi))
|
|
end
|
|
poi_changed = true
|
|
end
|
|
function QH_POI_Add(p, x, y, d)
|
|
local tab = QuestHelper:CreateTable("dodads_poi")
|
|
tab.p = p
|
|
tab.x = x
|
|
tab.y = y
|
|
tab.desc = d
|
|
table.insert(poi, tab)
|
|
poi_changed = true
|
|
end
|
|
|
|
|
|
local walker_loc
|
|
|
|
function QuestHelper:CreateWorldMapWalker()
|
|
if not self.Astrolabe or not QuestHelper then return end
|
|
QuestHelper: Assert(self == QuestHelper)
|
|
QuestHelper: Assert(self.Astrolabe)
|
|
|
|
local walker = CreateFrame("Button", nil, QuestHelper.map_overlay)
|
|
walker_loc = walker
|
|
walker:SetWidth(0)
|
|
walker:SetHeight(0)
|
|
walker:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", 0, 0)
|
|
walker:Show()
|
|
|
|
walker.phase = 0.0
|
|
walker.dots = {}
|
|
walker.points = {}
|
|
walker.origin = {}
|
|
walker.frame = self
|
|
walker.map_dodads = {}
|
|
walker.used_map_dodads = 0
|
|
|
|
function walker:OnUpdate(elapsed)
|
|
if poi_changed then self:RouteChanged() end -- bzzzzt
|
|
|
|
local out = 0
|
|
|
|
if QuestHelper_Pref.show_ants then
|
|
local points = self.points
|
|
|
|
self.phase = self.phase + elapsed * 0.66
|
|
while self.phase > 1 do self.phase = self.phase - 1 end
|
|
|
|
local w, h = QuestHelper.map_overlay:GetWidth(), -QuestHelper.map_overlay:GetHeight()
|
|
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
|
|
local last_x, last_y = self.frame.Astrolabe:TranslateWorldMapPosition(self.frame.c, self.frame.z, self.frame.x, self.frame.y, c, z)
|
|
local remainder = self.phase
|
|
|
|
for i, pos in ipairs(points) do
|
|
local new_x, new_y = unpack(pos)
|
|
local x1, y1, x2, y2 = ClampLine(last_x, last_y, new_x, new_y)
|
|
last_x, last_y = new_x, new_y
|
|
|
|
if x1 then
|
|
local len = math.sqrt((x1-x2)*(x1-x2)*16/9+(y1-y2)*(y1-y2))
|
|
|
|
if len > 0.0001 then
|
|
local interval = .025/len
|
|
local p = remainder*interval
|
|
|
|
while p < 1 do
|
|
out = out + 1
|
|
local dot = self.dots[out]
|
|
if not dot then
|
|
dot = QuestHelper:CreateDotTexture(self)
|
|
dot:SetDrawLayer("BACKGROUND")
|
|
self.dots[out] = dot
|
|
end
|
|
|
|
dot:ClearAllPoints()
|
|
dot:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x1*w*(1-p)+x2*w*p, y1*h*(1-p)+y2*h*p)
|
|
|
|
p = p + interval
|
|
end
|
|
|
|
remainder = (p-1)/interval
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
while #self.dots > out do
|
|
QuestHelper:ReleaseTexture(table.remove(self.dots))
|
|
end
|
|
end
|
|
|
|
function walker:RouteChanged(route)
|
|
if route then self.route = route end -- we cache it so we can refer to it later when the world map changes
|
|
if not self.route then return end
|
|
|
|
local dbgstr = string.format("%s %s %s %s", tostring(self), tostring(self.frame), tostring(QuestHelper), tostring(QuestHelper and QuestHelper.Astrolabe))
|
|
QuestHelper: Assert(self.frame == QuestHelper, dbgstr)
|
|
QuestHelper: Assert(QuestHelper.Astrolabe, dbgstr)
|
|
|
|
if self.next_item then
|
|
self.next_item:MarkAsNext(false)
|
|
self.next_item = nil
|
|
end
|
|
|
|
if self.frame.Astrolabe.WorldMapVisible then
|
|
local points = self.points
|
|
local cur = self.frame.pos
|
|
|
|
while #points > 0 do self.frame:ReleaseTable(table.remove(points)) end
|
|
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
|
|
for i, obj in ipairs(self.route) do
|
|
--QuestHelper:TextOut(string.format("%s", tostring(obj)))
|
|
|
|
--[[
|
|
local t = QuestHelper:CreateTable()
|
|
t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
|
|
|
|
table.insert(list, t)]]
|
|
|
|
-- We're ignoring travel time for now.
|
|
--[[
|
|
travel_time = travel_time + 60
|
|
obj.travel_time = travel_time]]
|
|
if i > 1 then -- skip the start location
|
|
local t = self.frame:CreateTable()
|
|
t[1], t[2] = convertLocationToScreen(obj.loc, c, z)
|
|
|
|
table.insert(points, t)
|
|
|
|
--if lotsup then print(obj.ignore, obj.loc.x, obj.loc.y, obj.loc.c) end
|
|
end
|
|
--QuestHelper:TextOut(string.format("%s/%s/%s to %s/%s", tostring(obj.c), tostring(obj.x), tostring(obj.y), tostring(t[1]), tostring(t[2])))
|
|
end
|
|
--lotsup = false
|
|
|
|
local cur_dodad = 1
|
|
for i = 2, #self.route do -- 2 because we're skipping the player
|
|
if not self.route[i].ignore or qh_hackery_show_all_map_nodes then
|
|
local dodad = self.map_dodads[cur_dodad]
|
|
if not dodad then
|
|
self.map_dodads[cur_dodad] = self.frame:CreateWorldMapDodad(self.route[i], i == 2)
|
|
else
|
|
self.map_dodads[cur_dodad]:SetObjective(self.route[i], i == 2)
|
|
end
|
|
|
|
if cur_dodad == 1 then
|
|
self.map_dodads[cur_dodad]:MarkAsNext(true)
|
|
self.next_item = self.map_dodads[cur_dodad]
|
|
end
|
|
cur_dodad = cur_dodad + 1
|
|
end
|
|
end
|
|
|
|
if cur_dodad <= self.used_map_dodads then for i = cur_dodad,self.used_map_dodads do
|
|
self.map_dodads[i]:SetObjective(nil, false)
|
|
end end
|
|
|
|
self.used_map_dodads = cur_dodad - 1
|
|
|
|
while #poi > #poi_dodads do
|
|
table.insert(poi_dodads, self.frame:CreateWorldMapMinidad())
|
|
end
|
|
|
|
for i = 1, #poi do
|
|
poi_dodads[i]:SetPosition(poi[i])
|
|
end
|
|
for i = #poi + 1, #poi_dodads do
|
|
poi_dodads[i]:SetPosition()
|
|
end
|
|
end
|
|
end
|
|
|
|
QH_Event("WORLD_MAP_UPDATE", function () walker:RouteChanged() end)
|
|
|
|
QH_Hook(walker, "OnUpdate", walker.OnUpdate)
|
|
|
|
return walker
|
|
end
|
|
|
|
|
|
|
|
function QuestHelper:GetOverlapObjectives(obj)
|
|
local w, h = self.map_overlay:GetWidth(), self.map_overlay:GetHeight()
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
|
|
local list = self.overlap_list
|
|
|
|
if not list then
|
|
list = {}
|
|
self.overlap_list = list
|
|
else
|
|
while table.remove(list) do end
|
|
end
|
|
|
|
local cx, cy = GetCursorPosition()
|
|
|
|
local es = QuestHelper.map_overlay:GetEffectiveScale()
|
|
local ies = 1/es
|
|
|
|
cx, cy = (cx-self.map_overlay:GetLeft()*es)*ies, (self.map_overlay:GetTop()*es-cy)*ies
|
|
|
|
local s = 10*QuestHelper_Pref.scale
|
|
|
|
for i, o in ipairs(walker_loc.route) do
|
|
--QuestHelper: Assert(o, string.format("nil dodads pos issue, o %s", tostring(o)))
|
|
--QuestHelper: Assert(o.pos, string.format("nil dodads pos issue, pos %s", QuestHelper:StringizeTable(o)))
|
|
if not o.ignore or qh_hackery_show_all_map_nodes then
|
|
if o == obj then
|
|
table.insert(list, o)
|
|
else
|
|
local x, y = convertLocationToScreen(o.loc, c, z)
|
|
|
|
if x and y and x > 0 and y > 0 and x < 1 and y < 1 then
|
|
x, y = x*w, y*h
|
|
|
|
if cx >= x-s and cy >= y-s and cx <= x+s and cy <= y+s then
|
|
table.insert(list, o)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
table.sort(list, function(a, b) return (a.distance or 0) < (b.distance or 0) end)
|
|
|
|
return list
|
|
end
|
|
|
|
function QuestHelper:AppendObjectiveProgressToTooltip(o, tooltip, font, depth)
|
|
if o.progress then
|
|
local prog_sort_table = {}
|
|
|
|
local theme = self:GetColourTheme()
|
|
|
|
local indent = (" "):rep(depth or 0)
|
|
|
|
for user, progress in pairs(o.progress) do
|
|
table.insert(prog_sort_table, user)
|
|
end
|
|
|
|
table.sort(prog_sort_table, function(a, b)
|
|
if o.progress[a][3] < o.progress[b][3] then
|
|
return true
|
|
elseif o.progress[a][3] == o.progress[b][3] then
|
|
return a < b
|
|
end
|
|
return false
|
|
end)
|
|
|
|
for i, u in ipairs(prog_sort_table) do
|
|
tooltip:AddDoubleLine(indent..QHFormat("PEER_PROGRESS", u),
|
|
self:ProgressString(o.progress[u][1].."/"..o.progress[u][2],
|
|
o.progress[u][3]), unpack(theme.tooltip))
|
|
|
|
if font then
|
|
local last, name = tooltip:NumLines(), tooltip:GetName()
|
|
local left, right = _G[name.."TextLeft"..last], _G[name.."TextRight"..last]
|
|
|
|
left:SetFont(font, 13)
|
|
right:SetFont(font, 13)
|
|
end
|
|
end
|
|
|
|
while table.remove(prog_sort_table) do end
|
|
end
|
|
end
|
|
|
|
function QuestHelper:AppendObjectiveToTooltip(o)
|
|
local theme = self:GetColourTheme()
|
|
|
|
QuestHelper: Assert(o.map_desc)
|
|
for _, v in ipairs(o.map_desc) do
|
|
self.tooltip:AddLine(v, unpack(theme.tooltip))
|
|
self.tooltip:GetPrevLines():SetFont(self.font.serif, 14)
|
|
end
|
|
|
|
if o.map_desc_chain then
|
|
self:AppendObjectiveToTooltip(o.map_desc_chain)
|
|
else
|
|
self:AppendObjectiveProgressToTooltip(o, self.tooltip, QuestHelper.font.sans)
|
|
|
|
if QuestHelper_Pref.travel_time then
|
|
self.tooltip:AddDoubleLine(QHText("TRAVEL_ESTIMATE"), QHFormat("TRAVEL_ESTIMATE_VALUE", o.distance or 0), unpack(theme.tooltip))
|
|
self.tooltip:GetPrevLines():SetFont(self.font.sans, 11)
|
|
end
|
|
end
|
|
end
|
|
|
|
globx = 0.5
|
|
globy = 0.5
|
|
|
|
function QH_Append_NextObjective(menu)
|
|
local obj = QuestHelper.minimap_marker.obj
|
|
if not obj then return end
|
|
|
|
QuestHelper:AddObjectiveOptionsToMenu(obj, menu)
|
|
end
|
|
|
|
local function rightclick_menu(obj)
|
|
if obj then
|
|
local menu = QuestHelper:CreateMenu()
|
|
local list = QuestHelper:GetOverlapObjectives(obj)
|
|
local item
|
|
|
|
if #list > 1 then
|
|
QuestHelper:CreateMenuTitle(menu, "Objectives")
|
|
|
|
for i, o in ipairs(list) do
|
|
local submenu = QuestHelper:CreateMenu()
|
|
item = QuestHelper:CreateMenuItem(menu, o.map_desc[1])
|
|
item:SetSubmenu(submenu)
|
|
item:AddTexture(QuestHelper:CreateIconTexture(item, o.icon_id or 8), true)
|
|
QuestHelper:AddObjectiveOptionsToMenu(o, submenu)
|
|
end
|
|
else
|
|
QuestHelper:CreateMenuTitle(menu, obj.map_desc[1])
|
|
QuestHelper:AddObjectiveOptionsToMenu(obj, menu)
|
|
end
|
|
|
|
menu:ShowAtCursor()
|
|
end
|
|
end
|
|
|
|
function QuestHelper:CreateWorldMapDodad(objective, nxt)
|
|
local icon = CreateFrame("Button", nil, QuestHelper.map_overlay)
|
|
icon:SetFrameStrata("FULLSCREEN")
|
|
|
|
function icon:SetTooltip(list)
|
|
QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
|
|
QuestHelper.tooltip:ClearLines()
|
|
|
|
local first = true
|
|
|
|
for i, o in ipairs(list) do
|
|
if first then
|
|
first = false
|
|
else
|
|
QuestHelper.tooltip:AddLine("|c80ff0000 . . . . . .|r")
|
|
QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.sans, 8)
|
|
end
|
|
|
|
QuestHelper:AppendObjectiveToTooltip(o)
|
|
end
|
|
|
|
QuestHelper.tooltip:Show()
|
|
end
|
|
|
|
function icon:MarkAsNext(nxt)
|
|
self.next = nxt
|
|
|
|
QH_Hook(self, "OnUpdate", self.OnUpdate)
|
|
end
|
|
|
|
function icon:SetObjective(objective, nxt)
|
|
self:SetHeight(20*QuestHelper_Pref.scale)
|
|
self:SetWidth(20*QuestHelper_Pref.scale)
|
|
|
|
if self.dot then
|
|
QuestHelper:ReleaseTexture(self.dot)
|
|
self.dot = nil
|
|
end
|
|
|
|
if self.bg then
|
|
QuestHelper:ReleaseTexture(self.bg)
|
|
self.bg = nil
|
|
end
|
|
|
|
if objective then
|
|
self.objective = objective
|
|
|
|
if nxt then
|
|
self.bg = QuestHelper:CreateIconTexture(self, 13)
|
|
elseif objective.map_highlight then
|
|
self.bg = QuestHelper:CreateIconTexture(self, 14)
|
|
else
|
|
self.bg = QuestHelper:CreateIconTexture(self, 16)
|
|
end
|
|
|
|
self.dot = QuestHelper:CreateIconTexture(self, objective.icon_id or 8)
|
|
|
|
self.bg:SetDrawLayer("BACKGROUND")
|
|
self.bg:SetAllPoints()
|
|
self.dot:SetPoint("TOPLEFT", self, "TOPLEFT", 3*QuestHelper_Pref.scale, -3*QuestHelper_Pref.scale)
|
|
self.dot:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -3*QuestHelper_Pref.scale, 3*QuestHelper_Pref.scale)
|
|
|
|
QuestHelper: Assert(objective, "Missing objective.")
|
|
QuestHelper: Assert(objective.loc, "Missing Location.")
|
|
local locarray = {convertLocation(objective.loc)}
|
|
QuestHelper: Assert(locarray, "Hmm, we aren't getting anything from the function... Why?")
|
|
QuestHelper: Assert(locarray[1] and locarray[2] and locarray[3] and locarray[4], "Location conversion failed. " .. tostring(locarray[1]) .. " " .. tostring(locarray[2]) .. " " .. tostring(locarray[3]) .. " " .. tostring(locarray[4]))
|
|
QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(objective.loc))
|
|
--QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, 0, 0, globx, globy)
|
|
else
|
|
self.objective = nil
|
|
self:Hide()
|
|
self.next = false
|
|
self:OnUpdate(0)
|
|
end
|
|
end
|
|
|
|
local triangle_r, triangle_g, triangle_b = 1.0, 0.3, 0
|
|
local triangle_opacity = 0.6
|
|
|
|
function icon:CreateTriangles(solid, tritarget, tristartat, linetarget, linestartat, parent)
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
|
|
local function makeline(ax, ay, bx, by)
|
|
local tri = linetarget[linestartat]
|
|
if not tri then
|
|
tri = CreateLine(parent)
|
|
table.insert(linetarget, tri)
|
|
end
|
|
linestartat = linestartat + 1
|
|
|
|
tri:SetLine(ax, ay, bx, by)
|
|
tri:SetVertexColor(0, 0, 0, 0)
|
|
tri:Show()
|
|
end
|
|
|
|
for _, v in ipairs(solid) do
|
|
local adjx, adjy = v[1], v[2]
|
|
local x, y = convertRawToScreen(v.continent, v[1], v[2], c, z)
|
|
--print("matchup", c, v.continent, x, y)
|
|
if x and y then
|
|
local lx, ly = convertRawToScreen(v.continent, adjx + v[3], adjy + v[4], c, z)
|
|
local linemode = false
|
|
|
|
local lidx = 5
|
|
while lidx <= #v do
|
|
if type(v[lidx]) == "string" then
|
|
if v[lidx] == "d" then
|
|
QuestHelper: Assert(type(lidx) == "number") -- what
|
|
lidx = lidx + 1
|
|
x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
|
|
lx, ly = convertRawToScreen(v.continent, adjx + v[lidx + 2], adjy + v[lidx + 3], c, z)
|
|
lidx = lidx + 4
|
|
elseif v[lidx] == "l" then
|
|
linemode = true
|
|
lidx = lidx + 1
|
|
x, y = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
|
|
lx, ly = x, y
|
|
lidx = lidx + 2
|
|
else
|
|
QuestHelper: Assert(false)
|
|
end
|
|
else
|
|
if not linemode then
|
|
local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
|
|
|
|
local tri = tritarget[tristartat]
|
|
if not tri then
|
|
tri = CreateTriangle(parent)
|
|
table.insert(tritarget, tri)
|
|
end
|
|
tristartat = tristartat + 1
|
|
|
|
tri:SetTriangle(x, y, lx, ly, tx, ty)
|
|
tri:SetVertexColor(0, 0, 0, 0)
|
|
tri:Show()
|
|
|
|
lx, ly = tx, ty
|
|
lidx = lidx + 2
|
|
else
|
|
local tx, ty = convertRawToScreen(v.continent, adjx + v[lidx], adjy + v[lidx + 1], c, z)
|
|
|
|
makeline(x, y, tx, ty)
|
|
|
|
x, y = tx, ty
|
|
lidx = lidx + 2
|
|
end
|
|
end
|
|
end
|
|
|
|
if linemode then
|
|
makeline(x, y, lx, ly)
|
|
end
|
|
end
|
|
end
|
|
|
|
return tristartat, linestartat
|
|
end
|
|
|
|
function icon:SetGlow(list)
|
|
local w, h = QuestHelper.map_overlay:GetWidth(), QuestHelper.map_overlay:GetHeight()
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
local zw = QuestHelper.Astrolabe:GetZoneWidth(c, z)
|
|
|
|
local solids = {}
|
|
|
|
local gid = 1
|
|
for _, v in ipairs(list) do
|
|
--print(v.cluster, v.cluster and v.cluster.solid)
|
|
if v.cluster and v.cluster.solid then
|
|
--print("solidified", #v.cluster.solid)
|
|
solids[v.cluster.solid] = true
|
|
else
|
|
local x, y = convertLocationToScreen(v.loc, c, z)
|
|
if x and y then
|
|
if not self.glow_list then
|
|
self.glow_list = QuestHelper:CreateTable()
|
|
end
|
|
local glo = self.glow_list[gid]
|
|
if not glo then
|
|
glo = QuestHelper:CreateGlowTexture(self)
|
|
self.glow_list[gid] = glo
|
|
end
|
|
gid = gid + 1
|
|
|
|
glo:SetPoint("CENTER", QuestHelper.map_overlay, "TOPLEFT", x*w, -y*h)
|
|
glo:SetVertexColor(triangle_r, triangle_g, triangle_b, 1)
|
|
glo:SetWidth(h / 20)
|
|
glo:SetHeight(h / 20)
|
|
glo:Show()
|
|
end
|
|
end
|
|
end
|
|
|
|
local tid = 1
|
|
local lid = 1
|
|
|
|
for k, _ in pairs(solids) do
|
|
if not self.triangle_list then
|
|
self.triangle_list = QuestHelper:CreateTable()
|
|
end
|
|
if not self.line_list then
|
|
self.line_list = QuestHelper:CreateTable()
|
|
end
|
|
|
|
tid, lid = self:CreateTriangles(k, self.triangle_list, tid, self.line_list, lid, QuestHelper.map_overlay)
|
|
end
|
|
-- call triangle maker here!
|
|
|
|
if self.triangle_list then
|
|
while #self.triangle_list >= tid do
|
|
ReleaseTriangle(table.remove(self.triangle_list))
|
|
end
|
|
|
|
if #self.triangle_list == 0 then
|
|
QuestHelper:ReleaseTable(self.triangle_list)
|
|
self.triangle_list = nil
|
|
end
|
|
end
|
|
|
|
if self.glow_list then
|
|
while #self.glow_list >= gid do
|
|
QuestHelper:ReleaseTexture(table.remove(self.glow_list))
|
|
end
|
|
|
|
if #self.glow_list == 0 then
|
|
QuestHelper:ReleaseTable(self.glow_list)
|
|
self.glow_list = nil
|
|
end
|
|
end
|
|
|
|
if self.line_list then
|
|
while #self.line_list >= lid do
|
|
ReleaseLine(table.remove(self.line_list))
|
|
end
|
|
|
|
if #self.line_list == 0 then
|
|
QuestHelper:ReleaseTable(self.line_list)
|
|
self.line_list = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
icon.show_glow = false
|
|
icon.glow_pct = 0.0
|
|
icon.phase = 0.0
|
|
icon.old_count = 0
|
|
|
|
function icon:OnUpdate(elapsed)
|
|
self.phase = (self.phase + elapsed)%6.283185307179586476925286766559005768394338798750211641949889185
|
|
|
|
if self.next and self.objective and self.objective.cluster.solid and QuestHelper_Pref.zones == "next" then
|
|
|
|
local c, z = QuestHelper.Astrolabe:GetCurrentVirtualMapCZ()
|
|
if self.tri_c ~= c or self.tri_z ~= z then
|
|
-- not entirely happy with this being here, but, welp
|
|
if not self.local_triangle_list then
|
|
self.local_triangle_list = QuestHelper:CreateTable()
|
|
end
|
|
if not self.local_line_list then
|
|
self.local_line_list = QuestHelper:CreateTable()
|
|
end
|
|
|
|
local tid, lid = self:CreateTriangles(self.objective.cluster.solid, self.local_triangle_list, 1, self.local_line_list, 1, QuestHelper.map_overlay)
|
|
|
|
if self.local_triangle_list then
|
|
while #self.local_triangle_list >= tid do
|
|
ReleaseTriangle(table.remove(self.local_triangle_list))
|
|
end
|
|
end
|
|
|
|
if self.local_line_list then
|
|
while #self.local_line_list >= lid do
|
|
ReleaseLine(table.remove(self.local_line_list))
|
|
end
|
|
end
|
|
end
|
|
|
|
self.tri_c, self.tri_z = c, z
|
|
else
|
|
if self.local_triangle_list then
|
|
while #self.local_triangle_list > 0 do
|
|
ReleaseTriangle(table.remove(self.local_triangle_list))
|
|
end
|
|
QuestHelper:ReleaseTable(self.local_triangle_list)
|
|
self.local_triangle_list = nil
|
|
end
|
|
|
|
if self.local_line_list then
|
|
while #self.local_line_list > 0 do
|
|
ReleaseLine(table.remove(self.local_line_list))
|
|
end
|
|
QuestHelper:ReleaseTable(self.local_line_list)
|
|
self.local_line_list = nil
|
|
end
|
|
|
|
self.tri_c, self.tri_z = nil, nil
|
|
end
|
|
|
|
if self.old_count > 0 then
|
|
local list = QuestHelper:GetOverlapObjectives(self.objective)
|
|
|
|
if #list ~= self.old_count then
|
|
self:SetTooltip(list)
|
|
self.old_count = #list
|
|
self:SetGlow(list)
|
|
end
|
|
end
|
|
|
|
if self.show_glow then
|
|
self.glow_pct = math.min(1, self.glow_pct+elapsed*1.5)
|
|
else
|
|
self.glow_pct = math.max(0, self.glow_pct-elapsed*0.5)
|
|
|
|
if self.glow_pct == 0 then
|
|
if self.triangle_list then
|
|
while #self.triangle_list > 0 do
|
|
ReleaseTriangle(table.remove(self.triangle_list))
|
|
end
|
|
QuestHelper:ReleaseTable(self.triangle_list)
|
|
self.triangle_list = nil
|
|
end
|
|
|
|
if self.glow_list then
|
|
while #self.glow_list > 0 do
|
|
QuestHelper:ReleaseTexture(table.remove(self.glow_list))
|
|
end
|
|
QuestHelper:ReleaseTable(self.glow_list)
|
|
self.glow_list = nil
|
|
end
|
|
|
|
if self.line_list then
|
|
while #self.line_list > 0 do
|
|
ReleaseLine(table.remove(self.line_list))
|
|
end
|
|
QuestHelper:ReleaseTable(self.line_list)
|
|
self.line_list = nil
|
|
end
|
|
|
|
if not self.next then
|
|
QH_Hook(self, "OnUpdate", nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.triangle_list then
|
|
for _, tri in ipairs(self.triangle_list) do
|
|
tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity/2)
|
|
end
|
|
end
|
|
if self.line_list then
|
|
for _, tri in ipairs(self.line_list) do
|
|
tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
|
|
end
|
|
end
|
|
if self.glow_list then
|
|
for _, tri in ipairs(self.glow_list) do
|
|
tri:SetVertexColor(triangle_r, triangle_g, triangle_b, self.glow_pct*triangle_opacity)
|
|
end
|
|
end
|
|
if self.local_triangle_list then
|
|
for _, tri in ipairs(self.local_triangle_list) do
|
|
tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity/2)
|
|
end
|
|
end
|
|
if self.local_line_list then
|
|
for _, tri in ipairs(self.local_line_list) do
|
|
tri:SetVertexColor(triangle_b, triangle_g, triangle_r, triangle_opacity)
|
|
end
|
|
end
|
|
end
|
|
|
|
function icon:OnEnter()
|
|
local list = QuestHelper:GetOverlapObjectives(self.objective)
|
|
self:SetTooltip(list)
|
|
self.old_count = #list
|
|
|
|
icon.show_glow = true
|
|
|
|
self:SetGlow(list)
|
|
|
|
QH_Hook(self, "OnUpdate", self.OnUpdate)
|
|
end
|
|
|
|
function icon:OnLeave()
|
|
QuestHelper.tooltip:Hide()
|
|
self.show_glow = false
|
|
self.old_count = 0
|
|
end
|
|
|
|
function icon:OnEvent()
|
|
if self.objective then
|
|
QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, convertLocation(self.objective.loc))
|
|
else
|
|
self.objective = nil
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
function icon:OnClick()
|
|
rightclick_menu(self.objective)
|
|
end
|
|
|
|
QH_Hook(icon, "OnClick", icon.OnClick)
|
|
QH_Hook(icon, "OnEnter", icon.OnEnter)
|
|
QH_Hook(icon, "OnLeave", icon.OnLeave)
|
|
QH_Hook(icon, "OnEvent", icon.OnEvent)
|
|
|
|
icon:RegisterForClicks("RightButtonUp")
|
|
|
|
QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end)
|
|
|
|
icon:SetObjective(objective, nxt)
|
|
return icon
|
|
end
|
|
|
|
|
|
function QuestHelper:CreateWorldMapMinidad(objective, nxt)
|
|
local icon = CreateFrame("Button", nil, QuestHelper.map_overlay)
|
|
icon:SetFrameStrata("FULLSCREEN")
|
|
|
|
function icon:SetPosition(objective)
|
|
self:SetHeight(16*QuestHelper_Pref.scale)
|
|
self:SetWidth(16*QuestHelper_Pref.scale)
|
|
|
|
if self.dot then
|
|
QuestHelper:ReleaseTexture(self.dot)
|
|
self.dot = nil
|
|
end
|
|
|
|
if objective then
|
|
self.objective = objective
|
|
|
|
self.dot = QuestHelper:CreateIconTexture(self, 15)
|
|
self.dot:SetAllPoints()
|
|
self.dot:SetDrawLayer("BACKGROUND")
|
|
|
|
QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, QuestHelper.Astrolabe:FromAbsoluteContinentPosition(QuestHelper_ParentLookup[self.objective.p], self.objective.x, self.objective.y))
|
|
else
|
|
self.objective = nil
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
|
|
function icon:OnEnter()
|
|
local list = QuestHelper:GetOverlapObjectives(self.objective)
|
|
self.old_count = #list
|
|
QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
|
|
QuestHelper.tooltip:ClearLines()
|
|
|
|
QuestHelper.tooltip:AddLine(self.objective.desc)
|
|
|
|
QuestHelper.tooltip:Show()
|
|
end
|
|
|
|
function icon:OnLeave()
|
|
QuestHelper.tooltip:Hide()
|
|
end
|
|
|
|
function icon:OnEvent()
|
|
if self.objective then
|
|
QuestHelper.Astrolabe:PlaceIconOnWorldMap(QuestHelper.map_overlay, self, QuestHelper.Astrolabe:FromAbsoluteContinentPosition(QuestHelper_ParentLookup[self.objective.p], self.objective.x, self.objective.y))
|
|
else
|
|
self.objective = nil
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
--function icon:OnClick()
|
|
--rightclick_menu(self.objective)
|
|
--end
|
|
|
|
--QH_Hook(icon, "OnClick", icon.OnClick)
|
|
QH_Hook(icon, "OnEnter", icon.OnEnter)
|
|
QH_Hook(icon, "OnLeave", icon.OnLeave)
|
|
QH_Hook(icon, "OnEvent", icon.OnEvent)
|
|
|
|
--icon:RegisterForClicks("RightButtonUp")
|
|
|
|
QH_Event("WORLD_MAP_UPDATE", function () icon:OnEvent() end)
|
|
|
|
icon:SetPosition(objective)
|
|
return icon
|
|
end
|
|
|
|
local callbacks = {}
|
|
local last_c, last_z, last_x, last_y, last_desc
|
|
|
|
function QuestHelper:AddWaypointCallback(func, ...)
|
|
local cb = self:CreateTable()
|
|
callbacks[cb] = true
|
|
local len = select("#", ...)
|
|
cb.len = len
|
|
cb.func = func
|
|
for i = 1,len do cb[i] = select(i, ...) end
|
|
cb[len+1] = last_c
|
|
cb[len+2] = last_z
|
|
cb[len+3] = last_x
|
|
cb[len+4] = last_y
|
|
cb[len+5] = last_desc
|
|
|
|
if last_c then
|
|
func(unpack(cb, 1, len+5))
|
|
end
|
|
|
|
return cb
|
|
end
|
|
|
|
function QuestHelper:RemoveWaypointCallback(cb)
|
|
callbacks[cb] = nil
|
|
self:ReleaseTable(cb)
|
|
end
|
|
|
|
function QuestHelper:InvokeWaypointCallbacks(c, z, x, y, desc)
|
|
QuestHelper: Assert(not c or type(c) == "number")
|
|
QuestHelper: Assert(not z or type(z) == "number")
|
|
QuestHelper: Assert(not x or type(x) == "number")
|
|
QuestHelper: Assert(not y or type(y) == "number")
|
|
if c == last_c and z == last_z and desc == last_desc and not x and not y then x, y = last_x, last_y end -- sometimes we may not have up-to-date location, but could still in theory be pointing at the same spot
|
|
|
|
if not c or (x and y) then
|
|
if c ~= last_c or z ~= last_z or x ~= last_x or y ~= last_y or desc ~= last_desc then
|
|
last_c, last_z, last_x, last_y, last_desc = c, z, x, y, desc
|
|
for cb in pairs(callbacks) do
|
|
local len = cb.len
|
|
cb[len+1] = c
|
|
cb[len+2] = z
|
|
cb[len+3] = x
|
|
cb[len+4] = y
|
|
cb[len+5] = desc
|
|
cb.func(unpack(cb, 1, len+5))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuestHelper:SetMinimapObject(minimap)
|
|
Minimap = minimap
|
|
QuestHelper.Astrolabe:SetMinimapObject(minimap)
|
|
QuestHelper.minimap_marker:SetParent(minimap)
|
|
QuestHelper.Astrolabe.processingFrame:SetParent(minimap)
|
|
end
|
|
|
|
--[[ Small parts of the arrow rendering code are thanks to Tomtom, with the following license:
|
|
|
|
-------------------------------------------------------------------------
|
|
Copyright (c) 2006-2007, James N. Whitehead II
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided
|
|
with the distribution.
|
|
* The name or alias of the copyright holder may not be used to endorse
|
|
or promote products derived from this software without specific prior
|
|
written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
---------------------------------------------------------------------------]]
|
|
|
|
function QuestHelper:CreateMipmapDodad()
|
|
local icon = CreateFrame("Button", nil, Minimap)
|
|
icon:Hide()
|
|
icon.recalc_timeout = 0
|
|
|
|
icon.arrow = icon:CreateTexture("BACKGROUND")
|
|
icon.arrow:SetHeight(40)
|
|
icon.arrow:SetWidth(40)
|
|
icon.arrow:SetPoint("CENTER", 0, 0)
|
|
icon.arrow:SetTexture("Interface\\AddOns\\QuestHelper\\MinimapArrow")
|
|
icon.arrow:Hide()
|
|
|
|
icon.phase = 0
|
|
icon.target = {0, 0, 0, 0}
|
|
|
|
icon.bg = QuestHelper:CreateIconTexture(icon, 16)
|
|
icon.bg:SetDrawLayer("BACKGROUND")
|
|
icon.bg:SetAllPoints()
|
|
|
|
function icon:OnUpdate(elapsed)
|
|
local c, z, x, y, textdesc
|
|
if self.obj then
|
|
c, z = QuestHelper.collect_rc, QuestHelper.collect_rz
|
|
if c and z then
|
|
x, y = convertLocationToScreen(self.obj.loc, c, z)
|
|
end
|
|
|
|
if self.obj.map_desc_chain then
|
|
-- the first line will just be an "enroute" line
|
|
textdesc = (self.obj.arrow_desc or self.obj.map_desc[1]) .. "\n" .. (self.obj.map_desc_chain.arrow_desc or self.obj.map_desc_chain.map_desc[1])
|
|
else
|
|
textdesc = (self.obj.arrow_desc or self.obj.map_desc[1])
|
|
end
|
|
|
|
if self.obj.arrow_desc then
|
|
textdesc = self.obj.arrow_desc
|
|
end
|
|
end
|
|
|
|
QuestHelper: Assert(not c or type(c) == "number")
|
|
QuestHelper: Assert(not z or type(z) == "number")
|
|
|
|
-- Deal with waypoint callbacks
|
|
if QuestHelper_Pref.hide or UnitIsDeadOrGhost("player") and not QuestHelper.InBrokenInstance then
|
|
QuestHelper:InvokeWaypointCallbacks()
|
|
else
|
|
QuestHelper:InvokeWaypointCallbacks(c, z, x, y, textdesc)
|
|
end
|
|
|
|
if self.obj and not QuestHelper.InBrokenInstance then
|
|
self:Show() -- really only triggers if the non-broken-instance code is being poked
|
|
|
|
QuestHelper: Assert(self, "Missing self.") -- Yeah right.
|
|
QuestHelper: Assert(self.obj, "Missing objective.")
|
|
QuestHelper: Assert(self.obj.loc, "Missing Location.")
|
|
local locarray = {convertLocation(self.obj.loc)}
|
|
QuestHelper: Assert(locarray, "Hmm, we aren't getting anything from the function... Why?")
|
|
QuestHelper: Assert(locarray[1] and locarray[2] and locarray[3] and locarray[4], "Location conversion failed. " .. tostring(locarray[1]) .. " " .. tostring(locarray[2]) .. " " .. tostring(locarray[3]) .. " " .. tostring(locarray[4]))
|
|
|
|
if not QuestHelper_Pref.hide and QuestHelper.Astrolabe:PlaceIconOnMinimap(self, convertLocation(self.obj.loc)) ~= -1 then
|
|
local edge = QuestHelper.Astrolabe:IsIconOnEdge(self)
|
|
|
|
if edge then
|
|
self.arrow:Show()
|
|
self.dot:Hide()
|
|
self.bg:Hide()
|
|
else
|
|
self.arrow:Hide()
|
|
self.dot:Show()
|
|
self.bg:Show()
|
|
|
|
self.dot:SetAlpha(QuestHelper_Pref.mini_opacity)
|
|
self.bg:SetAlpha(QuestHelper_Pref.mini_opacity)
|
|
end
|
|
|
|
if edge then
|
|
local angle = QuestHelper.Astrolabe:GetDirectionToIcon(self)
|
|
if GetCVar("rotateMinimap") == "1" then
|
|
angle = angle + QuestHelper.Astrolabe:GetFacing()
|
|
end
|
|
|
|
if elapsed then
|
|
if self.phase > 6.283185307179586476925 then
|
|
self.phase = self.phase-6.283185307179586476925+elapsed*3.5
|
|
else
|
|
self.phase = self.phase+elapsed*3.5
|
|
end
|
|
end
|
|
|
|
local scale = 1.0 + 0.1 * math.sin(self.phase)
|
|
|
|
local x, y = scale * math.sin(angle + 3.14159 * 0.75) * math.sqrt(0.5), scale * math.cos(angle + 3.14159 * 0.75) * math.sqrt(0.5)
|
|
self.arrow:SetTexCoord(0.5 - x, 0.5 + y, 0.5 + y, 0.5 + x, 0.5 - y, 0.5 - x, 0.5 + x, 0.5 - y)
|
|
end
|
|
else
|
|
self:Hide()
|
|
end
|
|
else
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
function icon:SetObjective(obj)
|
|
if obj then
|
|
QuestHelper: Assert(obj.loc, "Objective has no location data.")
|
|
QuestHelper: Assert(obj.loc.c, "c is nil")
|
|
QuestHelper: Assert(obj.loc.x, "x is nil")
|
|
QuestHelper: Assert(obj.loc.y, "y is nil")
|
|
end
|
|
self:SetHeight(20*QuestHelper_Pref.scale)
|
|
self:SetWidth(20*QuestHelper_Pref.scale)
|
|
|
|
if obj ~= self.obj then
|
|
self.obj = obj
|
|
|
|
self.recalc_timeout = 0
|
|
|
|
if self.dot then QuestHelper:ReleaseTexture(self.dot) self.dot = nil end
|
|
|
|
if self.obj then
|
|
self.dot = QuestHelper:CreateIconTexture(self, self.obj.icon_id or 8)
|
|
self.dot:SetPoint("TOPLEFT", icon, "TOPLEFT", 2, -2)
|
|
self.dot:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -2, 2)
|
|
end
|
|
|
|
self:OnUpdate(0)
|
|
end
|
|
end
|
|
|
|
function icon:OnEnter()
|
|
if self.obj then
|
|
QuestHelper.tooltip:SetOwner(self, "ANCHOR_CURSOR")
|
|
QuestHelper.tooltip:ClearLines()
|
|
|
|
--[[if self.target[5] then
|
|
QuestHelper.tooltip:AddLine(QHFormat("WAYPOINT_REASON", self.target[5]), unpack(QuestHelper:GetColourTheme().tooltip))
|
|
QuestHelper.tooltip:GetPrevLines():SetFont(QuestHelper.font.serif, 14)
|
|
end]]
|
|
|
|
QuestHelper:AppendObjectiveToTooltip(self.obj)
|
|
QuestHelper.tooltip:Show()
|
|
end
|
|
end
|
|
|
|
function icon:OnLeave()
|
|
QuestHelper.tooltip:Hide()
|
|
end
|
|
|
|
function icon:OnClick()
|
|
rightclick_menu(self.obj)
|
|
end
|
|
|
|
function icon:OnEvent()
|
|
if self.obj then
|
|
self:Show()
|
|
else
|
|
self:Hide()
|
|
end
|
|
end
|
|
|
|
QH_Hook(icon, "OnUpdate", icon.OnUpdate)
|
|
QH_Hook(icon, "OnEnter", icon.OnEnter)
|
|
QH_Hook(icon, "OnLeave", icon.OnLeave)
|
|
QH_Hook(icon, "OnClick", icon.OnClick)
|
|
|
|
icon:RegisterForClicks("RightButtonUp")
|
|
|
|
QH_Event("PLAYER_ENTERING_WORLD", function () icon:OnEvent() end)
|
|
|
|
return icon
|
|
end
|