From 7ee640152edcad1edc0cf21986f4d7ac034482f0 Mon Sep 17 00:00:00 2001 From: vaisest <4550061+vaisest@users.noreply.github.com> Date: Fri, 17 Apr 2026 04:48:49 +0300 Subject: [PATCH 1/3] Add functionality to copy augments to compared items, like anointments are copied. --- src/Classes/ItemsTab.lua | 76 +++++++++++++++++++++++++++++++++++----- src/Modules/Main.lua | 13 ++++++- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 5a2b9aa8f..5787d5d1f 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -1479,18 +1479,78 @@ function ItemsTabClass:DeleteItem(item, deferUndoState) end end +local function isAnointable(item) + return (item.canBeAnointed or item.base.type == "Amulet") +end + +local function isAugmentable(item) + return (item.sockets and #item.sockets > 0) or (item.base.socketLimit and item.base.socketLimit > 0) +end + +function ItemsTabClass:copyAnointsAndAugments(newItem, copyAugments, overwrite, sourceSlotName) + local newItemType = sourceSlotName or (newItem.base.weapon and "Weapon 1" or newItem.base.type) + -- tabula rasa has jewel sockets which don't apply here + if newItem.name == "Tabula Rasa, Garment" then return end + if self.activeItemSet[newItemType] then + local currentItem = self.activeItemSet[newItemType].selItemId and self.items[self.activeItemSet[newItemType].selItemId] + -- if you don't have an equipped item that matches the type of the newItem, no need to do anything + if currentItem then + local modifiableItem = not (newItem.corrupted or newItem.mirrored or newItem.sanctified) + -- if the new item is anointable and does not have an anoint and your current respective item does, apply that anoint to the new item + if isAnointable(newItem) and (#newItem.enchantModLines == 0 or overwrite) and self.activeItemSet[newItemType].selItemId > 0 and modifiableItem then + local currentAnoint = currentItem.enchantModLines + newItem.enchantModLines = currentAnoint + end + + --https://www.poe2wiki.net/wiki/Augment_socket + -- augments, given there are enough sockets + + local hasEmptySockets = true + for i = 1, #newItem.runes do + if newItem.runes[i] ~= "None" then + hasEmptySockets = false + break + end + end + local shouldChangeAugments = copyAugments and isAugmentable(newItem) and + (#newItem.runes == 0 or hasEmptySockets or overwrite) + + -- current runes sans "None" + local currentRunes = {} + for i = 1, #currentItem.runes do + if currentItem.runes[i] ~= "None" then + table.insert(currentRunes, currentItem.runes[i]) + end + end + -- add sockets, if necessary and possible + if shouldChangeAugments and isAugmentable(newItem) and modifiableItem and #newItem.sockets < #currentItem.sockets then + local maxSockets = modifiableItem and math.min(#currentItem.sockets, newItem.base.socketLimit) + local neededSockets = math.max(0, maxSockets - #newItem.sockets) + for i = 1, neededSockets do + table.insert(newItem.runes, "None") + table.insert(newItem.sockets, { group = #newItem.sockets + 1}) + end + newItem.itemSocketCount = #newItem.sockets + newItem:UpdateRunes() + end + -- replace runes with current ones, or set to none + if shouldChangeAugments then + for i = 1, #newItem.sockets do + newItem.runes[i] = currentRunes[i] or "None" + end + newItem:UpdateRunes() + end + + newItem:BuildAndParseRaw() + end + end +end + -- Attempt to create a new item from the given item raw text and sets it as the new display item function ItemsTabClass:CreateDisplayItemFromRaw(itemRaw, normalise) local newItem = new("Item", itemRaw) if newItem.base then - -- if the new item is an amulet and does not have an anoint and your current amulet does, apply that anoint to the new item - if newItem.base.type == "Amulet" and #newItem.enchantModLines == 0 and self.activeItemSet["Amulet"].selItemId > 0 then - local currentAnoint = self.items[self.activeItemSet["Amulet"].selItemId].enchantModLines - if currentAnoint and #currentAnoint == 1 then -- skip if amulet has more than one anoint e.g. Stranglegasp - newItem.enchantModLines = currentAnoint - newItem:BuildAndParseRaw() - end - end + self:copyAnointsAndAugments(newItem, main.migrateAugments, false) if normalise then newItem:NormaliseQuality() newItem:BuildModList() diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 9905923bb..073ad8b8b 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -107,6 +107,7 @@ function main:Init() self.dpiScaleOverridePercent = GetDPIScaleOverridePercent and GetDPIScaleOverridePercent() or 0 self.showWarnings = true self.slotOnlyTooltips = true + self.migrateAugments = true self.notSupportedModTooltips = true self.notSupportedTooltipText = " ^8(Not supported in PoB yet)" self.POESESSID = "" @@ -788,6 +789,7 @@ function main:SaveSettings() lastExportWebsite = self.lastExportWebsite, showWarnings = tostring(self.showWarnings), slotOnlyTooltips = tostring(self.slotOnlyTooltips), + migrateAugments = tostring(self.migrateAugments), notSupportedModTooltips = tostring(self.notSupportedModTooltips), POESESSID = self.POESESSID, invertSliderScrollDirection = tostring(self.invertSliderScrollDirection), @@ -873,7 +875,7 @@ function main:OpenOptionsPopup() end local defaultLabelSpacingPx = -4 - local defaultLabelPlacementX = 240 + local defaultLabelPlacementX = popupWidth*0.45 drawSectionHeader("app", "Application options") @@ -1077,6 +1079,13 @@ function main:OpenOptionsPopup() self.slotOnlyTooltips = state end) controls.slotOnlyTooltips.state = self.slotOnlyTooltips + + nextRow() + controls.migrateAugments = new("CheckBoxControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, currentY, 20 }, "^7Copy augments onto display item:", function(state) + self.migrateAugments = state + end) + controls.migrateAugments.tooltipText = "Apply augments and anoints from current gear when comparing new gear, given they are possible to add to the new item." + controls.migrateAugments.state = self.migrateAugments nextRow() controls.notSupportedModTooltips = new("CheckBoxControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, currentY, 20 }, "^7Show tooltip for unsupported mods :", function(state) @@ -1124,6 +1133,7 @@ function main:OpenOptionsPopup() local initialDefaultItemAffixQuality = self.defaultItemAffixQuality or 0.5 local initialShowWarnings = self.showWarnings local initialSlotOnlyTooltips = self.slotOnlyTooltips + local initialMigrateAugments = self.migrateAugments local initialNotSupportedModTooltips = self.notSupportedModTooltips local initialInvertSliderScrollDirection = self.invertSliderScrollDirection local initialDisableDevAutoSave = self.disableDevAutoSave @@ -1181,6 +1191,7 @@ function main:OpenOptionsPopup() self.defaultItemAffixQuality = initialDefaultItemAffixQuality self.showWarnings = initialShowWarnings self.slotOnlyTooltips = initialSlotOnlyTooltips + self.migrateAugments = initialMigrateAugments self.notSupportedModTooltips = initialNotSupportedModTooltips self.invertSliderScrollDirection = initialInvertSliderScrollDirection self.disableDevAutoSave = initialDisableDevAutoSave From 51df96419a1809213d2d8bb975dbae9cb99e2656 Mon Sep 17 00:00:00 2001 From: vaisest <4550061+vaisest@users.noreply.github.com> Date: Sat, 18 Apr 2026 04:50:39 +0300 Subject: [PATCH 2/3] Port jewel comparison tooltip socket sorting from pob1 --- src/Classes/ItemsTab.lua | 127 +++++++++++++++++++++++--------- src/Classes/PassiveTreeView.lua | 2 +- src/Modules/Main.lua | 2 +- 3 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 5787d5d1f..6883db296 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -3435,49 +3435,108 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode) t_insert(compareSlots, slot) end end - table.sort(compareSlots, function(a, b) - if a ~= b then - if slot == a then - return true - end - if slot == b then - return false + + tooltip:AddLine(14, colorCodes.TIP .. "Tip: Press Ctrl+D to disable the display of stat differences.", "VAR") + + local function getReplacedItemAndOutput(compareSlot) + local selItem = self.items[compareSlot.selItemId] + local output = calcFunc({ repSlotName = compareSlot.slotName, repItem = item ~= selItem and item or nil }) + return selItem, output + end + local function addCompareForSlot(compareSlot, selItem, output) + if not selItem or not output then + selItem, output = getReplacedItemAndOutput(compareSlot) + end + local header + if item == selItem then + header = "^7Removing this item from " .. compareSlot.label .. " will give you:" + else + header = string.format("^7Equipping this item in %s will give you:%s", + compareSlot.label or compareSlot.slotName, + selItem and "\n(replacing " .. colorCodes[selItem.rarity] .. selItem.name .. "^7)" or "") + end + self.build:AddStatComparesToTooltip(tooltip, calcBase, output, header) + end + + -- if we have a specific slot to compare to, and the user has "Show + -- tooltips only for affected slots" checked, we can just compare that + -- one slot + if main.slotOnlyTooltips and slot then + slot = type(slot) ~= "string" and slot or self.slots[slot] + if slot then addCompareForSlot(slot) end + return + end + + + local slots = {} + local isUnique = item.rarity == "UNIQUE" or item.rarity == "RELIC" + local currentSameUniqueCount = 0 + for _, compareSlot in ipairs(compareSlots) do + local selItem, output = getReplacedItemAndOutput(compareSlot) + local isSameUnique = isUnique and selItem and item.name == selItem.name + if isUnique and isSameUnique and item.limit then + currentSameUniqueCount = currentSameUniqueCount + 1 + end + table.insert(slots, + { selItem = selItem, output = output, compareSlot = compareSlot, isSameUnique = isSameUnique }) + end + + -- limited uniques: only compare to slots with the same item if more don't fit + if currentSameUniqueCount == item.limit then + for _, slotEntry in ipairs(slots) do + if slotEntry.isSameUnique then + addCompareForSlot(slotEntry.compareSlot, slotEntry.selItem, slotEntry.output) end end - if a.selItemId ~= b.selItemId then - if item == self.items[a.selItemId] then + return + end + + + -- either the same unique or same base type + local function similar(compareItem, sameUnique) + -- empty slot + if not compareItem then return 0 end + + local sameBaseType = not isUnique + and compareItem.rarity ~= "UNIQUE" and compareItem.rarity ~= "RELIC" + and item.base.type == compareItem.base.type + and item.base.subType == compareItem.base.subType + if sameBaseType or sameUnique then + return 1 + else + return 0 + end + end + -- sort by: + -- 1. empty sockets + -- 2. same base group jewel or unique + -- 3. DPS + -- 4. EHP + local function sortFunc(a, b) + if a == b then return end + + local aParams = { a.compareSlot.selItemId == 0 and 1 or 0, similar(a.selItem, a.isSameUnique), a.output + .FullDPS, a.output.CombinedDPS, a.output.TotalEHP, a.compareSlot.label, a.compareSlot.slotName } + local bParams = { b.compareSlot.selItemId == 0 and 1 or 0, similar(b.selItem, b.isSameUnique), b.output + .FullDPS, b + .output.CombinedDPS, b.output.TotalEHP, b.compareSlot.label, b.compareSlot.slotName } + for i = 1, #aParams do + if aParams[i] == nil or bParams[i] == nil then + -- continue + elseif aParams[i] > bParams[i] then return true - end - if item == self.items[b.selItemId] then + elseif aParams[i] < bParams[i] then return false end end - local aNum = tonumber(a.slotName:match("%d+")) - local bNum = tonumber(b.slotName:match("%d+")) - if aNum and bNum then - return aNum < bNum - else - return a.slotName < b.slotName - end - end) + return false + end + table.sort(slots, sortFunc) - -- Add comparisons for each slot - for _, compareSlot in pairs(compareSlots) do - if not main.slotOnlyTooltips or (slot and (slot.nodeId == compareSlot.nodeId or slot.slotName == compareSlot.slotName)) or not slot or slot == compareSlot then - local selItem = self.items[compareSlot.selItemId] - local output = calcFunc({ repSlotName = compareSlot.slotName, repItem = item ~= selItem and item or nil}) - local header - if item == selItem then - header = "^7Removing this item from "..compareSlot.label.." will give you:" - else - header = string.format("^7Equipping this item in %s will give you:%s", compareSlot.label, selItem and "\n(replacing "..colorCodes[selItem.rarity]..selItem.name.."^7)" or "") - end - self.build:AddStatComparesToTooltip(tooltip, calcBase, output, header) - end + for _, slotEntry in ipairs(slots) do + addCompareForSlot(slotEntry.compareSlot, slotEntry.selItem, slotEntry.output) end end - tooltip:AddLine(14, colorCodes.TIP.."Tip: Press Ctrl+D to disable the display of stat differences.", "VAR") - if launch.devModeAlt then -- Modifier debugging info tooltip:AddSeparator(10) diff --git a/src/Classes/PassiveTreeView.lua b/src/Classes/PassiveTreeView.lua index e33df5675..1f00fedcf 100644 --- a/src/Classes/PassiveTreeView.lua +++ b/src/Classes/PassiveTreeView.lua @@ -1336,7 +1336,7 @@ function PassiveTreeViewClass:AddNodeTooltip(tooltip, node, build, incSmallPassi if (node.type == "Socket" or node.containJewelSocket) and node.alloc then local socket, jewel = build.itemsTab:GetSocketAndJewelForNodeID(node.id) if jewel then - build.itemsTab:AddItemTooltip(tooltip, jewel, { nodeId = node.id }) + build.itemsTab:AddItemTooltip(tooltip, jewel, socket) if node.distanceToClassStart and node.distanceToClassStart > 0 then tooltip:AddSeparator(14) tooltip:AddLine(16, string.format("^7Distance to start: %d", node.distanceToClassStart)) diff --git a/src/Modules/Main.lua b/src/Modules/Main.lua index 073ad8b8b..5002f3440 100644 --- a/src/Modules/Main.lua +++ b/src/Modules/Main.lua @@ -1077,7 +1077,7 @@ function main:OpenOptionsPopup() nextRow() controls.slotOnlyTooltips = new("CheckBoxControl", { "TOPLEFT", nil, "TOPLEFT" }, { defaultLabelPlacementX, currentY, 20 }, "^7Show tooltips only for affected slots:", function(state) self.slotOnlyTooltips = state - end) + end, "Shows comparisons in tooltips only for the slot you are currently placing the item in, instead of all slots.") controls.slotOnlyTooltips.state = self.slotOnlyTooltips nextRow() From 17cec65689252255c9d814dfb787e50a63f066db Mon Sep 17 00:00:00 2001 From: vaisest <4550061+vaisest@users.noreply.github.com> Date: Sat, 18 Apr 2026 05:14:46 +0300 Subject: [PATCH 3/3] Fix item comparison augment copy not treating spell weapons as weapons, or shields as weapon 2s --- src/Classes/ItemsTab.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Classes/ItemsTab.lua b/src/Classes/ItemsTab.lua index 6883db296..40ef39e37 100644 --- a/src/Classes/ItemsTab.lua +++ b/src/Classes/ItemsTab.lua @@ -1488,7 +1488,9 @@ local function isAugmentable(item) end function ItemsTabClass:copyAnointsAndAugments(newItem, copyAugments, overwrite, sourceSlotName) - local newItemType = sourceSlotName or (newItem.base.weapon and "Weapon 1" or newItem.base.type) + local isWeapon = newItem.base.tags and (newItem.base.tags.onehand or newItem.base.tags.twohand) + local isShield = newItem.base.tags and (newItem.base.tags.shield or newItem.base.tags.focus) + local newItemType = sourceSlotName or (isWeapon and "Weapon 1") or (isShield and "Weapon 2") or newItem.base.type -- tabula rasa has jewel sockets which don't apply here if newItem.name == "Tabula Rasa, Garment" then return end if self.activeItemSet[newItemType] then