Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 213 additions & 0 deletions spec/System/TestItemsTab_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -408,4 +408,217 @@ describe("TestItemsTab", function()
end)
end)
end)

describe("TestCopyAnointsAndAugments", function ()
before_each(function ()
newBuild()
end)

-- Equips an item into the active item set's appropriate slot
local function equip(raw)
local item = new("Item", raw)
build.itemsTab:AddItem(item)
build.itemsTab:EquipItemInSet(item, build.itemsTab.activeItemSetId)
return item
end

describe("Anoints", function ()
it("copies an anoint from the equipped item onto a new item", function ()
equip([[
Rarity: RARE
Equipped
Crimson Amulet
Allocates Serrated Edges (enchant)
]])

local newItem = new("Item", [[
Rarity: RARE
New
Azure Amulet
]])
build.itemsTab:CopyAnointsAndAugments(newItem, false, false)

assert.are.equals(1, #newItem.enchantModLines)
end)

it("does not overwrite an existing anoint when overwrite is false", function ()
equip([[
Rarity: RARE
Equipped
Crimson Amulet
Allocates Serrated Edges (enchant)
]])

local newItem = new("Item", [[
Rarity: RARE
New
Azure Amulet
Allocates Unbound Forces (enchant)
]])
build.itemsTab:CopyAnointsAndAugments(newItem, false, false)

assert.are.equals(1, #newItem.enchantModLines)
assert.is_not_nil(newItem.enchantModLines[1].line:find("Unbound Forces"))
end)

it("overwrites an existing anoint when overwrite is true", function ()
equip([[
Rarity: RARE
Equipped
Crimson Amulet
Allocates Serrated Edges (enchant)
]])

local newItem = new("Item", [[
Rarity: RARE
New
Azure Amulet
Allocates Unbound Forces (enchant)
]])
build.itemsTab:CopyAnointsAndAugments(newItem, false, true)

assert.are.equals(1, #newItem.enchantModLines)
assert.is_not_nil(newItem.enchantModLines[1].line:find("Serrated Edges"))
end)

it("does not modify a corrupted item", function ()
equip([[
Rarity: RARE
Equipped
Crimson Amulet
Allocates Serrated Edges (enchant)
]])

for _, status in ipairs({ "Corrupted", "Mirrored", "Sanctified" }) do
local newItem = new("Item", string.format([[
Rarity: RARE
New
Azure Amulet
%s
]], status))
build.itemsTab:CopyAnointsAndAugments(newItem, false, false)

assert.are.equals(0, #newItem.enchantModLines)
end
end)
end)

describe("Augments", function ()
local rune = "Greater Robust Rune"

local existingItemText = string.format([[
Rarity: RARE
Equipped
Stocky Mitts
Sockets: S
Rune: %s
]], rune)

local newItemText = [[
Rarity: RARE
New
Stocky Mitts
]]

it("copies runes from the equipped item when copyAugments is true", function ()
equip(existingItemText)

local newItem = new("Item", [[
Rarity: RARE
New
Stocky Mitts
]])
build.itemsTab:CopyAnointsAndAugments(newItem, true, false)

assert.are.equals(rune, newItem.runes[1])
end)

it("adds sockets to the new item to fit the copied runes", function ()
equip(existingItemText)

local newItem = new("Item", newItemText)
assert.are.equals(0, #newItem.sockets)

build.itemsTab:CopyAnointsAndAugments(newItem, true, false)

assert.are.equals(1, #newItem.sockets)
end)

it("does not copy runes when copyAugments is false", function ()
equip(existingItemText)

local newItem = new("Item", newItemText)
build.itemsTab:CopyAnointsAndAugments(newItem, false, false)

assert.are.equals(0, #newItem.sockets)
end)

it("does not replace socket bound runes", function ()
equip(existingItemText)

local newItem = new("Item", [[
Rarity: RARE
Equipped
Stocky Mitts
Sockets: S
Rune: Kolr's Hunt
]])
build.itemsTab:CopyAnointsAndAugments(newItem, true, true)
assert.are.equals(newItem.runes[1], "Kolr's Hunt")

local newItem = new("Item", [[
Rarity: RARE
Equipped
Stocky Mitts
Sockets: S S
Rune: Kolr's Hunt
]])
build.itemsTab:CopyAnointsAndAugments(newItem, true, true)
assert.are.equals(newItem.runes[1], "Kolr's Hunt")
assert.are.equals(newItem.runes[2], rune)
end)

it("replaces runes when overwrite is true", function ()
equip(existingItemText)

local newItem = new("Item", [[
Rarity: RARE
Equipped
Stocky Mitts
Sockets: S S
Rune: Lesser Robust Rune
]])
build.itemsTab:CopyAnointsAndAugments(newItem, true, true)
assert.are.equals(newItem.runes[1], rune)
assert.are.equals(newItem.runes[2], "None")
end)

it("identifies socket bound runes", function ()
local item = new("Item", [[
Rarity: RARE
Equipped
Stocky Mitts
Sockets: S S
Rune: Kolr's Hunt
Rune: Lesser Robust Rune
]])
local validRunes = build.itemsTab:GetValidRunesForItem(item)

assert.is_true(build.itemsTab:IsSocketBoundRune(item, item.runes[1], validRunes))
assert.is_false(build.itemsTab:IsSocketBoundRune(item, item.runes[2], validRunes))
end)
end)

it("does nothing when no matching item is equipped", function ()
local newItem = new("Item", [[
Rarity: RARE
New
Azure Amulet
+8 to Strength (enchant)
]])
build.itemsTab:CopyAnointsAndAugments(newItem, true, false)

assert.are.equals(1, #newItem.enchantModLines)
end)
end)
end)
32 changes: 27 additions & 5 deletions src/Classes/ItemsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1746,18 +1746,28 @@ function ItemsTabClass:CopyAnointsAndAugments(newItem, copyAugments, overwrite,
local validRunes = self:GetValidRunesForItem(newItem)

-- replace runes with current ones, or set to none
local skipped = 0
if shouldChangeAugments then
for i = 1, #newItem.sockets do
-- avoid overwriting socket bound runes as removing these from e.g. trade results
-- will be confusing
if self:IsSocketBoundRune(newItem, newItem.runes[i], validRunes) then
-- if the new item has more slots than the old item, we still copy old
-- runes in order after skipping the socket bound rune
skipped = skipped + 1
goto continue
end
newItem.runes[i] = "None"
if currentRunes[i] then
if currentRunes[i - skipped] then
for _, rune in ipairs(validRunes) do
-- we only copy runes which fit the new item type
if rune.name == currentRunes[i] then
newItem.runes[i] = currentRunes[i]
if rune.name == currentRunes[i - skipped] then
newItem.runes[i] = currentRunes[i - skipped]
break
end
end
end
::continue::
end
newItem:UpdateRunes()
end
Expand Down Expand Up @@ -1909,11 +1919,11 @@ function ItemsTabClass:UpdateAffixControls()
self:UpdateCustomControls()
end

local runeModLines = { { name = "None", label = "None", lines = { "None" }, order = -1, slot = "None", group = -1 } }
local runeModLines = { { name = "None", label = "None", lines = { "None" }, order = -1, slot = "None", group = -1, isSocketBound = false } }
for name, runeMods in pairs(data.itemMods.Runes) do
-- Some runes have multiple mod lines; insert each as separate entry
for slotType, runeMod in pairs(runeMods) do
t_insert(runeModLines, { name = name, label = runeMod[1], lines = runeMod, req = runeMod.rank[1], order = runeMod.statOrder[1], slot = slotType, type = runeMod.type, group = #runeMod })
t_insert(runeModLines, { name = name, label = runeMod[1], lines = runeMod, req = runeMod.rank[1], order = runeMod.statOrder[1], slot = slotType, type = runeMod.type, group = #runeMod, isSocketBound = runeMod.isSocketBound })
end
end
table.sort(runeModLines, function(a, b)
Expand Down Expand Up @@ -1965,6 +1975,18 @@ function ItemsTabClass:GetValidRunesForItem(item)
return runes
end

function ItemsTabClass:IsSocketBoundRune(item, runeName, validRunes)
if not runeName or runeName == "None" then
return false
end
for _, rune in ipairs(validRunes or self:GetValidRunesForItem(item)) do
if rune.name == runeName then
return rune.isSocketBound
end
end
return false
end

-- Update rune selection controls
function ItemsTabClass:UpdateRuneControls()
local item = self.displayItem
Expand Down
5 changes: 4 additions & 1 deletion src/Classes/TradeQuery.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1044,8 +1044,11 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
for item_idx, _ in ipairs(itemsSafe) do
local item = new("Item", itemsSafe[item_idx].item_string)
-- sockets are kept as-is so the user can see e.g. exceptional or corrupted sockets
local validRunes = self.itemsTab:GetValidRunesForItem(item)
for rune_idx, _ in ipairs(item.runes or {}) do
item.runes[rune_idx] = "None"
if not self.itemsTab:IsSocketBoundRune(item, item.runes[rune_idx], validRunes) then
item.runes[rune_idx] = "None"
end
end
item:UpdateRunes()
itemsSafe[item_idx].item_string = item:BuildRaw()
Expand Down
Loading
Loading