Skip to content

Commit 587114e

Browse files
committed
Add Path of Exile 2 BuildPlanner (.build) export
Writes a .build JSON file to the in-game BuildPlanner folder (Documents/My Games/Path of Exile 2/BuildPlanner/) from a new section in the Import tab. Tree specs, item sets and skill sets export as level-bracketed loadouts via the format's level_interval field, with per-set Lvl Min/Max in each tab's Manage popup. The New Loadout dialog also takes a level range that propagates across the matching tree spec, item set and skill set on save. New sets auto-preset on a 30-level cadence (1-30, 30-60, 60-90, 90-100). Per-passive and per-gem author notes via Shift+Right-Click on the Tree and Skills tabs. The keybind hint and any existing note are shown in the respective tooltips. Notes flow into the exported additional_text; the format's Custom Text markup (<bold>{}, <italic>{}, <red>{}, <rgb(R,G,B)>{}) is preserved in the input. Non-unique items render rolled title + base type + mod list using the same markup (italic implicits, plain explicits). Active skills carry a "Level N[, Q% Quality]" hint when no note is set; trivial Level 1 / 0% Quality on uncustomised support gems is suppressed to avoid noise. Skill IDs use the Gems.lua table key to work around the singular "Metadata/Items/Gem/" typo on the gameId field of ~486 auto-generated entries. Passive IDs are emitted as PassiveSkills.Id strings (e.g. "projectiles18", "AscendancyMercenary2Notable5"). This required adding stringId to src/Export/Scripts/passivetree.lua and regenerating src/TreeData/0_4/tree.lua against GGPK. Older tree versions (0_1, 0_2, 0_3) still carry numeric IDs and fall back accordingly with a one-time console warning until they're regenerated too.
1 parent b9aa7fb commit 587114e

16 files changed

Lines changed: 10073 additions & 4539 deletions

src/Classes/GemSelectControl.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,12 @@ function GemSelectClass:AddGemTooltip(gemInstance)
588588
self.tooltip:AddLine(fontSizeBig, colorCodes.UNIQUE .. line, "FONTIN SC ITALIC")
589589
end
590590
end
591+
-- Author note (Shift+Right-Click to set/edit) emitted into the PoE2 .build export.
592+
self.tooltip:AddSeparator(10)
593+
self.tooltip:AddLine(14, colorCodes.TIP.."Shift + Right-Click to add a build note (PoE2 .build export)")
594+
if gemInstance.note and gemInstance.note ~= "" then
595+
self.tooltip:AddLine(14, "^7Note: "..gemInstance.note)
596+
end
591597
end
592598

593599
function GemSelectClass:AddGrantedEffectInfo(gemInstance, grantedEffect, addReq)
@@ -863,6 +869,18 @@ function GemSelectClass:OnKeyDown(key, doubleClick)
863869
self:ScrollSelIntoView()
864870
end
865871
end
872+
elseif key == "RIGHTBUTTON" and IsKeyDown("SHIFT") then
873+
-- Shift+Right-Click: edit the per-gem author note for the PoE2 .build export.
874+
local gemList = self.skillsTab.displayGroup and self.skillsTab.displayGroup.gemList
875+
local gemInstance = gemList and gemList[self.index]
876+
if gemInstance then
877+
local title = "Note: " .. ((gemInstance.nameSpec and gemInstance.nameSpec ~= "") and gemInstance.nameSpec or "Gem")
878+
main:OpenNoteEditPopup(title, gemInstance.note, function(text)
879+
gemInstance.note = text
880+
self.skillsTab.build.modFlag = true
881+
end)
882+
end
883+
return self
866884
elseif key == "RETURN" or key == "RIGHTBUTTON" then
867885
self.dropped = true
868886
self:UpdateSortCache()

src/Classes/ImportTab.lua

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,24 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
331331
end
332332
end
333333

