From 193c9c58f77ebfe44868cf79b774400f36d7dd16 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Fri, 13 Jun 2025 03:39:38 +0200 Subject: [PATCH 1/5] Fix globalLimit being sensitive to tag order (#8652) * FEAT(items): Add showcased uniques to New.lua * FEAT(mods): add handling for new mods on Scornflux * FEAT(mods): add handling for "Take X Fire Damage when you use a Skill" * FEAT(mods): add handling for Damage penetrates "Fire Resistance equal to your overcapped Fire Resistance" * FEAT(mods): add handling for "Warcries have an additional Life Cost equal to 15% of your Maximum Life" * FEAT(mods): add handling for "Warcry Skills have X increased Area of Effect" * FEAT(mods): add handling for `Gain no armour from equipped body armour` * FEAT(mods): port generalized "doubled" mod handling from POB2 https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2/pull/1095 * Update spelling and ModCache * FIX(mods): globalLimit style mods did not work sometimes When a mod gots pice wise parsed the tags can be added to the mod table in unpredictable order. The inital implementation was simply checking the first tag which caused the global limit functionality to not work sometimes. This commit moves the logic into EvalMod. * FEAT(mods): add support for "you have no Str/Dex" mods * FIX(spelling): un-rake-able --------- Co-authored-by: Wires77 --- src/Classes/ModDB.lua | 28 +++------------------------- src/Classes/ModStore.lua | 12 +++++++++++- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/Classes/ModDB.lua b/src/Classes/ModDB.lua index 75e0cad813..44f725f0d3 100644 --- a/src/Classes/ModDB.lua +++ b/src/Classes/ModDB.lua @@ -98,14 +98,7 @@ function ModDBClass:SumInternal(context, modType, cfg, flags, keywordFlags, sour local mod = modList[i] if mod.type == modType and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or ( mod.source and (mod.source:match("[^:]+") == source or mod.source == source))) then if mod[1] then - local value = context:EvalMod(mod, cfg) or 0 - if mod[1].globalLimit and mod[1].globalLimitKey then - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] or 0 - if globalLimits[mod[1].globalLimitKey] + value > mod[1].globalLimit then - value = mod[1].globalLimit - globalLimits[mod[1].globalLimitKey] - end - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] + value - end + local value = context:EvalMod(mod, cfg, globalLimits) or 0 result = result + value else result = result + mod.value @@ -133,14 +126,7 @@ function ModDBClass:MoreInternal(context, cfg, flags, keywordFlags, source, ...) if mod.type == "MORE" and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or mod.source:match("[^:]+") == source) then local value if mod[1] then - value = context:EvalMod(mod, cfg) or 0 - if mod[1].globalLimit and mod[1].globalLimitKey then - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] or 0 - if globalLimits[mod[1].globalLimitKey] + value > mod[1].globalLimit then - value = mod[1].globalLimit - globalLimits[mod[1].globalLimitKey] - end - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] + value - end + value = context:EvalMod(mod, cfg, globalLimits) or 0 else value = mod.value or 0 end @@ -249,15 +235,7 @@ function ModDBClass:TabulateInternal(context, result, modType, cfg, flags, keywo if (mod.type == modType or not modType) and band(flags, mod.flags) == mod.flags and MatchKeywordFlags(keywordFlags, mod.keywordFlags) and (not source or mod.source:match("[^:]+") == source) then local value if mod[1] then - value = context:EvalMod(mod, cfg) - if mod[1].globalLimit and mod[1].globalLimitKey then - value = value or 0 - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] or 0 - if globalLimits[mod[1].globalLimitKey] + value > mod[1].globalLimit then - value = mod[1].globalLimit - globalLimits[mod[1].globalLimitKey] - end - globalLimits[mod[1].globalLimitKey] = globalLimits[mod[1].globalLimitKey] + value - end + value = context:EvalMod(mod, cfg, globalLimits) else value = mod.value end diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index d1033107b4..c1138050d9 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -283,12 +283,22 @@ function ModStoreClass:GetStat(stat, cfg) end end -function ModStoreClass:EvalMod(mod, cfg) +function ModStoreClass:EvalMod(mod, cfg, globalLimits) local value = mod.value for _, tag in ipairs(mod) do if tag.type == "Multiplier" then local target = self local limitTarget = self + + if globalLimits and tag.globalLimit and tag.globalLimitKey then + value = value or 0 + globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] or 0 + if globalLimits[tag.globalLimitKey] + value > tag.globalLimit then + value = tag.globalLimit - globalLimits[tag.globalLimitKey] + end + globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] + value + end + -- Allow limiting a self multiplier on a parent multiplier (eg. Agony Crawler on player virulence) -- This explicit target is necessary because even though the GetMultiplier method does call self.parent.GetMultiplier, it does so with noMod = true, -- disabling the summation (3rd part): (not noMod and self:Sum("BASE", cfg, multiplierName[var]) or 0) From 44a59b6d137aaf2da813897bfeadc8a62359e58f Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Fri, 13 Jun 2025 10:17:46 +0200 Subject: [PATCH 2/5] [PATCH 1/3] FIX: globalLimit not applying --- src/Classes/ModStore.lua | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index c1138050d9..03b670aaa2 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -290,15 +290,6 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) local target = self local limitTarget = self - if globalLimits and tag.globalLimit and tag.globalLimitKey then - value = value or 0 - globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] or 0 - if globalLimits[tag.globalLimitKey] + value > tag.globalLimit then - value = tag.globalLimit - globalLimits[tag.globalLimitKey] - end - globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] + value - end - -- Allow limiting a self multiplier on a parent multiplier (eg. Agony Crawler on player virulence) -- This explicit target is necessary because even though the GetMultiplier method does call self.parent.GetMultiplier, it does so with noMod = true, -- disabling the summation (3rd part): (not noMod and self:Sum("BASE", cfg, multiplierName[var]) or 0) @@ -835,6 +826,18 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) return end end - end + end + + -- Apply global limits + for _, tag in ipairs(mod) do + if globalLimits and tag.globalLimit and tag.globalLimitKey then + value = value or 0 + globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] or 0 + if globalLimits[tag.globalLimitKey] + value > tag.globalLimit then + value = tag.globalLimit - globalLimits[tag.globalLimitKey] + end + globalLimits[tag.globalLimitKey] = globalLimits[tag.globalLimitKey] + value + end + end return value -end +end \ No newline at end of file From a7723d2ec5d3eda5301778aa0e6e2ae41332596d Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Fri, 13 Jun 2025 15:55:45 +0200 Subject: [PATCH 3/5] [PATCH 2/3] MISC(test): add some more tests for globlaLimit type mods --- spec/System/TestItemMods_spec.lua | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/spec/System/TestItemMods_spec.lua b/spec/System/TestItemMods_spec.lua index adbaaf7551..5de3762fc2 100644 --- a/spec/System/TestItemMods_spec.lua +++ b/spec/System/TestItemMods_spec.lua @@ -176,4 +176,44 @@ describe("TetsItemMods", function() assert.are_not.equals(baseLife, build.calcsTab.mainOutput.Life) end) + + it("globalLimit mods", function() + build.configTab.input.customMods = [[ + -1000% to cold resistance + ]] + build.configTab:BuildModList() + build.itemsTab:CreateDisplayItemFromRaw([[Replica Nebulis + Void Sceptre + League: Heist + Quality: 20 + Sockets: B-B-B + LevelReq: 68 + Implicits: 1 + 40% increased Elemental Damage + {fractured}{range:1}(15-20)% increased Cast Speed + {range:1}(15-20)% increased Cold Damage per 1% Missing Cold Resistance, up to a maximum of 300% + {range:1}(15-20)% increased Fire Damage per 1% Missing Fire Resistance, up to a maximum of 300%]]) + build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Slot: Weapon 1\nFireball 20/0 Default 1\n") + runCallback("OnFrame") + + assert.are_not.equals(340, build.calcsTab.mainEnv.modDB:Sum("INC", "FireDamage")) + assert.are_not.equals(340, build.calcsTab.mainEnv.modDB:Sum("INC", "ColdDamage")) + + newBuild() + + build.configTab.input.customMods = [[ + Gain 25% increased Armour per 5 Power for 8 seconds when you Warcry, up to a maximum of 100% + Warcries have infinite Power + ]] + build.configTab:BuildModList() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Plate Vest + Armour: 32 + ]]) + build.itemsTab:AddDisplayItem() + assert.are_not.equals(64, build.calcsTab.mainOutput.Armour) + runCallback("OnFrame") + end) end) From 9c7cccc8b5f1946873a8252d9314a8b91cecf1b5 Mon Sep 17 00:00:00 2001 From: Paliak <91493239+Paliak@users.noreply.github.com> Date: Fri, 13 Jun 2025 16:14:37 +0200 Subject: [PATCH 4/5] [PATCH 3/3] MISC(test): test PerStat code path --- spec/System/TestItemMods_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/System/TestItemMods_spec.lua b/spec/System/TestItemMods_spec.lua index 5de3762fc2..b5d44677e0 100644 --- a/spec/System/TestItemMods_spec.lua +++ b/spec/System/TestItemMods_spec.lua @@ -205,6 +205,7 @@ describe("TetsItemMods", function() build.configTab.input.customMods = [[ Gain 25% increased Armour per 5 Power for 8 seconds when you Warcry, up to a maximum of 100% Warcries have infinite Power + warcries grant arcane surge to you and allies, with 10% increased effect per 5 power, up to 100% ]] build.configTab:BuildModList() build.itemsTab:CreateDisplayItemFromRaw([[ @@ -213,6 +214,9 @@ describe("TetsItemMods", function() Armour: 32 ]]) build.itemsTab:AddDisplayItem() + build.skillsTab:PasteSocketGroup("Arc 20/0 Default 1") + + assert.are_not.equals(40, build.calcsTab.mainEnv.modDB:Sum("INC", { flags = ModFlag.Cast }, "Speed")) assert.are_not.equals(64, build.calcsTab.mainOutput.Armour) runCallback("OnFrame") end) From 41d38faf4ca93b74efaeb61dd1346d01dad3aca9 Mon Sep 17 00:00:00 2001 From: Wires77 Date: Thu, 28 Aug 2025 22:32:33 -0500 Subject: [PATCH 5/5] Fix tests for PoE2 --- spec/System/TestItemMods_spec.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/System/TestItemMods_spec.lua b/spec/System/TestItemMods_spec.lua index b5d44677e0..3cd048c22f 100644 --- a/spec/System/TestItemMods_spec.lua +++ b/spec/System/TestItemMods_spec.lua @@ -183,7 +183,7 @@ describe("TetsItemMods", function() ]] build.configTab:BuildModList() build.itemsTab:CreateDisplayItemFromRaw([[Replica Nebulis - Void Sceptre + Clasped Sceptre League: Heist Quality: 20 Sockets: B-B-B @@ -210,14 +210,14 @@ describe("TetsItemMods", function() build.configTab:BuildModList() build.itemsTab:CreateDisplayItemFromRaw([[ New Item - Plate Vest - Armour: 32 + Fur Plate + Armour: 60 ]]) build.itemsTab:AddDisplayItem() build.skillsTab:PasteSocketGroup("Arc 20/0 Default 1") - assert.are_not.equals(40, build.calcsTab.mainEnv.modDB:Sum("INC", { flags = ModFlag.Cast }, "Speed")) - assert.are_not.equals(64, build.calcsTab.mainOutput.Armour) + assert.are_not.equals(20, build.calcsTab.mainEnv.modDB:Sum("MORE", { flags = ModFlag.Cast }, "Speed")) + assert.are_not.equals(120, build.calcsTab.mainOutput.Armour) runCallback("OnFrame") end) end)