diff --git a/spec/System/TestDefence_spec.lua b/spec/System/TestDefence_spec.lua index 6d9c1a3f79..d96e6bea24 100644 --- a/spec/System/TestDefence_spec.lua +++ b/spec/System/TestDefence_spec.lua @@ -49,6 +49,49 @@ describe("TestDefence", function() assert.are.equals(manaWithoutTotalEnergyShield + 100, player.output.Mana) end) + it("scales conversion rates down proportionally when they total more than 100%", function() + -- 50% to Energy Shield plus 75% to Armour (with 75% Chaos Resistance) is 125%, so both scale by 100/125 + build.configTab.input.customMods = "\z + 50% of Maximum Life Converted to Energy Shield\n\z + Convert 1% of maximum Life to twice as much Armour per 1% Chaos Resistance above 0%\n\z + +75% to Chaos Resistance\n\z + " + build.configTab:BuildModList() + runCallback("OnFrame") + + local lifeBase = build.calcsTab.mainEnv.player.modDB:Sum("BASE", nil, "Life") + local factor = 100 / 125 + assert.are.equals(round(lifeBase * 50 * factor / 100), build.calcsTab.mainOutput.EnergyShield) + assert.are.equals(round(lifeBase * (75 * factor + 75) / 100), build.calcsTab.mainOutput.Armour) + end) + + it("takes each conversion target's share from the unconverted slot base", function() + local function energyShieldBodyArmourWith(customMods) + newBuild() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Tattered Robe + +100 to maximum Energy Shield + ]]) + build.itemsTab:AddDisplayItem() + build.configTab.input.customMods = customMods + build.configTab:BuildModList() + runCallback("OnFrame") + return build.calcsTab.mainOutput + end + local toMana = "Convert 40% of maximum Energy Shield to maximum Mana" + local asArmour = "Gain 20% of maximum Energy Shield as extra Armour" + + local manaOnly = energyShieldBodyArmourWith(toMana) + local armourOnly = energyShieldBodyArmourWith(asArmour) + local both = energyShieldBodyArmourWith(toMana .. "\n" .. asArmour) + + -- Gaining Armour from Energy Shield must not reduce the Energy Shield kept or the Mana converted + assert.are.equals(manaOnly.EnergyShield, both.EnergyShield) + assert.are.equals(manaOnly.Mana, both.Mana) + assert.are.equals(armourOnly.Armour, both.Armour) + end) + it("Geofri's Sanctuary mods work", function() build.itemsTab:CreateDisplayItemFromRaw([[ Geofri's Sanctuary diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index de8d8996b5..e5aa785b59 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -1372,7 +1372,7 @@ function calcs.defence(env, actor) if totalConversion > 100 then local factor = 100 / totalConversion totalConversion = 100 - for name, val in ipairs(source.conversionRate) do + for name, val in pairs(source.conversionRate) do source.conversionRate[name] = val * factor end end @@ -1410,7 +1410,6 @@ function calcs.defence(env, actor) if breakdown then breakdown.slot(slot, source.name .. " to " .. target.name .. " conversion", { slotName = slot }, targetBase, nil, unpack(target.mods)) end - source.basePerSlot[slot] = source.basePerSlot[slot] * (100 - source.totalConversion) / 100 end end local targetBase = globalBase * rate / 100 @@ -1437,6 +1436,10 @@ function calcs.defence(env, actor) end end if source.defence then + -- Every target takes its share from the unconverted base, so reduce the source once, after all targets + for _, slot in pairs({ "Helmet", "Gloves", "Boots", "Body Armour", "Weapon 2", "Weapon 3" }) do + source.basePerSlot[slot] = source.basePerSlot[slot] * (100 - source.totalConversion) / 100 + end source.globalBase = globalBase * (100 - source.totalConversion) / 100 source.totalBase = totalBase * (100 - source.totalConversion) / 100 end