334+
-- Path of Exile 2 BuildPlanner export
335+
local BuildExportPoE2 = require("Modules/BuildExportPoE2")
336+
self.controls.sectionPoE2Export = new("SectionControl", {"TOPLEFT",self.controls.sectionBuild,"BOTTOMLEFT",true}, {0, 18, 650, 112}, "Export to Path of Exile 2 BuildPlanner")
337+
self.controls.poe2ExportDesc = new("LabelControl", {"TOPLEFT",self.controls.sectionPoE2Export,"TOPLEFT"}, {6, 14, 0, 16}, "^7Save this build as a .build file the in-game BuildPlanner can load.")
338+
self.controls.poe2ExportDesc2 = new("LabelControl", {"TOPLEFT",self.controls.poe2ExportDesc,"BOTTOMLEFT"}, {0, 2, 0, 14}, "^xAAAAAATree specs, item sets and skill sets are exported as level-bracketed loadouts.")
339+
self.controls.poe2ExportDesc3 = new("LabelControl", {"TOPLEFT",self.controls.poe2ExportDesc2,"BOTTOMLEFT"}, {0, 2, 0, 14}, "^xAAAAAAEdit each set's level range in its Manage popup.")
340+
self.poe2ExportStatus = ""
341+
self.controls.poe2ExportPath = new("EditControl", {"TOPLEFT",self.controls.poe2ExportDesc3,"BOTTOMLEFT"}, {0, 8, 560, 20}, BuildExportPoE2.DefaultPath(self.build), "Path", nil, 260)
342+
self.controls.poe2ExportSave = new("ButtonControl", {"LEFT",self.controls.poe2ExportPath,"RIGHT"}, {8, 0, 80, 20}, "Save", function()
343+
self:DoPoE2Export(BuildExportPoE2, self.controls.poe2ExportPath.buf)
344+
end)
345+
self.controls.poe2ExportSave.enabled = function()
346+
return self.controls.poe2ExportPath.buf and self.controls.poe2ExportPath.buf ~= ""
347+
end
348+
self.controls.poe2ExportStatusLabel = new("LabelControl", {"TOPLEFT",self.controls.poe2ExportPath,"BOTTOMLEFT"}, {0, 4, 0, 14}, function()
349+
return self.poe2ExportStatus or ""
350+
end)
351+
334352
-- validate the status of the api the first time
335353
self.api:ValidateAuth(function(valid, updateSettings)
336354
if valid then
@@ -355,6 +373,26 @@ function ImportTabClass:SaveApiSettings()
355373
main:SaveSettings()
356374
end
357375

376+
function ImportTabClass:DoPoE2Export(Exporter, path)
377+
local function doWrite()
378+
local ok, err = Exporter.WriteFile(self.build, path)
379+
if ok then
380+
self.poe2ExportStatus = colorCodes.POSITIVE .. "Saved to " .. path
381+
else
382+
self.poe2ExportStatus = colorCodes.NEGATIVE .. (err or "Export failed")
383+
main:OpenMessagePopup("Export Failed", err or "Unknown error")
384+
end
385+
end
386+
-- Confirm overwrite if the file already exists.
387+
local existing = io.open(path, "r")
388+
if existing then
389+
existing:close()
390+
main:OpenConfirmPopup("Overwrite?", "A file already exists at:\n" .. path .. "\n\nOverwrite it?", "Overwrite", doWrite)
391+
else
392+
doWrite()
393+
end
394+
end
395+
358396
function ImportTabClass:Load(xml, fileName)
359397
self.lastRealm = xml.attrib.lastRealm
360398
self.controls.accountRealm:SelByValue(self.lastRealm or main.lastRealm or "PC", "id")

src/Classes/ItemSetListControl.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ local ItemSetListClass = newClass("ItemSetListControl", "ListControl", function(
3636
return self.selValue ~= nil
3737
end
3838
self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
39+
local existing = { }
40+
for _, id in ipairs(itemsTab.itemSetOrderList) do
41+
t_insert(existing, itemsTab.itemSets[id])
42+
end
3943
local newSet = itemsTab:NewItemSet()
44+
require("Modules/BuildExportPoE2").PresetNextLevels(existing, newSet)
4045
self:RenameSet(newSet, true)
4146
end)
4247
end)

src/Classes/ItemsTab.lua

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,8 @@ function ItemsTabClass:Load(xml, dbFileName)
968968
local itemSet = self:NewItemSet(tonumber(node.attrib.id))
969969
itemSet.title = node.attrib.title
970970
itemSet.useSecondWeaponSet = node.attrib.useSecondWeaponSet == "true"
971+
itemSet.levelMin = tonumber(node.attrib.levelMin)
972+
itemSet.levelMax = tonumber(node.attrib.levelMax)
971973
for _, child in ipairs(node) do
972974
if child.elem == "Slot" then
973975
local slotName = child.attrib.name or ""
@@ -1056,7 +1058,7 @@ function ItemsTabClass:Save(xml)
10561058
end
10571059
for _, itemSetId in ipairs(self.itemSetOrderList) do
10581060
local itemSet = self.itemSets[itemSetId]
1059-
local child = { elem = "ItemSet", attrib = { id = tostring(itemSetId), title = itemSet.title, useSecondWeaponSet = tostring(itemSet.useSecondWeaponSet) } }
1061+
local child = { elem = "ItemSet", attrib = { id = tostring(itemSetId), title = itemSet.title, useSecondWeaponSet = tostring(itemSet.useSecondWeaponSet), levelMin = itemSet.levelMin and tostring(itemSet.levelMin) or nil, levelMax = itemSet.levelMax and tostring(itemSet.levelMax) or nil } }
10601062
for slotName, slot in pairs(self.slots) do
10611063
if not slot.nodeId then
10621064
t_insert(child, { elem = "Slot", attrib = { name = slotName, itemId = tostring(itemSet[slotName].selItemId), itemPbURL = itemSet[slotName].pbURL or "", active = itemSet[slotName].active and "true" }})
@@ -2053,7 +2055,49 @@ function ItemsTabClass:OpenItemSetManagePopup()
20532055
controls.sharedList = new("SharedItemSetListControl", nil, {155, 50, 300, 200}, self)
20542056
controls.setList.dragTargetList = { controls.sharedList }
20552057
controls.sharedList.dragTargetList = { controls.setList }
2056-
controls.close = new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
2058+
2059+
-- Level bracket inputs for the .build (PoE2 BuildPlanner) export.
2060+
-- Bound to the row currently selected in the local item-set list.
2061+
local function clampLvl(buf)
2062+
local n = tonumber(buf)
2063+
if not n then return nil end
2064+
n = m_floor(n)
2065+
if n < 0 then n = 0 end
2066+
if n > 100 then n = 100 end
2067+
return n
2068+
end
2069+
local function selectedSet()
2070+
return self.itemSets[controls.setList.selValue]
2071+
end
2072+
controls.lvlLabel = new("LabelControl", nil, {-225, 260, 0, 16}, "^7.build export level range:")
2073+
controls.lvlMin = new("EditControl", nil, {-95, 260, 60, 20}, nil, nil, "%D", 3, function(buf)
2074+
local set = selectedSet()
2075+
if set then
2076+
set.levelMin = clampLvl(buf)
2077+
self.modFlag = true
2078+
end
2079+
end)
2080+
controls.lvlMin.tooltipText = "Lowest character level this item set applies to in the exported .build (1-100). Leave blank to auto-split across item sets."
2081+
controls.lvlDash = new("LabelControl", nil, {-30, 260, 0, 16}, "^7-")
2082+
controls.lvlMax = new("EditControl", nil, {30, 260, 60, 20}, nil, nil, "%D", 3, function(buf)
2083+
local set = selectedSet()
2084+
if set then
2085+
set.levelMax = clampLvl(buf)
2086+
self.modFlag = true
2087+
end
2088+
end)
2089+
controls.lvlMax.tooltipText = "Highest character level this item set applies to in the exported .build (1-100). Leave blank to auto-split across item sets."
2090+
local function refreshLvl()
2091+
local set = selectedSet()
2092+
controls.lvlMin:SetText(set and set.levelMin and tostring(set.levelMin) or "")
2093+
controls.lvlMax:SetText(set and set.levelMax and tostring(set.levelMax) or "")
2094+
end
2095+
controls.setList.OnSelClick = function(listSelf, index, value, doubleClick)
2096+
refreshLvl()
2097+
end
2098+
refreshLvl()
2099+
2100+
controls.close = new("ButtonControl", nil, {180, 260, 90, 20}, "Done", function()
20572101
main:ClosePopup()
20582102
end)
20592103
main:OpenPopup(630, 290, "Manage Item Sets", controls)

src/Classes/PassiveSpec.lua

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,17 @@ function PassiveSpecClass:Init(treeVersion, convert)
9191

9292
-- Keys are node IDs, values are the replacement node
9393
self.hashOverrides = { }
94+
95+
-- Author notes attached to allocated nodes (Shift+Right-Click on a node to
96+
-- set one). Keyed by node id; emitted into the PoE2 .build export as the
97+
-- node's additional_text.
98+
self.nodeNotes = { }
9499
end
95100

96101
function PassiveSpecClass:Load(xml, dbFileName)
97102
self.title = xml.attrib.title
103+
self.levelMin = tonumber(xml.attrib.levelMin)
104+
self.levelMax = tonumber(xml.attrib.levelMax)
98105
local weaponSets = {}
99106
local url
100107
for _, node in pairs(xml) do
@@ -134,6 +141,17 @@ function PassiveSpecClass:Load(xml, dbFileName)
134141
for nodeId in node.attrib.nodes:gmatch("%d+") do
135142
weaponSets[tonumber(nodeId)] = weaponSet
136143
end
144+
elseif node.elem == "Notes" then
145+
for _, child in ipairs(node) do
146+
if child.elem == "Note" and child.attrib.nodeId then
147+
local nid = tonumber(child.attrib.nodeId)
148+
-- Note text lives in the element body (preserves newlines, no XML attribute escaping headaches).
149+
local text = type(child[1]) == "string" and child[1] or child.attrib.text
150+
if nid and text and text ~= "" then
151+
self.nodeNotes[nid] = text
152+
end
153+
end
154+
end
137155
end
138156
end
139157
end
@@ -248,7 +266,9 @@ function PassiveSpecClass:Save(xml)
248266
ascendancyInternalId = tostring(ascendancyInternalId),
249267
secondaryAscendClassId = tostring(self.curSecondaryAscendClassId),
250268
nodes = table.concat(allocNodeIdList, ","),
251-
masteryEffects = table.concat(masterySelections, ",")
269+
masteryEffects = table.concat(masterySelections, ","),
270+
levelMin = self.levelMin and tostring(self.levelMin) or nil,
271+
levelMax = self.levelMax and tostring(self.levelMax) or nil,
252272
}
253273
t_insert(xml, {
254274
-- Legacy format
@@ -298,6 +318,17 @@ function PassiveSpecClass:Save(xml)
298318
end
299319
t_insert(xml, overrides)
300320

321+
-- Per-node author notes (Shift+Right-Click on a node). Stored as element
322+
-- body text so multi-line notes survive without XML attribute escaping.
323+
local notesElem = { elem = "Notes" }
324+
local hasNotes = false
325+
for nodeId, note in pairs(self.nodeNotes) do
326+
if note and note ~= "" then
327+
hasNotes = true
328+
t_insert(notesElem, { elem = "Note", attrib = { nodeId = tostring(nodeId) }, [1] = note })
329+
end
330+
end
331+
if hasNotes then t_insert(xml, notesElem) end
301332
end
302333

303334
function PassiveSpecClass:PostLoad()

src/Classes/PassiveSpecListControl.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ local PassiveSpecListClass = newClass("PassiveSpecListControl", "ListControl", f
3838
newSpec:SelectClass(treeTab.build.spec.curClassId)
3939
newSpec:SelectAscendClass(treeTab.build.spec.curAscendClassId)
4040
newSpec:SelectSecondaryAscendClass(treeTab.build.spec.curSecondaryAscendClassId)
41+
require("Modules/BuildExportPoE2").PresetNextLevels(treeTab.specList, newSpec)
4142
self:RenameSpec(newSpec, "New Tree", true)
4243
end)
4344
self:UpdateItemsTabPassiveTreeDropdown()

src/Classes/PassiveTreeView.lua

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,16 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
433433
elseif treeClick == "RIGHT" then
434434
-- User right-clicked on a node
435435
if hoverNode then
436-
if hoverNode.alloc and (hoverNode.type == "Socket" or hoverNode.containJewelSocket) then
436+
if IsKeyDown("SHIFT") then
437+
-- Shift+Right-Click: open a popup to edit the per-node author note
438+
-- (consumed by the PoE2 .build export as the node's additional_text).
439+
local nodeId = hoverNode.id
440+
local title = "Note: " .. (hoverNode.dn or hoverNode.name or "Passive")
441+
main:OpenNoteEditPopup(title, spec.nodeNotes[nodeId], function(text)
442+
spec.nodeNotes[nodeId] = text
443+
build.modFlag = true
444+
end)
445+
elseif hoverNode.alloc and (hoverNode.type == "Socket" or hoverNode.containJewelSocket) then
437446
local slot = build.itemsTab.sockets[hoverNode.id]
438447
if slot:IsEnabled() then
439448
-- User right-clicked a jewel socket, jump to the item page and focus the corresponding item slot control
@@ -1682,6 +1691,15 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
16821691
tooltip:AddLine(14, colorCodes.TIP.."Tip: Hold Ctrl to hide this tooltip.")
16831692
tooltip:AddLine(14, colorCodes.TIP.."Tip: Press Ctrl+C to copy this node's text.")
16841693
end
1694+
-- Per-node author note (Shift+Right-Click to set/edit) emitted into the PoE2 .build export.
1695+
if node.id and build.spec and build.spec.nodeNotes then
1696+
local existing = build.spec.nodeNotes[node.id]
1697+
tooltip:AddSeparator(10)
1698+
tooltip:AddLine(14, colorCodes.TIP.."Shift + Right-Click to add a build note (PoE2 .build export)")
1699+
if existing and existing ~= "" then
1700+
tooltip:AddLine(14, "^7Note: "..existing)
1701+
end
1702+
end
16851703
end
16861704

16871705
-- Helper function to check if a node is connected to weapon set nodes

src/Classes/SkillSetListControl.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ local SkillSetListClass = newClass("SkillSetListControl", "ListControl", functio
4646
return self.selValue ~= nil
4747
end
4848
self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-4, 0, 60, 18}, "New", function()
49-
self:RenameSet(skillsTab:NewSkillSet(), true)
49+
local existing = { }
50+
for _, id in ipairs(skillsTab.skillSetOrderList) do
51+
t_insert(existing, skillsTab.skillSets[id])
52+
end
53+
local newSet = skillsTab:NewSkillSet()
54+
require("Modules/BuildExportPoE2").PresetNextLevels(existing, newSet)
55+
self:RenameSet(newSet, true)
5056
end)
5157
end)
5258

src/Classes/SkillsTab.lua

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ function SkillsTabClass:LoadSkill(node, skillSetId)
308308
end
309309
gemInstance.level = tonumber(child.attrib.level)
310310
gemInstance.quality = tonumber(child.attrib.quality)
311+
-- Optional author note for the PoE2 .build export (Shift+Right-Click on the gem to set).
312+
gemInstance.note = child.attrib.note
311313
gemInstance.enabled = not child.attrib.enabled and true or child.attrib.enabled == "true"
312314
gemInstance.enableGlobal1 = not child.attrib.enableGlobal1 or child.attrib.enableGlobal1 == "true"
313315
gemInstance.enableGlobal2 = child.attrib.enableGlobal2 == "true"
@@ -393,6 +395,8 @@ function SkillsTabClass:Load(xml, fileName)
393395
if node.elem == "SkillSet" then
394396
local skillSet = self:NewSkillSet(tonumber(node.attrib.id))
395397
skillSet.title = node.attrib.title
398+
skillSet.levelMin = tonumber(node.attrib.levelMin)
399+
skillSet.levelMax = tonumber(node.attrib.levelMax)
396400
t_insert(self.skillSetOrderList, skillSet.id)
397401
for _, subNode in ipairs(node) do
398402
self:LoadSkill(subNode, skillSet.id)
@@ -414,7 +418,7 @@ function SkillsTabClass:Save(xml)
414418
}
415419
for _, skillSetId in ipairs(self.skillSetOrderList) do
416420
local skillSet = self.skillSets[skillSetId]
417-
local child = { elem = "SkillSet", attrib = { id = tostring(skillSetId), title = skillSet.title } }
421+
local child = { elem = "SkillSet", attrib = { id = tostring(skillSetId), title = skillSet.title, levelMin = skillSet.levelMin and tostring(skillSet.levelMin) or nil, levelMax = skillSet.levelMax and tostring(skillSet.levelMax) or nil } }
418422
t_insert(xml, child)
419423

