Skip to content
Open
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
34 changes: 34 additions & 0 deletions spec/System/TestItemParse_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,40 @@ describe("TestAdvancedItemParse #item", function()
assert.are.equals("Adds 14 to 285 Lightning Damage", item.explicitModLines[2].line)
end)

it("preserves corrupted modifier identity and requirement through crafting", function()
local item = new("Item"):Item([[
Rarity: Rare
Test Ring
Gold Ring
Crafted: true
Prefix: None
Prefix: None
Prefix: None
Suffix: None
Suffix: None
Suffix: None
LevelReq: 1
Implicits: 1
{modGroup:IncreasedCastSpeedCorrupted}(4-6)% increased Cast Speed
Corrupted
]])

assert.are.equals("IncreasedCastSpeedCorrupted", item.implicitModLines[1].modGroup)
item:BuildAndParseRaw()
assert.are.equals("IncreasedCastSpeedCorrupted", item.implicitModLines[1].modGroup)

item:Craft()
assert.are.equals(1, item.requirements.level)

item.suffixes[1] = { modId = "Strength8", range = 0.5 }
item:Craft()
assert.are.equals(59, item.requirements.level)

item.suffixes[1] = { modId = "None" }
item:Craft()
assert.are.equals(1, item.requirements.level)
end)

