diff --git a/spec/System/TestTimelessJewelSettings_spec.lua b/spec/System/TestTimelessJewelSettings_spec.lua new file mode 100644 index 0000000000..50858ed40b --- /dev/null +++ b/spec/System/TestTimelessJewelSettings_spec.lua @@ -0,0 +1,52 @@ +describe("TestTimelessJewelSettings", function() + before_each(function() + newBuild() + end) + + -- The finder's "Socket Jewel" toggle lives in timelessData, which only reaches the + -- build XML through the TimelessData element, so cover the save/load round trip. + it("round trips socketAllocate through the build XML", function() + build.timelessData.socketAllocate = true + local xmlText = build:SaveDB("code") + assert.is_truthy(xmlText:match('socketAllocate="true"')) + + loadBuildFromXML(xmlText) + assert.is_true(build.timelessData.socketAllocate) + end) + + it("omits socketAllocate from the build XML while unticked", function() + build.timelessData.socketAllocate = false + local xmlText = build:SaveDB("code") + assert.is_nil(xmlText:match("socketAllocate")) + + loadBuildFromXML(xmlText) + assert.is_false(build.timelessData.socketAllocate) + end) + + it("records the item addition when the target socket is unallocated", function() + local socketId, socketControl = next(build.itemsTab.sockets) + local result = { label = "10000:", seed = 10000, total = 1 } + build.spec.allocNodes[socketId] = nil + build.timelessData.socketAllocate = true + build.timelessData.sharedResults = { + type = { id = 2, label = "Lethal Pride" }, + conqueror = { id = 1 }, + socket = { id = socketId, label = "Socket" }, + desiredNodes = { }, + } + build.timelessData.searchResults = { result } + local control = new("TimelessJewelListControl"):TimelessJewelListControl(nil, { 0, 0, 300, 100 }, build) + local initialItemCount = #build.itemsTab.itemOrderList + build.itemsTab:ResetUndo() + build.itemsTab.modFlag = false + + control:OnSelClick(1, result, true) + + assert.are.equal(initialItemCount + 1, #build.itemsTab.itemOrderList) + assert.are.equal(0, socketControl.selItemId) + assert.is_true(build.itemsTab.modFlag) + + build.itemsTab:Undo() + assert.are.equal(initialItemCount, #build.itemsTab.itemOrderList) + end) +end) diff --git a/src/Classes/TimelessJewelListControl.lua b/src/Classes/TimelessJewelListControl.lua index eb494dfe63..8b82e3b2d9 100644 --- a/src/Classes/TimelessJewelListControl.lua +++ b/src/Classes/TimelessJewelListControl.lua @@ -298,6 +298,13 @@ function TimelessJewelListControlClass:AddValueTooltip(tooltip, index, data) if not self.noTooltip then if self.list[index].label:match("B2B2B2") == nil then tooltip:AddLine(16, "^7Double click to add this jewel to your build.") + if self.build.timelessData.socketAllocate then + if socket and self.build.spec.allocNodes[socketId] then + tooltip:AddLine(16, "^7It will be socketed into " .. (data.socketLabel or self.sharedList.socket.label or socketId) .. ".") + else + tooltip:AddLine(16, colorCodes.WARNING .. "That jewel socket is not allocated, so the jewel will only be added to your items.") + end + end else tooltip:AddLine(16, "^7" .. self.sharedList.type.label .. " " .. data.seed .. " was successfully added to your build.") end @@ -328,8 +335,18 @@ end function TimelessJewelListControlClass:OnSelClick(index, data, doubleClick) if doubleClick and self.list[index].label:match("B2B2B2") == nil then local item = self:GetJewelItem(data) - self.build.itemsTab:AddItem(item, true) - self.build.itemsTab:PopulateSlots() + local itemsTab = self.build.itemsTab + itemsTab:AddItem(item, true) + if self.build.timelessData.socketAllocate then + local socketId = data.socketId or self.sharedList.socket.id + local socketControl = socketId ~= -1 and itemsTab.sockets[socketId] + if socketControl and self.build.spec.allocNodes[socketId] and itemsTab:IsItemValidForSlot(item, socketControl.slotName) then + socketControl:SetSelItemId(item.id) + self.build.buildFlag = true + end + end + itemsTab:PopulateSlots() + itemsTab:AddUndoState() self.list[index].label = "^xB2B2B2" .. self.list[index].label end end diff --git a/src/Classes/TreeTab.lua b/src/Classes/TreeTab.lua index 06f66f38df..842b3b4e09 100644 --- a/src/Classes/TreeTab.lua +++ b/src/Classes/TreeTab.lua @@ -1670,6 +1670,20 @@ function TreeTabClass:FindTimelessJewel() end controls.socketFilter.state = timelessData.socketFilter + -- own row under the socket filter, so it never collides with the node distance slider + controls.socketAllocate = new("CheckBoxControl"):CheckBoxControl({"TOPLEFT", controls.socketFilter, "BOTTOMLEFT"}, {0, rowSpacing, rowHeight}, nil, function(value) + timelessData.socketAllocate = value + self.build.modFlag = true + end) + controls.socketAllocateLabel = new("LabelControl"):LabelControl({"RIGHT", controls.socketAllocate, "LEFT"}, {-labelSpacing, 0, 0, labelHeight}, "^7Socket Jewel:") + controls.socketAllocate.tooltipFunc = function(tooltip, mode, index, value) + tooltip:Clear() + tooltip:AddLine(16, "^7Double clicking a result also equips the jewel in its jewel socket.") + tooltip:AddLine(16, "^7The socket must be allocated on your current tree; if it isn't, the jewel is only added to your item list.") + tooltip:AddLine(16, "^7A jewel already in that socket is replaced.") + end + controls.socketAllocate.state = timelessData.socketAllocate + -- Protect notables that must not be replaced by Militant Faith or Reclaimed Malevolence. controls.protectAllocatedLabel = new("LabelControl"):LabelControl({ "TOPLEFT", nil, "TOPLEFT" }, { 15, @@ -1750,7 +1764,7 @@ function TreeTabClass:FindTimelessJewel() local scrollWheelSpeedTbl2 = { ["SHIFT"] = 0.2, ["CTRL"] = 0.002, ["DEFAULT"] = 0.02 } local nodeSliderStatLabel = "None" - controls.nodeSlider = new("SliderControl"):SliderControl({"TOPLEFT", controls.socketFilter, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value) + controls.nodeSlider = new("SliderControl"):SliderControl({"TOPLEFT", controls.socketAllocate, "BOTTOMLEFT"}, {0, rowSpacing, 200, rowHeight}, function(value) controls.nodeSliderValue.label = s_format("^7%.3f", value * 10) parseSearchList(1, controls.searchListFallback and controls.searchListFallback.shown or false) end, scrollWheelSpeedTbl) @@ -2867,6 +2881,8 @@ function TreeTabClass:FindTimelessJewel() end end) - local panelHeight = 565 + -- the settings column is top anchored and the results/trade block bottom anchored, + -- so the panel grows by a row for every row the settings column gains + local panelHeight = 565 + rowSpacing + rowHeight main:OpenPopup(panelWidth, panelHeight, "Find a Timeless Jewel", controls) end diff --git a/src/Modules/Build.lua b/src/Modules/Build.lua index d080d84c90..5bde4c868a 100644 --- a/src/Modules/Build.lua +++ b/src/Modules/Build.lua @@ -1005,6 +1005,7 @@ function buildMode:Load(xml, fileName) idx = tonumber(child.attrib.fallbackWeightModeIdx) } self.timelessData.socketFilter = child.attrib.socketFilter == "true" + self.timelessData.socketAllocate = child.attrib.socketAllocate == "true" self.timelessData.socketFilterDistance = tonumber(child.attrib.socketFilterDistance) or 0 self.timelessData.searchList = child.attrib.searchList self.timelessData.searchListFallback = child.attrib.searchListFallback @@ -1086,6 +1087,7 @@ function buildMode:Save(xml) jewelSocketId = next(self.timelessData.jewelSocket) and tostring(self.timelessData.jewelSocket.id), fallbackWeightModeIdx = next(self.timelessData.fallbackWeightMode) and tostring(self.timelessData.fallbackWeightMode.idx), socketFilter = self.timelessData.socketFilter and "true", + socketAllocate = self.timelessData.socketAllocate and "true", socketFilterDistance = self.timelessData.socketFilterDistance and tostring(self.timelessData.socketFilterDistance), searchList = self.timelessData.searchList and tostring(self.timelessData.searchList), searchListFallback = self.timelessData.searchListFallback and tostring(self.timelessData.searchListFallback)