- Added shared item list - Added options screen - Added toasts - Program now always updates on first run, but continues if update check fails - Updated libcurl to 7.54.0
310 lines
10 KiB
Lua
310 lines
10 KiB
Lua
-- Path of Building
|
|
--
|
|
-- Module: Tree Tab
|
|
-- Passive skill tree tab for the current build.
|
|
--
|
|
local launch, main = ...
|
|
|
|
local ipairs = ipairs
|
|
local t_insert = table.insert
|
|
local m_min = math.min
|
|
|
|
local TreeTabClass = common.NewClass("TreeTab", "ControlHost", function(self, build)
|
|
self.ControlHost()
|
|
|
|
self.build = build
|
|
|
|
self.viewer = common.New("PassiveTreeView")
|
|
|
|
self.specList = { }
|
|
self.specList[1] = common.New("PassiveSpec", build)
|
|
self:SetActiveSpec(1)
|
|
|
|
self.anchorControls = common.New("Control", nil, 0, 0, 0, 20)
|
|
self.controls.specSelect = common.New("DropDownControl", {"LEFT",self.anchorControls,"RIGHT"}, 0, 0, 150, 20, nil, function(sel, selVal)
|
|
if self.specList[sel] then
|
|
self.build.modFlag = true
|
|
self:SetActiveSpec(sel)
|
|
else
|
|
self:OpenSpecManagePopup()
|
|
end
|
|
end)
|
|
self.controls.specSelect.tooltipFunc = function(mode, sel, selVal)
|
|
if mode ~= "OUT" then
|
|
local spec = self.specList[sel]
|
|
if spec then
|
|
local used, ascUsed, sockets = spec:CountAllocNodes()
|
|
main:AddTooltipLine(16, "Class: "..spec.curClassName)
|
|
main:AddTooltipLine(16, "Ascendancy: "..spec.curAscendClassName)
|
|
main:AddTooltipLine(16, "Points used: "..used)
|
|
if sockets > 0 then
|
|
main:AddTooltipLine(16, "Jewel sockets: "..sockets)
|
|
end
|
|
if sel ~= self.activeSpec then
|
|
local calcFunc, calcBase = self.build.calcsTab:GetMiscCalculator()
|
|
if calcFunc then
|
|
local output = calcFunc({ spec = spec })
|
|
self.build:AddStatComparesToTooltip(calcBase, output, "^7Switching to this tree will give you:")
|
|
end
|
|
if spec.curClassId == self.build.spec.curClassId then
|
|
local respec = 0
|
|
for nodeId, node in pairs(self.build.spec.allocNodes) do
|
|
if node.type ~= "classStart" and node.type ~= "ascendClassStart" and not spec.allocNodes[nodeId] then
|
|
if node.ascendancyName then
|
|
respec = respec + 5
|
|
else
|
|
respec = respec + 1
|
|
end
|
|
end
|
|
end
|
|
if respec > 0 then
|
|
main:AddTooltipLine(16, "^7Switching to this tree requires "..respec.." refund points.")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
self.controls.reset = common.New("ButtonControl", {"LEFT",self.controls.specSelect,"RIGHT"}, 8, 0, 60, 20, "Reset", function()
|
|
main:OpenConfirmPopup("Reset Tree", "Are you sure you want to reset your passive tree?", "Reset", function()
|
|
self.build.spec:ResetNodes()
|
|
self.build.spec:AddUndoState()
|
|
self.build.buildFlag = true
|
|
end)
|
|
end)
|
|
self.controls.import = common.New("ButtonControl", {"LEFT",self.controls.reset,"RIGHT"}, 8, 0, 90, 20, "Import Tree", function()
|
|
self:OpenImportPopup()
|
|
end)
|
|
self.controls.export = common.New("ButtonControl", {"LEFT",self.controls.import,"RIGHT"}, 8, 0, 90, 20, "Export Tree", function()
|
|
self:OpenExportPopup()
|
|
end)
|
|
self.controls.treeSearch = common.New("EditControl", {"LEFT",self.controls.export,"RIGHT"}, 8, 0, 300, 20, "", "Search", "%c%(%)", 100, function(buf)
|
|
self.viewer.searchStr = buf
|
|
end)
|
|
self.controls.treeHeatMap = common.New("CheckBoxControl", {"LEFT",self.controls.treeSearch,"RIGHT"}, 130, 0, 20, "Show Node Power:", function(state)
|
|
self.viewer.showHeatMap = state
|
|
end)
|
|
self.controls.treeHeatMap.tooltip = function()
|
|
local offCol, defCol = main.nodePowerTheme:match("(%a+)/(%a+)")
|
|
return "When enabled, an estimate of the offensive and defensive strength of\neach unallocated passive is calculated and displayed visually.\nOffensive power shows as "..offCol:lower()..", defensive power as "..defCol:lower().."."
|
|
end
|
|
end)
|
|
|
|
function TreeTabClass:Draw(viewPort, inputEvents)
|
|
self.anchorControls.x = viewPort.x + 4
|
|
self.anchorControls.y = viewPort.y + viewPort.height - 24
|
|
|
|
for id, event in ipairs(inputEvents) do
|
|
if event.type == "KeyDown" then
|
|
if event.key == "z" and IsKeyDown("CTRL") then
|
|
self.build.spec:Undo()
|
|
self.build.buildFlag = true
|
|
inputEvents[id] = nil
|
|
elseif event.key == "y" and IsKeyDown("CTRL") then
|
|
self.build.spec:Redo()
|
|
self.build.buildFlag = true
|
|
inputEvents[id] = nil
|
|
end
|
|
end
|
|
end
|
|
self:ProcessControlsInput(inputEvents, viewPort)
|
|
|
|
local treeViewPort = { x = viewPort.x, y = viewPort.y, width = viewPort.width, height = viewPort.height - 32 }
|
|
self.viewer:Draw(self.build, treeViewPort, inputEvents)
|
|
|
|
self.controls.specSelect.sel = self.activeSpec
|
|
wipeTable(self.controls.specSelect.list)
|
|
for id, spec in ipairs(self.specList) do
|
|
t_insert(self.controls.specSelect.list, spec.title or "Default")
|
|
end
|
|
t_insert(self.controls.specSelect.list, "Manage trees...")
|
|
if not self.controls.treeSearch.hasFocus then
|
|
self.controls.treeSearch:SetText(self.viewer.searchStr)
|
|
end
|
|
self.controls.treeHeatMap.state = self.viewer.showHeatMap
|
|
|
|
SetDrawLayer(1)
|
|
|
|
SetDrawColor(0.05, 0.05, 0.05)
|
|
DrawImage(nil, viewPort.x, viewPort.y + viewPort.height - 28, viewPort.width, 28)
|
|
SetDrawColor(0.85, 0.85, 0.85)
|
|
DrawImage(nil, viewPort.x, viewPort.y + viewPort.height - 32, viewPort.width, 4)
|
|
|
|
self:DrawControls(viewPort)
|
|
end
|
|
|
|
function TreeTabClass:Load(xml, dbFileName)
|
|
self.specList = { }
|
|
if xml.elem == "Spec" then
|
|
-- Import single spec from old build
|
|
self.specList[1] = common.New("PassiveSpec", self.build)
|
|
self.specList[1]:Load(xml, dbFileName)
|
|
self.activeSpec = 1
|
|
self.build.spec = self.specList[1]
|
|
return
|
|
end
|
|
for _, node in pairs(xml) do
|
|
if type(node) == "table" then
|
|
if node.elem == "Spec" then
|
|
local newSpec = common.New("PassiveSpec", self.build)
|
|
newSpec:Load(node, dbFileName)
|
|
t_insert(self.specList, newSpec)
|
|
end
|
|
end
|
|
end
|
|
if not self.specList[1] then
|
|
self.specList[1] = common.New("PassiveSpec", self.build)
|
|
end
|
|
self:SetActiveSpec(tonumber(xml.attrib.activeSpec) or 1)
|
|
end
|
|
|
|
function TreeTabClass:PostLoad()
|
|
for _, spec in ipairs(self.specList) do
|
|
spec:BuildAllDependsAndPaths()
|
|
end
|
|
end
|
|
|
|
function TreeTabClass:Save(xml)
|
|
xml.attrib = {
|
|
activeSpec = tostring(self.activeSpec)
|
|
}
|
|
for specId, spec in ipairs(self.specList) do
|
|
if specId == self.activeSpec then
|
|
-- Update this spec's jewels from the socket slots
|
|
for _, slot in pairs(self.build.itemsTab.slots) do
|
|
if slot.nodeId then
|
|
spec.jewels[slot.nodeId] = slot.selItemId
|
|
end
|
|
end
|
|
end
|
|
local child = {
|
|
elem = "Spec"
|
|
}
|
|
spec:Save(child)
|
|
t_insert(xml, child)
|
|
end
|
|
self.modFlag = false
|
|
end
|
|
|
|
function TreeTabClass:SetActiveSpec(specId)
|
|
local prevSpec = self.build.spec
|
|
self.activeSpec = m_min(specId, #self.specList)
|
|
local curSpec = self.specList[self.activeSpec]
|
|
self.build.spec = curSpec
|
|
self.build.buildFlag = true
|
|
for _, slot in pairs(self.build.itemsTab.slots) do
|
|
if slot.nodeId then
|
|
if prevSpec then
|
|
-- Update the previous spec's jewel for this slot
|
|
prevSpec.jewels[slot.nodeId] = slot.selItemId
|
|
end
|
|
if curSpec.jewels[slot.nodeId] then
|
|
-- Socket the jewel for the new spec
|
|
slot.selItemId = curSpec.jewels[slot.nodeId]
|
|
end
|
|
end
|
|
end
|
|
if self.build.itemsTab.orderList[1] then
|
|
-- Update item slots if items have been loaded already
|
|
self.build.itemsTab:PopulateSlots()
|
|
end
|
|
end
|
|
|
|
function TreeTabClass:OpenSpecManagePopup()
|
|
main:OpenPopup(370, 290, "Manage Passive Trees", {
|
|
common.New("PassiveSpecList", nil, 0, 50, 350, 200, self),
|
|
common.New("ButtonControl", nil, 0, 260, 90, 20, "Done", function()
|
|
main:ClosePopup()
|
|
end),
|
|
})
|
|
end
|
|
|
|
function TreeTabClass:OpenImportPopup()
|
|
local controls = { }
|
|
local function decodeTreeLink(treeLink)
|
|
local errMsg = self.build.spec:DecodeURL(treeLink)
|
|
if errMsg then
|
|
controls.msg.label = "^1"..errMsg
|
|
else
|
|
self.build.spec:AddUndoState()
|
|
self.build.buildFlag = true
|
|
main:ClosePopup()
|
|
end
|
|
end
|
|
controls.editLabel = common.New("LabelControl", nil, 0, 20, 0, 16, "Enter passive tree link:")
|
|
controls.edit = common.New("EditControl", nil, 0, 40, 350, 18, "", nil, nil, nil, function(buf)
|
|
controls.msg.label = ""
|
|
end)
|
|
controls.msg = common.New("LabelControl", nil, 0, 58, 0, 16, "")
|
|
controls.import = common.New("ButtonControl", nil, -45, 80, 80, 20, "Import", function()
|
|
local treeLink = controls.edit.buf
|
|
if #treeLink == 0 then
|
|
return
|
|
end
|
|
if treeLink:match("poeurl%.com/") then
|
|
controls.import.enabled = false
|
|
controls.msg.label = "Resolving PoEURL link..."
|
|
local id = LaunchSubScript([[
|
|
local treeLink = ...
|
|
local curl = require("lcurl.safe")
|
|
local easy = curl.easy()
|
|
easy:setopt_url(treeLink)
|
|
easy:setopt_writefunction(function(data)
|
|
return true
|
|
end)
|
|
easy:perform()
|
|
local redirect = easy:getinfo(curl.INFO_REDIRECT_URL)
|
|
easy:close()
|
|
if not redirect or redirect:match("poeurl%.com/") then
|
|
return nil, "Failed to resolve PoEURL link"
|
|
end
|
|
return redirect
|
|
]], "", "", treeLink)
|
|
if id then
|
|
launch:RegisterSubScript(id, function(treeLink, errMsg)
|
|
if errMsg then
|
|
controls.msg.label = "^1"..errMsg
|
|
controls.import.enabled = true
|
|
else
|
|
decodeTreeLink(treeLink)
|
|
end
|
|
end)
|
|
end
|
|
else
|
|
decodeTreeLink(treeLink)
|
|
end
|
|
end)
|
|
controls.cancel = common.New("ButtonControl", nil, 45, 80, 80, 20, "Cancel", function()
|
|
main:ClosePopup()
|
|
end)
|
|
main:OpenPopup(380, 110, "Import Tree", controls, "import", "edit")
|
|
end
|
|
|
|
function TreeTabClass:OpenExportPopup()
|
|
local treeLink = self.build.spec:EncodeURL("https://www.pathofexile.com/passive-skill-tree/")
|
|
local popup
|
|
local controls = { }
|
|
controls.label = common.New("LabelControl", nil, 0, 20, 0, 16, "Passive tree link:")
|
|
controls.edit = common.New("EditControl", nil, 0, 40, 350, 18, treeLink, nil, "%Z")
|
|
controls.shrink = common.New("ButtonControl", nil, -90, 70, 140, 20, "Shrink with PoEURL", function()
|
|
controls.shrink.enabled = false
|
|
controls.shrink.label = "Shrinking..."
|
|
launch:DownloadPage("http://poeurl.com/shrink.php?url="..treeLink, function(page, errMsg)
|
|
controls.shrink.label = "Done"
|
|
if errMsg or not page:match("%S") then
|
|
main:OpenMessagePopup("PoEURL Shortener", "Failed to get PoEURL link. Try again later.")
|
|
else
|
|
treeLink = "http://poeurl.com/"..page
|
|
controls.edit:SetText(treeLink)
|
|
popup:SelectControl(controls.edit)
|
|
end
|
|
end)
|
|
end)
|
|
controls.copy = common.New("ButtonControl", nil, 30, 70, 80, 20, "Copy", function()
|
|
Copy(treeLink)
|
|
end)
|
|
controls.done = common.New("ButtonControl", nil, 120, 70, 80, 20, "Done", function()
|
|
main:ClosePopup()
|
|
end)
|
|
popup = main:OpenPopup(380, 100, "Export Tree", controls, "done", "edit")
|
|
end |