From 73dd988b309501fc6f92842e80844756e0782a3f Mon Sep 17 00:00:00 2001 From: unrealdreamz <132005717+unrealdreamz@users.noreply.github.com> Date: Mon, 18 May 2026 18:25:52 -0400 Subject: [PATCH] Fix weapon set branch path allocation --- spec/System/TestPassiveSpec_spec.lua | 71 ++++++++++++++++++++++++++++ src/Classes/PassiveSpec.lua | 19 +++++++- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 spec/System/TestPassiveSpec_spec.lua diff --git a/spec/System/TestPassiveSpec_spec.lua b/spec/System/TestPassiveSpec_spec.lua new file mode 100644 index 0000000000..6618f7e14a --- /dev/null +++ b/spec/System/TestPassiveSpec_spec.lua @@ -0,0 +1,71 @@ +describe("TestPassiveSpec", function() + before_each(function() + newBuild() + end) + + local function pathContains(path, needle) + if not path then + return false + end + for _, node in ipairs(path) do + if node == needle then + return true + end + end + return false + end + + local function isAllocatableNormalNode(node) + return node + and not node.alloc + and node.type == "Normal" + and not node.ascendancyName + and not node.isMultipleChoice + and not node.isMultipleChoiceOption + and #node.intuitiveLeapLikesAffecting == 0 + end + + local function findNormalPathNodeAfter(spec, throughNode) + for _, node in ipairs(throughNode.linked) do + if isAllocatableNormalNode(node) and (node.pathRoot == throughNode or pathContains(node.path, throughNode)) then + return node + end + end + for _, node in pairs(spec.nodes) do + if isAllocatableNormalNode(node) and (node.pathRoot == throughNode or pathContains(node.path, throughNode)) then + return node + end + end + end + + it("normal passive allocation cannot continue through weapon-set-only branches", function() + local spec = build.spec + local startNode = spec.nodes[spec.curClass.startNodeId] + local firstNode = findNormalPathNodeAfter(spec, startNode) + assert.True(firstNode ~= nil) + + spec.allocMode = 0 + spec:AllocNode(firstNode) + assert.are.equals(0, firstNode.allocMode) + + local weaponSetNode = findNormalPathNodeAfter(spec, firstNode) + assert.True(weaponSetNode ~= nil) + + spec.allocMode = 1 + spec:AllocNode(weaponSetNode) + assert.are.equals(1, weaponSetNode.allocMode) + + local blockedNode = findNormalPathNodeAfter(spec, weaponSetNode) + assert.True(blockedNode ~= nil) + assert.True(blockedNode.pathRoot == weaponSetNode or pathContains(blockedNode.path, weaponSetNode)) + + spec.allocMode = 0 + spec:AllocNode(blockedNode) + assert.are_not.equals(true, blockedNode.alloc) + + spec.allocMode = 1 + spec:AllocNode(blockedNode) + assert.True(blockedNode.alloc) + assert.are.equals(1, blockedNode.allocMode) + end) +end) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 294782679c..744ac43fc1 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -815,6 +815,20 @@ function PassiveSpecClass:AllocNode(node, altPath) -- Node cannot be connected to the tree as there is no possible path return end + local path = altPath or node.path + + if self.allocMode == 0 and #node.intuitiveLeapLikesAffecting == 0 then + if not altPath and node.pathRoot and node.pathRoot.alloc and node.pathRoot.allocMode and node.pathRoot.allocMode > 0 then + -- Normal passives cannot continue from weapon-set-only branches. + return + end + for _, pathNode in ipairs(path) do + if pathNode.alloc and pathNode.allocMode and pathNode.allocMode > 0 then + -- Normal passives cannot continue from weapon-set-only branches. + return + end + end + end -- Allocate all nodes along the path if #node.intuitiveLeapLikesAffecting > 0 then @@ -822,7 +836,7 @@ function PassiveSpecClass:AllocNode(node, altPath) node.allocMode = (node.ascendancyName or node.type == "Keystone" or node.type == "Socket" or node.containJewelSocket) and 0 or self.allocMode self.allocNodes[node.id] = node else - for _, pathNode in ipairs(altPath or node.path) do + for _, pathNode in ipairs(path) do pathNode.alloc = true pathNode.allocMode = (node.ascendancyName or pathNode.type == "Keystone" or pathNode.type == "Socket" or pathNode.containJewelSocket) and 0 or self.allocMode -- set path attribute nodes to latest chosen attribute or default to Strength if allocating before choosing an attribute @@ -952,6 +966,7 @@ end function PassiveSpecClass:BuildPathFromNode(root) root.pathDist = 0 root.path = { } + root.pathRoot = root local queue = { root } local o, i = 1, 2 -- Out, in while o < i do @@ -999,6 +1014,7 @@ function PassiveSpecClass:BuildPathFromNode(root) other.pathDist = other.pathDist + 1 end other.path = wipeTable(other.path) + other.pathRoot = root other.path[1] = other for i, n in ipairs(node.path) do other.path[i+1] = n @@ -1668,6 +1684,7 @@ function PassiveSpecClass:BuildAllDependsAndPaths() for id, node in pairs(self.nodes) do node.pathDist = (node.alloc and #node.intuitiveLeapLikesAffecting == 0) and 0 or 1000 node.path = nil + node.pathRoot = nil if node.isJewelSocket or node.expansionJewel then node.distanceToClassStart = 0 end