it("filters flask base properties and parses fixed-value advanced rolls", function()
local item = new("Item"):Item([[
Rarity: Unique
Expand Down
54 changes: 54 additions & 0 deletions spec/System/TestItemTools_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,58 @@ Can be Anointed

assert.are.equals(0, fakeItemsTab:getMissingAnointCount(item))
end)

it("calculates corrupted requirements from generated modifier levels", function()
local item = setmetatable({
crafted = true,
rarity = "RARE",
base = { req = { level = 20 } },
affixes = { },
prefixes = { },
suffixes = { },
requirements = { level = 20 },
}, common.classes.Item)

assert.are.equals(60, item:CalculateCorruptedRequirement({ { level = 75 } }, 20))
assert.are.equals(64, item:CalculateCorruptedRequirement({ { level = 75 }, { level = 80 } }, 20))
end)

it("composes structured affix and conservative requirement floors", function()
local item = setmetatable({
crafted = true,
rarity = "RARE",
base = { req = { level = 20 } },
affixes = { HighAffix = { level = 85 } },
prefixes = { { modId = "HighAffix" } },
suffixes = { },
requirements = { level = 72 },
}, common.classes.Item)

assert.are.equals(68, item:CalculateCorruptedRequirement({ { level = 75 } }, 72))

item.prefixes[1].modId = "MissingAffix"
assert.are.equals(72, item:CalculateCorruptedRequirement({ { level = 75 } }, 72))

item.prefixes = { }
item.base.weapon = { }
item.base.req.level = 70
assert.are.equals(70, item:CalculateCorruptedRequirement({ { level = 75 } }, 72))
end)

it("does not lower unique or non-crafted item requirements", function()
local item = setmetatable({
crafted = true,
rarity = "UNIQUE",
base = { req = { level = 20 } },
affixes = { },
prefixes = { },
suffixes = { },
requirements = { level = 70 },
}, common.classes.Item)

assert.are.equals(70, item:CalculateCorruptedRequirement({ { level = 75 } }, 70))
item.rarity = "RARE"
item.crafted = false
assert.are.equals(70, item:CalculateCorruptedRequirement({ { level = 75 } }, 70))
end)
end)
60 changes: 60 additions & 0 deletions src/Classes/Item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2051,8 +2051,61 @@ function ItemClass:BuildAndParseRaw()
self:ParseRaw(raw)
end

function ItemClass:GetCorruptedImplicitMods()
local mods = { }
local seen = { }
for _, modLine in ipairs(self.implicitModLines) do
local modId = modLine.modGroup
if modId and not seen[modId] then
local mod = data.itemMods.Corrupted[modId]
if mod and mod.type == "Corrupted" then
seen[modId] = true
t_insert(mods, mod)
end
end
end
return mods
end

function ItemClass:CalculateCorruptedRequirement(corruptedMods, existingRequirement)
local requirement
local canRecalculate = self.crafted and self.rarity ~= "UNIQUE" and self.rarity ~= "RELIC"
if canRecalculate then
if self.base.weapon or self.base.armour or self.base.flask then
requirement = self.base.req.level or 1
else
-- Other bases have a pre-implicit requirement of 1 in the base exporter.
requirement = 1
end
for _, list in ipairs({ self.prefixes, self.suffixes }) do
for _, affix in ipairs(list) do
if affix.modId ~= "None" then
local mod = affix.modId and self.affixes[affix.modId]
if not mod then
canRecalculate = false
break
end
requirement = m_max(requirement, m_floor(mod.level * 0.8))
end
end
if not canRecalculate then
break
end
end
end
if not canRecalculate then
requirement = existingRequirement or self.requirements.level or self.base.req.level or 1
end
for _, mod in ipairs(corruptedMods) do
requirement = m_max(requirement, m_floor(mod.level * 0.8))
end
return requirement
end

-- Rebuild explicit modifiers using the item's affixes
function ItemClass:Craft()
local existingLevelRequirement = self.requirements.level
local corruptedImplicitMods = self:GetCorruptedImplicitMods()
-- Save off any crafted or custom mods so they can be re-added at the end
local savedMods = {}
for _, mod in ipairs(self.explicitModLines) do
Expand Down Expand Up @@ -2113,6 +2166,13 @@ function ItemClass:Craft()
if #self.explicitModLines > 1 then
sortCraftedModLines(self.explicitModLines)
end
if self.corrupted then
if #corruptedImplicitMods > 0 then
self.requirements.level = self:CalculateCorruptedRequirement(corruptedImplicitMods, existingLevelRequirement)
else
self.requirements.level = m_max(self.requirements.level or 0, existingLevelRequirement or 0)
end
end

self:BuildAndParseRaw()
end
Expand Down
28 changes: 20 additions & 8 deletions src/Classes/ItemsTab.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3150,13 +3150,13 @@ function ItemsTabClass:CorruptDisplayItem()
if modType == "Glimpse of Chaos" then
for modId, mod in pairs(data.itemMods.ItemExclusive) do
if modId:find("^UniqueSpecialCorruption") then
t_insert(implicitList[modType], { mod = mod })
t_insert(implicitList[modType], { modId = modId, mod = mod })
end
end
else
for modId, mod in pairs(self.displayItem.affixes) do
if mod.type == modType and self.displayItem:GetModSpawnWeight(mod) > 0 then
t_insert(implicitList[modType], { mod = mod })
t_insert(implicitList[modType], { modId = modId, mod = mod })
end
end
end
Expand All @@ -3182,7 +3182,7 @@ function ItemsTabClass:CorruptDisplayItem()
for _, entry in ipairs(implicitList[modType]) do
local mod = entry.mod
if not otherMod or mod.group ~= otherMod.group then
t_insert(control.list, { label = table.concat(mod, "/"), mod = mod })
t_insert(control.list, { label = table.concat(mod, "/"), modId = entry.modId, mod = mod })
end
end
control:SelByValue(selfMod, "mod")
Expand All @@ -3206,7 +3206,7 @@ function ItemsTabClass:CorruptDisplayItem()
for _, entry in ipairs(implicitList[modType]) do
local mod = entry.mod
if not selectedGroups[mod.group] or selectedGroups[mod.group].idx == i then
t_insert(control.list, { label = table.concat(mod, "/"), mod = mod })
t_insert(control.list, { label = table.concat(mod, "/"), modId = entry.modId, mod = mod })
end
end
end
Expand Down Expand Up @@ -3306,16 +3306,21 @@ function ItemsTabClass:CorruptDisplayItem()
-- implicits, like in pob2
if addingImplicits then
local newImplicit = {}
local selectedCorruptionMods = { }
for i = 1, maxImplicitNum do
local control = controls[string.format("implicit%d", i)]
if control.selIndex > 1 then
local mod = control.list[control.selIndex].mod
local entry = control.list[control.selIndex]
local mod = entry.mod
if currentModType == "Corrupted" then
t_insert(selectedCorruptionMods, mod)
end
for _, modLine in ipairs(mod) do
modLine = (currentModType == "ScourgeUpside" and "{scourge}" or "") .. modLine
if mod.modTags[1] then
t_insert(newImplicit, { line = "{tags:" .. table.concat(mod.modTags, ",") .. "}" .. modLine })
t_insert(newImplicit, { line = "{tags:" .. table.concat(mod.modTags, ",") .. "}" .. modLine, modGroup = currentModType == "Corrupted" and entry.modId or nil })
else
t_insert(newImplicit, { line = modLine })
t_insert(newImplicit, { line = modLine, modGroup = currentModType == "Corrupted" and entry.modId or nil })
end
end
end
Expand All @@ -3329,6 +3334,11 @@ function ItemsTabClass:CorruptDisplayItem()
t_insert(currentModType ~= "ScourgeUpside" and item.implicitModLines or item.scourgeModLines, implicit)
end
end
item:BuildAndParseRaw()
if #selectedCorruptionMods > 0 then
item.requirements.level = item:CalculateCorruptedRequirement(selectedCorruptionMods, self.displayItem.requirements.level)
item:BuildAndParseRaw()
end
end
if not addingImplicits then
for i, modLine in ipairs(item.explicitModLines) do
Expand All @@ -3338,7 +3348,9 @@ function ItemsTabClass:CorruptDisplayItem()
end
end
end
item:BuildAndParseRaw()
if not addingImplicits then
item:BuildAndParseRaw()
end
return item
end
if self.displayItem.rarity == "UNIQUE" or self.displayItem.rarity == "RELIC" then
Expand Down
Loading