Skip to content

Commit c8bc528

Browse files
authored
Fix global node allocation rules and add direct connection validation (#1197)
- Add proper allocation/deallocation blocking for global nodes from weapon sets - Implement IsConnectedToWeaponSetNodes() method with path and adjacency checks - Add comprehensive tooltip warnings for blocked actions - Ensure global nodes always use allocMode=0 regardless of allocation context - Fix tooltip cache invalidation when switching between weapon sets
1 parent 2fcdfa1 commit c8bc528

2 files changed

Lines changed: 107 additions & 7 deletions

File tree

src/Classes/PassiveSpec.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -703,12 +703,12 @@ function PassiveSpecClass:AllocNode(node, altPath)
703703
-- Allocate all nodes along the path
704704
if #node.intuitiveLeapLikesAffecting > 0 then
705705
node.alloc = true
706-
node.allocMode = node.ascendancyName and 0 or self.allocMode
706+
node.allocMode = (node.ascendancyName or node.type == "Keystone" or node.type == "Socket" or node.containJewelSocket) and 0 or self.allocMode
707707
self.allocNodes[node.id] = node
708708
else
709709
for _, pathNode in ipairs(altPath or node.path) do
710710
pathNode.alloc = true
711-
pathNode.allocMode = node.ascendancyName and 0 or self.allocMode
711+
pathNode.allocMode = (node.ascendancyName or pathNode.type == "Keystone" or pathNode.type == "Socket" or pathNode.containJewelSocket) and 0 or self.allocMode
712712
-- set path attribute nodes to latest chosen attribute or default to Strength if allocating before choosing an attribute
713713
if pathNode.isAttribute then
714714
self:SwitchAttributeNode(pathNode.id, self.attributeIndex or 1)

src/Classes/PassiveTreeView.lua

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,44 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
270270
end
271271

272272
local hotkeyPressed = IsKeyDown("1") or IsKeyDown("I") or IsKeyDown("2") or IsKeyDown("S") or IsKeyDown("3") or IsKeyDown("D")
273+
274+
-- Helper function to determine if global node allocation should be blocked
275+
local function shouldBlockGlobalNodeAllocation(node)
276+
local isGlobalNode = node.type == "Keystone" or node.type == "Socket" or node.containJewelSocket
277+
278+
if not isGlobalNode or node.alloc or not node.path then
279+
return false
280+
end
281+
282+
local weaponSetMode = spec.allocMode > 0
283+
local connectedToWeaponSetNodes = self:IsConnectedToWeaponSetNodes(node)
284+
285+
-- Only allow allocation from main tree AND node must not be connected to weapon set nodes
286+
local shouldBlock = weaponSetMode or connectedToWeaponSetNodes
287+
288+
return shouldBlock
289+
end
290+
291+
-- Helper function to determine if global node deallocation should be blocked
292+
local function shouldBlockGlobalNodeDeallocation(node)
293+
local isGlobalNode = node.type == "Keystone" or node.type == "Socket" or node.containJewelSocket
294+
295+
if not isGlobalNode or not node.alloc then
296+
return false
297+
end
298+
299+
-- Main-tree global nodes can only be deallocated from main tree
300+
-- Legacy weapon-set global nodes can be deallocated from any mode
301+
local shouldBlock = node.allocMode == 0 and spec.allocMode > 0
302+
303+
return shouldBlock
304+
end
305+
273306
if treeClick == "LEFT" then
274307
if hoverNode then
275308
-- User left-clicked on a node
276-
if hoverNode.alloc then
309+
if hoverNode.alloc and not shouldBlockGlobalNodeDeallocation(hoverNode) then
310+
-- Handle deallocation of allocated nodes
277311
if hoverNode.isAttribute then
278312
-- change to other attribute without needing to deallocate
279313
if hotkeyPressed then
@@ -289,9 +323,8 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
289323
end
290324
spec:AddUndoState()
291325
build.buildFlag = true
292-
elseif hoverNode.path then
293-
-- Node is unallocated and can be allocated, so allocate it
294-
-- attribute switching, unallocated to allocated
326+
elseif hoverNode.path and not shouldBlockGlobalNodeAllocation(hoverNode) then
327+
-- Handle allocation of unallocated nodes
295328
if hoverNode.isAttribute and not hotkeyPressed then
296329
build.treeTab:ModifyAttributePopup(hoverNode)
297330
else
@@ -307,6 +340,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
307340
end
308341
end
309342
elseif treeClick == "RIGHT" then
343+
-- User right-clicked on a node
310344
if hoverNode then
311345
if hoverNode.alloc and (hoverNode.type == "Socket" or hoverNode.containJewelSocket) then
312346
local slot = build.itemsTab.sockets[hoverNode.id]
@@ -840,7 +874,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
840874
-- Draw tooltip
841875
SetDrawLayer(nil, 100)
842876
local size = m_floor(node.size * scale)
843-
if self.tooltip:CheckForUpdate(node, self.showStatDifferences, self.tracePath, launch.devModeAlt, build.outputRevision) then
877+
if self.tooltip:CheckForUpdate(node, self.showStatDifferences, self.tracePath, launch.devModeAlt, build.outputRevision, build.spec.allocMode) then
844878
self:AddNodeTooltip(self.tooltip, node, build, incSmallPassiveSkillEffect)
845879
end
846880
self.tooltip.center = true
@@ -1144,6 +1178,9 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
11441178
if socket ~= nil and socket:IsEnabled() then
11451179
tooltip:AddLine(14, colorCodes.TIP.."Tip: Right click this socket to go to the items page and choose the jewel for this socket.")
11461180
end
1181+
1182+
self:AddGlobalNodeWarningsToTooltip(tooltip, node, build)
1183+
11471184
tooltip:AddLine(14, colorCodes.TIP.."Tip: Hold Shift or Ctrl to hide this tooltip.")
11481185
return
11491186
end
@@ -1403,6 +1440,9 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
14031440
tooltip:AddLine(14, "^7"..#node.depends .. " points gained from unallocating these nodes")
14041441
tooltip:AddLine(14, colorCodes.TIP)
14051442
end
1443+
1444+
self:AddGlobalNodeWarningsToTooltip(tooltip, node, build)
1445+
14061446
if node.type == "Socket" then
14071447
tooltip:AddLine(14, colorCodes.TIP.."Tip: Hold Shift or Ctrl to hide this tooltip.")
14081448
else
@@ -1411,6 +1451,66 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
14111451
end
14121452
end
14131453

1454+
-- Helper function to check if a node is connected to weapon set nodes
1455+
function PassiveTreeViewClass:IsConnectedToWeaponSetNodes(node)
1456+
-- First check the path for weapon set nodes
1457+
if node.path and #node.path > 1 then
1458+
-- Check all nodes in the path (except the first element since it's the target node itself)
1459+
for i = 2, #node.path do
1460+
local pathNode = node.path[i]
1461+
if pathNode.alloc and pathNode.allocMode > 0 then
1462+
return true
1463+
end
1464+
end
1465+
end
1466+
1467+
-- And finally check for direct connections when path is short or empty
1468+
-- (This handles cases where global nodes are directly adjacent to weapon set nodes)
1469+
if node.linked then
1470+
for _, linkedNode in ipairs(node.linked) do
1471+
if linkedNode.alloc and linkedNode.allocMode and linkedNode.allocMode > 0 then
1472+
return true
1473+
end
1474+
end
1475+
end
1476+
1477+
return false
1478+
end
1479+
1480+
-- Helper function to add warnings in the tooltip for global nodes (keystones/jewel sockets)
1481+
function PassiveTreeViewClass:AddGlobalNodeWarningsToTooltip(tooltip, node, build)
1482+
local isGlobalNode = node.type == "Keystone" or node.type == "Socket" or node.containJewelSocket
1483+
1484+
if not isGlobalNode then
1485+
return -- No warning needed for non-global nodes
1486+
end
1487+
1488+
local nodeTypeText = node.type == "Keystone" and "keystones" or "jewel sockets"
1489+
local warningText = ""
1490+
local tipText = ""
1491+
1492+
if not node.alloc and node.path then
1493+
-- Unallocated global node - check allocation conditions
1494+
if build.spec.allocMode > 0 then
1495+
warningText = "Cannot allocate " .. nodeTypeText .. " while weapon set " .. build.spec.allocMode .. " is selected"
1496+
tipText = "Tip: Switch to main tree (Alt+scroll) to allocate " .. nodeTypeText
1497+
elseif self:IsConnectedToWeaponSetNodes(node) then
1498+
warningText = "Cannot allocate " .. nodeTypeText .. " - connected to weapon set nodes"
1499+
tipText = "Tip: Deallocate weapon set nodes in the connection path to allow allocation"
1500+
end
1501+
elseif node.alloc and node.allocMode == 0 and build.spec.allocMode > 0 then
1502+
-- Allocated main-tree global node viewed from weapon set
1503+
warningText = "Cannot deallocate global " .. nodeTypeText .. " from weapon set " .. build.spec.allocMode
1504+
tipText = "Tip: Switch to main tree (Alt+scroll) to deallocate " .. nodeTypeText
1505+
end
1506+
1507+
if warningText ~= "" then
1508+
tooltip:AddSeparator(14)
1509+
tooltip:AddLine(14, colorCodes.WARNING .. warningText)
1510+
tooltip:AddLine(14, colorCodes.TIP .. tipText)
1511+
end
1512+
end
1513+
14141514
function PassiveTreeViewClass:DrawAllocMode(allocMode, viewPort)
14151515
local rgbColor
14161516
if allocMode == 0 then

0 commit comments

Comments
 (0)