From 56e67a83d5c4038130624ade7333c4444fd80fa0 Mon Sep 17 00:00:00 2001 From: Matthew Sbar Date: Sat, 1 Aug 2026 10:27:46 -0500 Subject: [PATCH] Add mine detonation chance --- spec/System/TestOffence_spec.lua | 39 ++++++++++++++++++++++++++++++++ src/Data/ModCache.lua | 4 ++-- src/Modules/CalcOffence.lua | 12 ++++++++++ src/Modules/CalcSections.lua | 4 ++++ src/Modules/ModParser.lua | 1 + 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/spec/System/TestOffence_spec.lua b/spec/System/TestOffence_spec.lua index d93047e864..9337863127 100644 --- a/spec/System/TestOffence_spec.lua +++ b/spec/System/TestOffence_spec.lua @@ -279,4 +279,43 @@ describe("TestOffence", function() assert.are.equals(1, build.calcsTab.mainOutput[outputName]) end) end + + it("applies chance for Mines to be Detonated an Additional Time as an average DPS multiplier", function() + build.skillsTab:PasteSocketGroup("Slot: Body Armour\nStormblast Mine 20/0 1\n") + runCallback("OnFrame") + + local baseDPS = build.calcsTab.mainOutput.TotalDPS + assert.is_true(baseDPS > 0) + + build.configTab.input.customMods = "Mines have a 10% chance to be Detonated an Additional Time" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(10, build.calcsTab.mainOutput.MineAdditionalDetonationChance) + assertNearRelative(baseDPS * 1.10, build.calcsTab.mainOutput.TotalDPS, 0.001, "10% chance to be detonated an additional time") + + -- Multiple sources stack additively, and the chance is capped at 100% (at most one extra detonation) + build.configTab.input.customMods = [[ + Mines have a 15% chance to be Detonated an Additional Time + Mines have a 100% chance to be Detonated an Additional Time + ]] + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(100, build.calcsTab.mainOutput.MineAdditionalDetonationChance) + assertNearRelative(baseDPS * 2, build.calcsTab.mainOutput.TotalDPS, 0.001, "capped at 100% chance") + + -- Does not apply to skills that are not mines + newBuild() + build.skillsTab:PasteSocketGroup("Slot: Body Armour\nFireball 20/0 1\n") + runCallback("OnFrame") + local fireballDPS = build.calcsTab.mainOutput.TotalDPS + assert.is_true(fireballDPS > 0) + + build.configTab.input.customMods = "Mines have a 10% chance to be Detonated an Additional Time" + build.configTab:BuildModList() + runCallback("OnFrame") + + assert.are.equals(fireballDPS, build.calcsTab.mainOutput.TotalDPS) + end) end) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 4544bc04a8..d7fdcb05c3 100755 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -10033,8 +10033,8 @@ c["Mines have 20% increased Detonation Speed Mines have a 10% chance to be Deton c["Mines have 30% increased Detonation Speed"]={nil,"Mines have 30% increased Detonation Speed "} c["Mines have 50% increased Detonation Speed"]={nil,"Mines have 50% increased Detonation Speed "} c["Mines have 50% increased Detonation Speed Skills which throw Mines throw up to 1 additional Mine if you have at least 800 Dexterity"]={nil,"Mines have 50% increased Detonation Speed Skills which throw Mines throw up to 1 additional Mine if you have at least 800 Dexterity "} -c["Mines have a 10% chance to be Detonated an Additional Time"]={nil,"Mines have a 10% chance to be Detonated an Additional Time "} -c["Mines have a 15% chance to be Detonated an Additional Time"]={nil,"Mines have a 15% chance to be Detonated an Additional Time "} +c["Mines have a 10% chance to be Detonated an Additional Time"]={{[1]={flags=0,keywordFlags=0,name="MineAdditionalDetonationChance",type="BASE",value=10}},nil} +c["Mines have a 15% chance to be Detonated an Additional Time"]={{[1]={flags=0,keywordFlags=0,name="MineAdditionalDetonationChance",type="BASE",value=15}},nil} c["Minion Instability"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Minion Instability"}},nil} c["Minion Life is increased by their Overcapped Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={div=1,stat="FireResistOverCap",type="PerStat"},flags=0,keywordFlags=0,name="Life",type="INC",value=1}}}},nil} c["Minion Spells Triggered by this Item have a 0.25 second Cooldown with 5 Uses"]={nil,"Minion Spells Triggered by this Item have a 0.25 second Cooldown with 5 Uses "} diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 956ac30db3..8e355c4d59 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -1351,6 +1351,18 @@ function calcs.offence(env, actor, activeSkill) }) end + -- Calculate chance for mines to be detonated an additional time + output.MineAdditionalDetonationChance = m_min(skillModList:Sum("BASE", skillCfg, "MineAdditionalDetonationChance"), 100) + if output.MineAdditionalDetonationChance > 0 then + skillData.dpsMultiplier = (skillData.dpsMultiplier or 1) * (1 + output.MineAdditionalDetonationChance / 100) + if breakdown then + breakdown.MineAdditionalDetonationChance = { + s_format("%g%% ^8(chance to be detonated an additional time)", output.MineAdditionalDetonationChance), + s_format("= x %.2f ^8(average number of detonations)", 1 + output.MineAdditionalDetonationChance / 100), + } + end + end + local incArea, moreArea = calcLib.mods(skillModList, skillCfg, "MineDetonationAreaOfEffect") local areaMod = round(round(incArea * moreArea, 10), 2) output.MineDetonationRadius = calcRadius(data.misc.MineDetonationRadiusBase, areaMod) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index fcc1f55f16..e6818b07c9 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -789,6 +789,10 @@ return { }, }, { label = "Mine Throw Time", flag = "mine", { format = "{2:output:MineLayingTime}s", { breakdown = "MineThrowingTime" }, }, }, { label = "Avg. Mines per Throw", flag = "mine", { format = "{2:output:MineThrowCount}", { modName = "MineThrowCount", cfg = "skill"}, }, }, + { label = "Extra Deton. Chance", haveOutput = "MineAdditionalDetonationChance", { format = "{0:output:MineAdditionalDetonationChance}%", + { breakdown = "MineAdditionalDetonationChance" }, + { modName = "MineAdditionalDetonationChance", cfg = "skill" }, + }, }, { label = "Mine Deton. Radius", flag = "mine", { format = "{1:output:MineDetonationRadiusMetre}m", { breakdown = "MineDetonationRadius" }, { label = "Area of Effect modifiers", modName = "MineDetonationAreaOfEffect", cfg = "skill" }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 751b2ada44..ee846c2fbe 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -4279,6 +4279,7 @@ local specialModList = { ["can have up to (%d+) additional traps? placed at a time"] = function(num) return { mod("ActiveTrapLimit", "BASE", num) } end, ["can have (%d+) fewer traps placed at a time"] = function(num) return { mod("ActiveTrapLimit", "BASE", -num) } end, ["can have up to (%d+) additional remote mines? placed at a time"] = function(num) return { mod("ActiveMineLimit", "BASE", num) } end, + ["mines have a (%d+)%% chance to be detonated an additional time"] = function(num) return { mod("MineAdditionalDetonationChance", "BASE", num) } end, -- Additional trap & mine throw ["throw an additional trap"] = { mod("TrapThrowCount", "BASE", 1) }, ["(%d+)%% chance to throw up to (%d+) additional traps?"] = function(chance, _, num) return { mod("TrapThrowCount", "BASE", tonumber(num) * tonumber(chance) / 100.0) } end,