420424
for _, socketGroup in ipairs(skillSet.socketGroupList) do
@@ -454,6 +458,7 @@ function SkillsTabClass:Save(xml)
454458
skillMinionItemSetCalcs = gemInstance.skillMinionItemSetCalcs and tostring(gemInstance.skillMinionItemSetCalcs),
455459
skillMinionSkill = gemInstance.skillMinionSkill and tostring(gemInstance.skillMinionSkill),
456460
skillMinionSkillCalcs = gemInstance.skillMinionSkillCalcs and tostring(gemInstance.skillMinionSkillCalcs),
461+
note = (gemInstance.note and gemInstance.note ~= "") and gemInstance.note or nil,
457462
} }
458463
if gemInstance.statSet then
459464
for grantedEffect, index in pairs(gemInstance.statSet) do
@@ -1261,12 +1266,53 @@ end
12611266

12621267
-- Opens the skill set manager
12631268
function SkillsTabClass:OpenSkillSetManagePopup()
1264-
main:OpenPopup(370, 290, "Manage Skill Sets", {
1265-
new("SkillSetListControl", nil, {0, 50, 350, 200}, self),
1266-
new("ButtonControl", nil, {0, 260, 90, 20}, "Done", function()
1267-
main:ClosePopup()
1268-
end),
1269-
})
1269+
local controls = { }
1270+
controls.setList = new("SkillSetListControl", nil, {0, 50, 350, 200}, self)
1271+
1272+
-- Level bracket inputs for the .build (PoE2 BuildPlanner) export.
1273+
local function clampLvl(buf)
1274+
local n = tonumber(buf)
1275+
if not n then return nil end
1276+
n = math.floor(n)
1277+
if n < 0 then n = 0 end
1278+
if n > 100 then n = 100 end
1279+
return n
1280+
end
1281+
local function selectedSet()
1282+
return self.skillSets[controls.setList.selValue]
1283+
end
1284+
controls.lvlLabel = new("LabelControl", nil, {-95, 260, 0, 16}, "^7Lvl range:")
1285+
controls.lvlMin = new("EditControl", nil, {-30, 260, 60, 20}, nil, nil, "%D", 3, function(buf)
1286+
local set = selectedSet()
1287+
if set then
1288+
set.levelMin = clampLvl(buf)
1289+
self.build.modFlag = true
1290+
end
1291+
end)
1292+
controls.lvlMin.tooltipText = "Lowest character level this skill set applies to in the exported .build (1-100). Leave blank to auto-split across skill sets."
1293+
controls.lvlDash = new("LabelControl", nil, {30, 260, 0, 16}, "^7-")
1294+
controls.lvlMax = new("EditControl", nil, {80, 260, 60, 20}, nil, nil, "%D", 3, function(buf)
1295+
local set = selectedSet()
1296+
if set then
1297+
set.levelMax = clampLvl(buf)
1298+
self.build.modFlag = true
1299+
end
1300+
end)
1301+
controls.lvlMax.tooltipText = "Highest character level this skill set applies to in the exported .build (1-100). Leave blank to auto-split across skill sets."
1302+
local function refreshLvl()
1303+
local set = selectedSet()
1304+
controls.lvlMin:SetText(set and set.levelMin and tostring(set.levelMin) or "")
1305+
controls.lvlMax:SetText(set and set.levelMax and tostring(set.levelMax) or "")
1306+
end
1307+
controls.setList.OnSelClick = function(listSelf, index, value, doubleClick)
1308+
refreshLvl()
1309+
end
1310+
refreshLvl()
1311+
1312+
controls.close = new("ButtonControl", nil, {155, 260, 50, 20}, "Done", function()
1313+
main:ClosePopup()
1314+
end)
1315+
main:OpenPopup(370, 290, "Manage Skill Sets", controls)
12701316
end
12711317

12721318
-- Creates a new skill set

0 commit comments

Comments
 (0)