@@ -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
@@ -1179,7 +1197,7 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
11791197 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Right click this socket to go to the items page and choose the jewel for this socket." )
11801198 end
11811199
1182- self :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1200+ self :AddNodeWarningsToTooltip (tooltip , node , build )
11831201
11841202 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Hold Shift or Ctrl to hide this tooltip." )
11851203 return
@@ -1441,7 +1459,7 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi
14411459 tooltip :AddLine (14 , colorCodes .TIP )
14421460 end
14431461
1444- self :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1462+ self :AddNodeWarningsToTooltip (tooltip , node , build )
14451463
14461464 if node .type == " Socket" then
14471465 tooltip :AddLine (14 , colorCodes .TIP .. " Tip: Hold Shift or Ctrl to hide this tooltip." )
@@ -1477,31 +1495,79 @@ function PassiveTreeViewClass:IsConnectedToWeaponSetNodes(node)
14771495 return false
14781496end
14791497
1480- -- Helper function to add warnings in the tooltip for global nodes (keystones/jewel sockets)
1481- function PassiveTreeViewClass :AddGlobalNodeWarningsToTooltip (tooltip , node , build )
1498+ -- Helper function to check if a node can be reached from current weapon set without crossing other weapon sets
1499+ function PassiveTreeViewClass :CanReachFromCurrentWeaponSet (node , spec )
1500+ if not node or node .alloc then
1501+ return true -- Already allocated nodes don't need path checking
1502+ end
1503+
1504+ -- Check if any directly linked allocated node belongs to current weapon set or main tree
1505+ local canReachFromCurrentSet = false
1506+
1507+ if node .linked then
1508+ for _ , linkedNode in ipairs (node .linked ) do
1509+ if linkedNode .alloc then
1510+ -- Can reach if linked node is from current weapon set or main tree
1511+ if linkedNode .allocMode == spec .allocMode or linkedNode .allocMode == 0 then
1512+ canReachFromCurrentSet = true
1513+ end
1514+
1515+ -- Block if linked node is from different weapon set
1516+ if linkedNode .allocMode ~= spec .allocMode and linkedNode .allocMode ~= 0 then
1517+ return false
1518+ end
1519+ end
1520+ end
1521+ end
1522+
1523+ return canReachFromCurrentSet
1524+ end
1525+
1526+ -- Helper function to check if a path crosses between different weapon sets
1527+ function PassiveTreeViewClass :PathCrossesWeaponSets (node , spec )
1528+ -- Use the new reachability check instead of path analysis
1529+ return not self :CanReachFromCurrentWeaponSet (node , spec )
1530+ end
1531+
1532+ -- Helper function to add warnings in the tooltip for nodes affected by weapon set rules
1533+ function PassiveTreeViewClass :AddNodeWarningsToTooltip (tooltip , node , build )
14821534 local isGlobalNode = node .type == " Keystone" or node .type == " Socket" or node .containJewelSocket
1535+ local isAttributeNode = node .isAttribute
1536+ local spec = build .spec
14831537
1484- if not isGlobalNode then
1485- return -- No warning needed for non-global nodes
1538+ -- Early fold - no warnings needed for these cases
1539+ if not isGlobalNode and not isAttributeNode and not self :PathCrossesWeaponSets (node , spec ) then
1540+ return
14861541 end
14871542
1488- local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
14891543 local warningText = " "
14901544 local tipText = " "
14911545
14921546 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
1547+ -- Unallocated node warnings
1548+ if isGlobalNode then
1549+ local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
1550+ if spec .allocMode > 0 then
1551+ warningText = " Cannot allocate " .. nodeTypeText .. " while weapon set " .. spec .allocMode .. " is selected"
1552+ tipText = " Tip: Switch to main tree (Alt+scroll) to allocate " .. nodeTypeText
1553+ elseif self :IsConnectedToWeaponSetNodes (node ) then
1554+ warningText = " Cannot allocate " .. nodeTypeText .. " - connected to weapon set nodes"
1555+ tipText = " Tip: Deallocate weapon set nodes in the connection path to allow allocation"
1556+ end
1557+ elseif isAttributeNode or self :PathCrossesWeaponSets (node , spec ) then
1558+ warningText = " Cannot allocate - path crosses between different weapon sets"
1559+ tipText = " Tip: Deallocate conflicting weapon set nodes in the path first"
1560+ end
1561+ elseif node .alloc then
1562+ -- Allocated node warnings
1563+ if isGlobalNode and node .allocMode == 0 and spec .allocMode > 0 then
1564+ local nodeTypeText = node .type == " Keystone" and " keystones" or " jewel sockets"
1565+ warningText = " Cannot deallocate global " .. nodeTypeText .. " from weapon set " .. spec .allocMode
1566+ tipText = " Tip: Switch to main tree (Alt+scroll) to deallocate " .. nodeTypeText
1567+ elseif (isAttributeNode or not isGlobalNode ) and node .allocMode ~= spec .allocMode and node .allocMode ~= 0 then
1568+ warningText = " Cannot deallocate - node was allocated by weapon set " .. node .allocMode
1569+ tipText = " Tip: Switch to weapon set " .. node .allocMode .. " (Alt+scroll) to deallocate this node"
1570+ end
15051571 end
15061572
15071573 if warningText ~= " " then
0 commit comments