@@ -271,42 +271,59 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
271271
272272 local hotkeyPressed = IsKeyDown (" 1" ) or IsKeyDown (" I" ) or IsKeyDown (" 2" ) or IsKeyDown (" S" ) or IsKeyDown (" 3" ) or IsKeyDown (" D" )
273273
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
274+ -- Helper function to check if a path crosses between different weapon sets
275+ local function pathCrossesWeaponSets (node )
276+ return self :PathCrossesWeaponSets (node , spec )
277+ end
277278
278- if not isGlobalNode or node .alloc or not node .path then
279+ -- Unified helper function to determine if node allocation should be blocked
280+ local function shouldBlockNodeAllocation (node )
281+ if not node .path or node .alloc then
279282 return false
280283 end
281284
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 )
293285 local isGlobalNode = node .type == " Keystone" or node .type == " Socket" or node .containJewelSocket
286+ local isAttributeNode = node .isAttribute
287+
288+ -- Fold early - handle global nodes first
289+ if isGlobalNode then
290+ local weaponSetMode = spec .allocMode > 0
291+ local connectedToWeaponSetNodes = self :IsConnectedToWeaponSetNodes (node )
292+ return weaponSetMode or connectedToWeaponSetNodes
293+ elseif isAttributeNode then
294+ -- Attribute nodes follow same rules as regular nodes for weapon set crossing
295+ return pathCrossesWeaponSets (node )
296+ else
297+ -- Regular nodes - check for weapon set path crossing
298+ return pathCrossesWeaponSets (node )
299+ end
300+ end
294301
295- if not isGlobalNode or not node .alloc then
302+ -- Unified helper function to determine if node deallocation should be blocked
303+ local function shouldBlockNodeDeallocation (node )
304+ if not node .alloc then
296305 return false
297306 end
298307
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
308+ local isGlobalNode = node .type == " Keystone" or node .type == " Socket" or node .containJewelSocket
309+ local isAttributeNode = node .isAttribute
310+
311+ -- Fold early - handle global nodes first
312+ if isGlobalNode then
313+ return node .allocMode == 0 and spec .allocMode > 0
314+ elseif isAttributeNode then
315+ -- Attribute nodes follow same rules as regular nodes
316+ return node .allocMode ~= spec .allocMode and node .allocMode ~= 0
317+ else
318+ -- Regular nodes
319+ return node .allocMode ~= spec .allocMode and node .allocMode ~= 0
320+ end
304321 end
305322
306323 if treeClick == " LEFT" then
307324 if hoverNode then
308325 -- User left-clicked on a node
309- if hoverNode .alloc and not shouldBlockGlobalNodeDeallocation (hoverNode ) then
326+ if hoverNode .alloc and not shouldBlockNodeDeallocation (hoverNode ) then
310327 -- Handle deallocation of allocated nodes
311328 if hoverNode .isAttribute then
312329 -- change to other attribute without needing to deallocate
@@ -323,7 +340,7 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
323340 end
324341 spec :AddUndoState ()
325342 build .buildFlag = true
326- elseif hoverNode .path and not shouldBlockGlobalNodeAllocation (hoverNode ) then
343+ elseif hoverNode .path and not shouldBlockNodeAllocation (hoverNode ) then
327344 -- Handle allocation of unallocated nodes
328345 if hoverNode .isAttribute and not hotkeyPressed then
329346 build .treeTab :ModifyAttributePopup (hoverNode )
@@ -350,7 +367,8 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents)
350367 build .itemsTab :SelectControl (slot )
351368 build .viewMode = " ITEMS"
352369 end
353- else
370+ elseif not hoverNode .alloc and not shouldBlockNodeAllocation (hoverNode ) then
371+ -- Only proceed with allocation if it's not blocked
354372 -- a way for us to bypass the popup when allocating attribute nodes, last used hotkey + RMB
355373 -- RMB + non attribute node logic
356374 -- RMB hot-swap logic
@@ -1183,7 +1201,7 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
11831201 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Right click this socket to go to the items page and choose the jewel for this socket." )
11841202 end
11851203
1186- self :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1204+ self :AddNodeWarningsToTooltip (tooltip , node , build )
11871205
11881206 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Hold Shift or Ctrl to hide this tooltip." )
11891207 return
@@ -1448,7 +1466,7 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
14481466 tooltip :AddLine (14 , colorCodes .TIP )
14491467 end
14501468
1451- self :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1469+ self :AddNodeWarningsToTooltip (tooltip , node , build )
14521470
14531471 if node .type == " Socket" then
14541472 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Hold Shift or Ctrl to hide this tooltip." )
@@ -1484,31 +1502,79 @@ function PassiveTreeViewClass:IsConnectedToWeaponSetNodes(node)
14841502 return false
14851503end
14861504
1487- -- Helper function to add warnings in the tooltip for global nodes (keystones/jewel sockets)
1488- function PassiveTreeViewClass :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1505+ -- Helper function to check if a node can be reached from current weapon set without crossing other weapon sets
1506+ function PassiveTreeViewClass :CanReachFromCurrentWeaponSet (node , spec )
1507+ if not node or node .alloc then
1508+ return true -- Already allocated nodes don't need path checking
1509+ end
1510+
1511+ -- Check if any directly linked allocated node belongs to current weapon set or main tree
1512+ local canReachFromCurrentSet = false
1513+
1514+ if node .linked then
1515+ for _ , linkedNode in ipairs (node .linked ) do
1516+ if linkedNode .alloc then
1517+ -- Can reach if linked node is from current weapon set or main tree
1518+ if linkedNode .allocMode == spec .allocMode or linkedNode .allocMode == 0 then
1519+ canReachFromCurrentSet = true
1520+ end
1521+
1522+ -- Block if linked node is from different weapon set
1523+ if linkedNode .allocMode ~= spec .allocMode and linkedNode .allocMode ~= 0 then
1524+ return false
1525+ end
1526+ end
1527+ end
1528+ end
1529+
1530+ return canReachFromCurrentSet
1531+ end
1532+
1533+ -- Helper function to check if a path crosses between different weapon sets
1534+ function PassiveTreeViewClass :PathCrossesWeaponSets (node , spec )
1535+ -- Use the new reachability check instead of path analysis
1536+ return not self :CanReachFromCurrentWeaponSet (node , spec )
1537+ end
1538+
1539+ -- Helper function to add warnings in the tooltip for nodes affected by weapon set rules
1540+ function PassiveTreeViewClass :AddNodeWarningsToTooltip (tooltip , node , build )
14891541 local isGlobalNode = node .type == " Keystone" or node .type == " Socket" or node .containJewelSocket
1542+ local isAttributeNode = node .isAttribute
1543+ local spec = build .spec
14901544
1491- if not isGlobalNode then
1492- return -- No warning needed for non-global nodes
1545+ -- Early fold - no warnings needed for these cases
1546+ if not isGlobalNode and not isAttributeNode and not self :PathCrossesWeaponSets (node , spec ) then
1547+ return
14931548 end
14941549
1495- local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
14961550 local warningText = " "
14971551 local tipText = " "
14981552
14991553 if not node .alloc and node .path then
1500- -- Unallocated global node - check allocation conditions
1501- if build .spec .allocMode > 0 then
1502- warningText = " Cannot allocate " .. nodeTypeText .. " while weapon set " .. build .spec .allocMode .. " is selected"
1503- tipText = " Tip: Switch to main tree (Alt+scroll) to allocate " .. nodeTypeText
1504- elseif self :IsConnectedToWeaponSetNodes (node ) then
1505- warningText = " Cannot allocate " .. nodeTypeText .. " - connected to weapon set nodes"
1506- tipText = " Tip: Deallocate weapon set nodes in the connection path to allow allocation"
1507- end
1508- elseif node .alloc and node .allocMode == 0 and build .spec .allocMode > 0 then
1509- -- Allocated main-tree global node viewed from weapon set
1510- warningText = " Cannot deallocate global " .. nodeTypeText .. " from weapon set " .. build .spec .allocMode
1511- tipText = " Tip: Switch to main tree (Alt+scroll) to deallocate " .. nodeTypeText
1554+ -- Unallocated node warnings
1555+ if isGlobalNode then
1556+ local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
1557+ if spec .allocMode > 0 then
1558+ warningText = " Cannot allocate " .. nodeTypeText .. " while weapon set " .. spec .allocMode .. " is selected"
1559+ tipText = " Tip: Switch to main tree (Alt+scroll) to allocate " .. nodeTypeText
1560+ elseif self :IsConnectedToWeaponSetNodes (node ) then
1561+ warningText = " Cannot allocate " .. nodeTypeText .. " - connected to weapon set nodes"
1562+ tipText = " Tip: Deallocate weapon set nodes in the connection path to allow allocation"
1563+ end
1564+ elseif isAttributeNode or self :PathCrossesWeaponSets (node , spec ) then
1565+ warningText = " Cannot allocate - path crosses between different weapon sets"
1566+ tipText = " Tip: Deallocate conflicting weapon set nodes in the path first"
1567+ end
1568+ elseif node .alloc then
1569+ -- Allocated node warnings
1570+ if isGlobalNode and node .allocMode == 0 and spec .allocMode > 0 then
1571+ local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
1572+ warningText = " Cannot deallocate global " .. nodeTypeText .. " from weapon set " .. spec .allocMode
1573+ tipText = " Tip: Switch to main tree (Alt+scroll) to deallocate " .. nodeTypeText
1574+ elseif (isAttributeNode or not isGlobalNode ) and node .allocMode ~= spec .allocMode and node .allocMode ~= 0 then
1575+ warningText = " Cannot deallocate - node was allocated by weapon set " .. node .allocMode
1576+ tipText = " Tip: Switch to weapon set " .. node .allocMode .. " (Alt+scroll) to deallocate this node"
1577+ end
15121578 end
15131579
15141580 if warningText ~= " " then
0 commit comments