From 1bb94627dc6bda5d6a4a1cf327d7ad134ad91ce8 Mon Sep 17 00:00:00 2001 From: Trifall Date: Sat, 8 Aug 2026 03:16:28 -0400 Subject: [PATCH 1/3] Fix invalid mod parsing on mods that grant skills --- src/Classes/Item.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index c0d2e7a7dcd..1d211aa20f1 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -1420,9 +1420,11 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) if mod.valueScalar and mod.valueScalar ~= 1 then local rangedLine = itemLib.applyRange(mod.line, mod.range or 1, mod.valueScalar, 1) local modList, extra = modLib.parseMod(rangedLine) - mod.displayValueScalar = 1 - mod.modList = modList - mod.extra = extra + if modList then + mod.displayValueScalar = 1 + mod.modList = modList + mod.extra = extra + end end ::modMagnitudeContinue:: end From 9b26d7d08d7513e5e3fde3a560fb00774d3a67fa Mon Sep 17 00:00:00 2001 From: Trifall Date: Sat, 8 Aug 2026 03:33:57 -0400 Subject: [PATCH 2/3] add regression test for invalid mod parsing involving grantedExtraSkill --- spec/System/TestItemParse_spec.lua | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua index 0654d3c8634..51696093fa2 100644 --- a/spec/System/TestItemParse_spec.lua +++ b/spec/System/TestItemParse_spec.lua @@ -1358,5 +1358,36 @@ describe("TestAdvancedItemParse #item", function() assert.equal(27, spellCrit()) assert.equal(8, spellDamage()) end) + + + it("does not overwrite existing values when a suffix magnitude mod fails to parse", function() + -- grantedExtraSkill returns (nil) when the skill is missing from gemIdLookup, + -- so parseMod also returns nil (no second value) -> overwriting both modList and extra when the magnitude loop runs + local item = new("Item", [[ + Item Class: Rings + Rarity: Rare + Plague Knuckle + Helical Ring + -------- + Item Level: 84 + -------- + { Implicit Modifier } + 50% increased Suffix Modifier magnitudes + -------- + { Suffix Modifier "of !!UNPARSEABLE!!" — 50% Increased } + Grants Level 20 Aspect of !!UNPARSEABLE!! Skill + -------- + ]]) + assert.truthy(item.base) + local aspectLine + for _, modLine in ipairs(item.explicitModLines) do + if modLine.line:find("UNPARSEABLE", 1, true) then + aspectLine = modLine + end + end + assert.truthy(aspectLine) + assert.truthy(aspectLine.modList) + assert.truthy(aspectLine.extra) + end) end) end) From 6e2bb17591b45c5dfda8415d5142676b51db9cf2 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Mon, 24 Aug 2026 08:39:32 +1000 Subject: [PATCH 3/3] Stop skill granting mods from scaling --- spec/System/TestItemParse_spec.lua | 30 +++++++++++++++++++----------- src/Classes/Item.lua | 14 +++++++++++++- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/spec/System/TestItemParse_spec.lua b/spec/System/TestItemParse_spec.lua index 51696093fa2..8c19280a0c7 100644 --- a/spec/System/TestItemParse_spec.lua +++ b/spec/System/TestItemParse_spec.lua @@ -1358,11 +1358,7 @@ describe("TestAdvancedItemParse #item", function() assert.equal(27, spellCrit()) assert.equal(8, spellDamage()) end) - - - it("does not overwrite existing values when a suffix magnitude mod fails to parse", function() - -- grantedExtraSkill returns (nil) when the skill is missing from gemIdLookup, - -- so parseMod also returns nil (no second value) -> overwriting both modList and extra when the magnitude loop runs + it("does not scale modifiers that grant skills", function() local item = new("Item", [[ Item Class: Rings Rarity: Rare @@ -1376,18 +1372,30 @@ describe("TestAdvancedItemParse #item", function() -------- { Suffix Modifier "of !!UNPARSEABLE!!" — 50% Increased } Grants Level 20 Aspect of !!UNPARSEABLE!! Skill + { Suffix Modifier "of the Spider" — 50% Increased } + Grants Level 20 Aspect of the Spider Skill -------- ]]) assert.truthy(item.base) - local aspectLine + local found = 0 + local foundExtraSkill = false for _, modLine in ipairs(item.explicitModLines) do - if modLine.line:find("UNPARSEABLE", 1, true) then - aspectLine = modLine + if modLine.line:find("Grants Level", 1, true) then + found = found + 1 + assert.matches("Level 20", itemLib.formatModLine(modLine)) + for _, mod in ipairs(modLine.modList) do + if mod.name == "ExtraSkill" then + foundExtraSkill = true + assert.equals(20, mod.value.level) + end + end + if modLine.line:find("UNPARSEABLE", 1, true) then + assert.truthy(modLine.extra) + end end end - assert.truthy(aspectLine) - assert.truthy(aspectLine.modList) - assert.truthy(aspectLine.extra) + assert.equals(2, found) + assert.is_true(foundExtraSkill) end) end) end) diff --git a/src/Classes/Item.lua b/src/Classes/Item.lua index 1d211aa20f1..48fb55d1666 100644 --- a/src/Classes/Item.lua +++ b/src/Classes/Item.lua @@ -1390,6 +1390,18 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) if mod.variantList and (self:GetModLineVariantCount(mod) == 0) then goto modMagnitudeContinue end + -- Modifiers that grant skills are not affected by modifier magnitude. + local grantsSkill = false + for _, parsedMod in ipairs(mod.modList) do + if parsedMod.name == "ExtraSkill" then + grantsSkill = true + break + end + end + if mod.extra and not grantsSkill then + local line = mod.line:lower() + grantsSkill = line:match("^grants level %d+ ") or line:match("^grants %D+$") + end -- Create a fast lookup table for all provided tags local tagLookup = {} for _, curTag in ipairs(mod.modTags) do @@ -1410,7 +1422,7 @@ function ItemClass:ParseRaw(raw, rarity, highQuality) if modMagnitudeMod.anyTags and not (tagLookup[modMagnitudeMod.anyTags[1]] or tagLookup[modMagnitudeMod.anyTags[2]]) then match = false end - if match and not mod.unscalable then + if match and not mod.unscalable and not grantsSkill then if modMagnitudeMod.multiplier then mod.valueScalar = (mod.valueScalar or 1) * modMagnitudeMod.multiplier else