From 54a43e578cd79ea750918d0a52e5ba237ace7d7e Mon Sep 17 00:00:00 2001 From: Andrew Devlin Date: Sun, 1 Mar 2026 15:09:05 -0800 Subject: [PATCH] Adds Split Personality path connector coloring and an option menu toggle to disable it. Signed-off-by: Andrew Devlin --- src/Classes/PassiveSpec.lua | 45 +++++++++++++++++++++++++++++++++ src/Classes/PassiveTreeView.lua | 44 ++++++++++++++++++++++++++------ src/Data/Global.lua | 3 ++- src/Modules/Main.lua | 13 ++++++++++ 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/Classes/PassiveSpec.lua b/src/Classes/PassiveSpec.lua index 937be5065f..f9e9ee8b3e 100644 --- a/src/Classes/PassiveSpec.lua +++ b/src/Classes/PassiveSpec.lua @@ -950,6 +950,51 @@ function PassiveSpecClass:SetNodeDistanceToClassStart(root) end end +-- Determine the shortest path from the given node to the class' start +-- Only allocated nodes can be traversed +function PassiveSpecClass:GetShortestPathToClassStart(rootId) + local root = self.nodes[rootId] + if not root or not root.alloc or not root.connectedToStart then + return nil + end + + -- Stop once the current class' starting node is reached + local targetNodeId = self.curClass.startNodeId + + local parent = { } + parent[root.id] = nil + + local queue = { root } + local o, i = 1, 2 -- Out, in + while o < i do + local node = queue[o] + o = o + 1 + -- Iterate through all nodes that are connected to this one + for _, other in ipairs(node.linked) do + -- If this connected node is the correct class start node, then construct and return the path + if other.id == targetNodeId then + local path = { [root.id] = true, [other.id] = true } + local cur = node + while cur do + path[cur.id] = true + cur = parent[cur.id] + end + return path + end + + -- Otherwise, record the parent of this node if it hasn't already been visited + if other.alloc and node.type ~= "Mastery" and other.type ~= "ClassStart" and other.type ~= "AscendClassStart" and not parent[other.id] and other.id ~= root.id then + parent[other.id] = node + + -- Add the other node to the end of the queue + queue[i] = other + i = i + 1 + end + end + end + return nil +end + function PassiveSpecClass:AddMasteryEffectOptionsToNode(node) node.sd = {} if node.masteryEffects ~= nil and #node.masteryEffects > 0 then diff --git a/src/Classes/PassiveTreeView.lua b/src/Classes/PassiveTreeView.lua index 77c9f21fc3..2809b731f0 100644 --- a/src/Classes/PassiveTreeView.lua +++ b/src/Classes/PassiveTreeView.lua @@ -269,6 +269,22 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) end end + -- Split Personality highlight + local splitPersonalityPath = { } + if main.showSplitPersonalityPath then + for nodeId, itemId in pairs(spec.jewels) do + local item = build.itemsTab.items[itemId] + if item and item.jewelData and item.jewelData.jewelIncEffectFromClassStart then + local path = spec:GetShortestPathToClassStart(nodeId) + if path then + for id in pairs(path) do + splitPersonalityPath[id] = true + end + end + end + end + end + if treeClick == "LEFT" then if hoverNode then -- User left-clicked on a node @@ -503,7 +519,13 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) end local function renderConnector(connector) local node1, node2 = spec.nodes[connector.nodeId1], spec.nodes[connector.nodeId2] - setConnectorColor(1, 1, 1) + local connectorDefaultColor = "^xFFFFFF" + + if splitPersonalityPath[node1.id] and splitPersonalityPath[node2.id] then + connectorDefaultColor = colorCodes.SPLITPERSONALITY + end + + setConnectorColor(connectorDefaultColor) local state = getState(node1, node2) local baseState = state if self.compareSpec then @@ -589,6 +611,12 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) local base, overlay, effect local isAlloc = node.alloc or build.calcsTab.mainEnv.grantedPassives[nodeId] or (compareNode and compareNode.alloc) + local nodeDefaultColor = "^xFFFFFF" + + if splitPersonalityPath[node.id] then + nodeDefaultColor = colorCodes.SPLITPERSONALITY + end + SetDrawLayer(nil, 25) if node.type == "ClassStart" then overlay = isAlloc and node.startArt or "PSStartNodeBackgroundInactive" @@ -734,11 +762,11 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) -- Node is a mastery, both have it allocated, but mastery changed, color it blue SetDrawColor(0, 0, 1) else - -- Both have or both have not, use white - SetDrawColor(1, 1, 1) + -- Both have or both have not + SetDrawColor(nodeDefaultColor) end else - SetDrawColor(1, 1, 1) + SetDrawColor(nodeDefaultColor) end end elseif launch.devModeAlt then @@ -762,11 +790,11 @@ function PassiveTreeViewClass:Draw(build, viewPort, inputEvents) -- Node is a mastery, both have it allocated, but mastery changed, color it blue SetDrawColor(0, 0, 1) else - -- Both have or both have not, use white - SetDrawColor(1, 1, 1) - end + -- Both have or both have not + SetDrawColor(nodeDefaultColor) + end else - SetDrawColor(1, 1, 1) + SetDrawColor(nodeDefaultColor) end end diff --git a/src/Data/Global.lua b/src/Data/Global.lua index a264f13dfa..a8cc44731a 100644 --- a/src/Data/Global.lua +++ b/src/Data/Global.lua @@ -56,7 +56,8 @@ colorCodes = { BRITTLEBG = "^x00122b", SAPBG = "^x261500", SCOURGE = "^xFF6E25", - CRUCIBLE = "^xFFA500" + CRUCIBLE = "^xFFA500", + SPLITPERSONALITY = "^xFFD62A" } colorCodes.STRENGTH = colorCodes.MARAUDER colorCodes.DEXTERITY = colorCodes.RANGER diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index c329acc5ec..693d73b87a 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -115,6 +115,7 @@ function main:Init() self.showAnimations = true self.showAllItemAffixes = true self.errorReadingSettings = false + self.showSplitPersonalityPath = true if not SetDPIScaleOverridePercent then SetDPIScaleOverridePercent = function(scale) end end @@ -660,6 +661,9 @@ function main:LoadSettings(ignoreBuild) self.dpiScaleOverridePercent = tonumber(node.attrib.dpiScaleOverridePercent) or 0 SetDPIScaleOverridePercent(self.dpiScaleOverridePercent) end + if node.attrib.showSplitPersonalityPath then + self.showSplitPersonalityPath = node.attrib.showSplitPersonalityPath == "true" + end end end end @@ -791,6 +795,7 @@ function main:SaveSettings() showAnimations = tostring(self.showAnimations), showAllItemAffixes = tostring(self.showAllItemAffixes), dpiScaleOverridePercent = tostring(self.dpiScaleOverridePercent), + showSplitPersonalityPath = tostring(self.showSplitPersonalityPath), } }) local res, errMsg = common.xml.SaveXMLFile(setXML, self.userPath.."Settings.xml") if not res then @@ -1079,6 +1084,12 @@ function main:OpenOptionsPopup() controls.invertSliderScrollDirection.tooltipText = "Default scroll direction is:\nScroll Up = Move right\nScroll Down = Move left" controls.invertSliderScrollDirection.state = self.invertSliderScrollDirection + nextRow() + controls.showSplitPersonalityPath = new("CheckBoxControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, currentY, 20 }, "^7Show Split Personality paths:", function(state) + self.showSplitPersonalityPath = state + end) + controls.showSplitPersonalityPath.state = self.showSplitPersonalityPath + if launch.devMode then nextRow() controls.disableDevAutoSave = new("CheckBoxControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, currentY, 20 }, "^7Disable Dev AutoSave:", function(state) @@ -1118,6 +1129,7 @@ function main:OpenOptionsPopup() local initialShowAnimations = self.showAnimations local initialShowAllItemAffixes = self.showAllItemAffixes local initialDpiScaleOverridePercent = self.dpiScaleOverridePercent + local initialShowSplitPersonalityPath = self.showSplitPersonalityPath -- last line with buttons has more spacing nextRow(1.5) @@ -1175,6 +1187,7 @@ function main:OpenOptionsPopup() self.showAllItemAffixes = initialShowAllItemAffixes self.dpiScaleOverridePercent = initialDpiScaleOverridePercent SetDPIScaleOverridePercent(self.dpiScaleOverridePercent) + self.showSplitPersonalityPath = initialShowSplitPersonalityPath main:ClosePopup() end) nextRow(1.5)