From a369a74e0be0c1d09977e146e57f4444e1647555 Mon Sep 17 00:00:00 2001 From: Alexander Karrer Date: Thu, 29 Oct 2026 04:23:09 +0100 Subject: [PATCH] Use selected minion life for Death Wish explosions --- spec/System/TestDeathWish_spec.lua | 203 +++++++++++++++++++++++++++++ src/Classes/ConfigTab.lua | 17 +++ src/Classes/SkillsTab.lua | 18 +++ src/Data/Skills/other.lua | 8 +- src/Export/Skills/other.txt | 8 +- src/Modules/CalcActiveSkill.lua | 23 +++- src/Modules/CalcOffence.lua | 4 +- src/Modules/CalcPerform.lua | 61 ++++++--- src/Modules/CalcSections.lua | 1 + src/Modules/ConfigOptions.lua | 16 +++ 10 files changed, 322 insertions(+), 37 deletions(-) create mode 100644 spec/System/TestDeathWish_spec.lua diff --git a/spec/System/TestDeathWish_spec.lua b/spec/System/TestDeathWish_spec.lua new file mode 100644 index 00000000000..61388fa8c3f --- /dev/null +++ b/spec/System/TestDeathWish_spec.lua @@ -0,0 +1,203 @@ +describe("Death Wish minion explosion", function() + local function recalculate(group) + if group then + build.mainSocketGroup = group + build.calcsTab.input.skill_number = group + end + build.buildFlag = true + runCallback("OnFrame") + end + + local function minionKey(groupIndex, gemIndex) + local gem = build.skillsTab.socketGroupList[groupIndex].gemList[gemIndex or 1] + return "minion:"..build.skillsTab:GetMinionSourceId(gem)..":"..gem.skillId + end + + local function selectMinion(key) + build.configTab.input.deathWishMinion = key + recalculate(2) + end + + local function explosionDamage() + return build.calcsTab.mainEnv.player.mainSkill.skillData.FireBonusMin + end + + before_each(function() + newBuild() + build.skillsTab:PasteSocketGroup("Summon Stone Golem 20/0 1\nMinion Life 20/0 1") + build.itemsTab:CreateDisplayItemFromRaw([[Maw of Mischief +Bone Helmet +Grants Level 20 Death Wish Skill]]) + build.itemsTab:AddDisplayItem() + recalculate(2) + end) + + it("defaults to Minion Explosion in the sidebar and Calcs", function() + assert.are.equal(2, build.calcsTab.mainEnv.player.mainSkill.skillPart) + assert.are.equal(2, build.calcsTab.calcsEnv.player.mainSkill.skillPart) + end) + + it("uses the summoning skill's calculated life and ignores corpse life", function() + recalculate(1) + local minionLife = build.calcsTab.mainOutput.Minion.Life + assert.is_true(minionLife > 0) + build.configTab.input.detonateDeadCorpseLife = 1000000 + build.configTab:BuildModList() + selectMinion(minionKey(1)) + assert.are.equal(minionLife, build.calcsTab.mainOutput.DeathWishMinionLife) + assert.are.near(minionLife * 0.19, explosionDamage(), 0.001) + assert.are.equal(minionLife, build.calcsTab.calcsOutput.DeathWishMinionLife) + end) + + it("updates when minion gem level, supports and global life scaling change", function() + selectMinion(minionKey(1)) + local originalLife = build.calcsTab.mainOutput.DeathWishMinionLife + build.skillsTab.socketGroupList[1].gemList[1].level = 25 + build.configTab.input.customMods = "Minions have 100% increased maximum Life" + build.configTab:BuildModList() + recalculate() + local scaledLife = build.calcsTab.mainOutput.DeathWishMinionLife + assert.is_true(scaledLife > originalLife) + recalculate(1) + assert.are.equal(scaledLife, build.calcsTab.mainOutput.Minion.Life) + build.skillsTab.socketGroupList[1].gemList[2].enabled = false + recalculate(2) + assert.is_true(build.calcsTab.mainOutput.DeathWishMinionLife < scaledLife) + end) + + it("falls back to enemy corpse life when no minion is selected", function() + build.configTab.input.detonateDeadCorpseLife = 10000 + build.configTab:BuildModList() + selectMinion("None") + assert.is_nil(build.calcsTab.mainOutput.DeathWishMinionLife) + assert.are.near(1900, explosionDamage(), 0.001) + end) + + it("falls back when the selected minion is disabled or removed", function() + build.configTab.input.detonateDeadCorpseLife = 10000 + build.configTab:BuildModList() + selectMinion(minionKey(1)) + build.skillsTab.socketGroupList[1].enabled = false + recalculate() + assert.is_nil(build.calcsTab.mainOutput.DeathWishMinionLife) + assert.are.near(1900, explosionDamage(), 0.001) + selectMinion("9:1:SummonStoneGolem") + assert.is_nil(build.calcsTab.mainOutput.DeathWishMinionLife) + end) + + it("keeps channelling selectable without explosion damage", function() + selectMinion(minionKey(1)) + local gem = build.skillsTab.socketGroupList[2].gemList[1] + gem.skillPart = 1 + gem.skillPartCalcs = 1 + recalculate() + assert.are.equal(1, build.calcsTab.mainEnv.player.mainSkill.skillPart) + assert.is_nil(explosionDamage()) + end) + + it("saves and restores the selected minion", function() + selectMinion(minionKey(1)) + local life = build.calcsTab.mainOutput.DeathWishMinionLife + local xml = build:SaveDB("code") + loadBuildFromXML(xml) + assert.are.equal(minionKey(1), build.configTab.input.deathWishMinion) + assert.are.equal(life, build.calcsTab.mainOutput.DeathWishMinionLife) + end) + + it("distinguishes two sources of the same minion", function() + build.skillsTab:PasteSocketGroup("Summon Stone Golem 1/0 1") + recalculate(3) + local lowLevelLife = build.calcsTab.mainOutput.Minion.Life + selectMinion(minionKey(3)) + assert.are.equal(lowLevelLife, build.calcsTab.mainOutput.DeathWishMinionLife) + selectMinion(minionKey(1)) + assert.is_true(build.calcsTab.mainOutput.DeathWishMinionLife > lowLevelLife) + end) + + it("uses the selected spectre's calculated life", function() + build.spectreList = { "Metadata/Monsters/BloodChieftain/MonkeyChiefBloodEnrage" } + build.skillsTab:PasteSocketGroup("Raise Spectre 20/0 1\nMinion Life 20/0 1") + recalculate(3) + local spectreLife = build.calcsTab.mainOutput.Minion.Life + selectMinion(minionKey(3)) + assert.are.equal(spectreLife, build.calcsTab.mainOutput.DeathWishMinionLife) + assert.are.near(spectreLife * 0.19, explosionDamage(), 0.001) + end) + + it("uses minion life in Full DPS and calculator comparisons", function() + selectMinion(minionKey(1)) + build.skillsTab.socketGroupList[2].includeInFullDPS = true + recalculate() + local selectedDPS = build.calcsTab.mainOutput.FullDPS + assert.is_true(selectedDPS > 0) + local calculator = build.calcsTab.calcs.getMiscCalculator(build) + local result = calculator({ }, false) + assert.are.equal(build.calcsTab.mainOutput.DeathWishMinionLife, result.DeathWishMinionLife) + build.configTab.input.detonateDeadCorpseLife = 1000000 + build.configTab:BuildModList() + recalculate() + assert.are.equal(selectedDPS, build.calcsTab.mainOutput.FullDPS) + end) + + it("keeps the selected source when groups are reordered and saved", function() + build.skillsTab:PasteSocketGroup("Summon Stone Golem 1/0 1") + selectMinion(minionKey(1)) + local key = build.configTab.input.deathWishMinion + local life = build.calcsTab.mainOutput.DeathWishMinionLife + local groups = build.skillsTab.socketGroupList + table.insert(groups, 3, table.remove(groups, 1)) + build.skillsTab.controls.groupList:OnOrderChange(1, 3) + recalculate() + assert.are.equal(key, build.configTab.input.deathWishMinion) + assert.are.equal(life, build.calcsTab.mainOutput.DeathWishMinionLife) + loadBuildFromXML(build:SaveDB("code")) + assert.are.equal(key, build.configTab.input.deathWishMinion) + assert.are.equal(life, build.calcsTab.mainOutput.DeathWishMinionLife) + end) + + it("keeps the selected source when gems are reordered and undone", function() + selectMinion(minionKey(1)) + local key = build.configTab.input.deathWishMinion + local life = build.calcsTab.mainOutput.DeathWishMinionLife + local state = build.skillsTab:CreateUndoState() + local gems = build.skillsTab.socketGroupList[1].gemList + table.insert(gems, table.remove(gems, 1)) + recalculate() + assert.are.equal(life, build.calcsTab.mainOutput.DeathWishMinionLife) + build.skillsTab:RestoreUndoState(state) + recalculate() + assert.are.equal(key, build.configTab.input.deathWishMinion) + assert.are.equal(life, build.calcsTab.mainOutput.DeathWishMinionLife) + end) + + it("does not select a replacement gem after its source is deleted", function() + selectMinion(minionKey(1)) + local key = build.configTab.input.deathWishMinion + table.remove(build.skillsTab.socketGroupList[1].gemList, 1) + recalculate() + assert.is_nil(build.calcsTab.mainOutput.DeathWishMinionLife) + loadBuildFromXML(build:SaveDB("code")) + build.skillsTab:PasteSocketGroup("Summon Stone Golem 20/0 1") + recalculate(2) + assert.are.equal(key, build.configTab.input.deathWishMinion) + assert.is_nil(build.calcsTab.mainOutput.DeathWishMinionLife) + assert.is_true(minionKey(3) ~= key) + end) + + it("migrates selections saved with group positions", function() + selectMinion("1:1:SummonStoneGolem") + assert.are.equal(minionKey(1), build.configTab.input.deathWishMinion) + assert.is_true(build.calcsTab.mainOutput.DeathWishMinionLife > 0) + end) + + it("populates the selector with enabled minions and a corpse fallback", function() + local control = build.configTab.varControls.deathWishMinion + control.refreshList() + assert.are.equal(2, #control.list) + assert.are.equal("None", control.list[1].val) + assert.are.equal(minionKey(1), control.list[2].val) + control.selFunc(2, control.list[2]) + recalculate() + assert.is_true(build.calcsTab.mainOutput.DeathWishMinionLife > 0) + end) +end) diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index 3d1f007cd63..30a7fec6ebd 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -319,6 +319,15 @@ function ConfigTabClass:ConfigTab(build) self:BuildModList() self.build.buildFlag = true end) + if varData.listFunc then + control.refreshList = function() + control.list = varData.listFunc(self.build) + control:CheckDroppedWidth(true) + control:UpdateSearch() + control.selIndex = 1 + control:SelByValue(self.input[varData.var] or self:GetDefaultState(varData.var), "val") + end + end elseif varData.type == "text" and not varData.resizable then control = new("EditControl"):EditControl({"TOPLEFT",lastSection,"TOPLEFT"}, {8, 0, 344, 118}, "", nil, "^%C\t\n", nil, function(buf, placeholder) if placeholder then @@ -1015,6 +1024,9 @@ function ConfigTabClass:UpdateControls() elseif control._className == "CheckBoxControl" then control.state = self.configSets[self.activeConfigSetId].input[var] elseif control._className == "DropDownControl" then + if control.refreshList then + control.refreshList() + end control:SelByValue(self.configSets[self.activeConfigSetId].input[var] or self:GetDefaultState(var), "val") end end @@ -1041,6 +1053,11 @@ function ConfigTabClass:Draw(viewPort, inputEvents) end end + for _, control in pairs(self.varControls) do + if control.refreshList then + control.refreshList() + end + end self:ProcessControlsInput(inputEvents, viewPort) for _, event in ipairs(inputEvents) do if event.type == "KeyUp" then diff --git a/src/Classes/SkillsTab.lua b/src/Classes/SkillsTab.lua index f1326ddc980..601c48743ec 100644 --- a/src/Classes/SkillsTab.lua +++ b/src/Classes/SkillsTab.lua @@ -85,6 +85,7 @@ function SkillsTabClass:SkillsTab(build) self:Control() self.build = build + self.nextMinionSourceId = 1 self.socketGroupList = { } @@ -460,6 +461,8 @@ function SkillsTabClass:LoadSkill(node, skillSetId) for _, child in ipairs(node) do local gemInstance = { } + gemInstance.minionSourceId = tonumber(child.attrib.minionSourceId) + self.nextMinionSourceId = m_max(self.nextMinionSourceId, (gemInstance.minionSourceId or 0) + 1) gemInstance.nameSpec = sanitiseText(child.attrib.nameSpec or "") if child.attrib.gemId then local gemData @@ -521,6 +524,7 @@ function SkillsTabClass:LoadSkill(node, skillSetId) end function SkillsTabClass:Load(xml, fileName) + self.nextMinionSourceId = tonumber(xml.attrib.nextMinionSourceId) or 1 self.activeSkillSetId = 0 self.skillSets = { } self.skillSetOrderList = { } @@ -572,6 +576,7 @@ end function SkillsTabClass:Save(xml) xml.attrib = { + nextMinionSourceId = tostring(self.nextMinionSourceId), activeSkillSet = tostring(self.activeSkillSetId), defaultGemLevel = self.defaultGemLevel, defaultGemQuality = tostring(self.defaultGemQuality), @@ -599,6 +604,7 @@ function SkillsTabClass:Save(xml) } } for _, gemInstance in ipairs(socketGroup.gemList) do t_insert(node, { elem = "Gem", attrib = { + minionSourceId = gemInstance.minionSourceId and tostring(gemInstance.minionSourceId), nameSpec = gemInstance.nameSpec, skillId = gemInstance.skillId, gemId = gemInstance.gemData and gemInstance.gemData.gameId, @@ -1156,6 +1162,15 @@ function SkillsTabClass:ProcessGemLevel(gemData, imbued) end end +-- Allocate once and preserve through reordering, undo and build saves. +function SkillsTabClass:GetMinionSourceId(gemInstance) + if not gemInstance.minionSourceId then + gemInstance.minionSourceId = self.nextMinionSourceId + self.nextMinionSourceId = self.nextMinionSourceId + 1 + end + return gemInstance.minionSourceId +end + -- Processes the given socket group, filling in information that will be used for display or calculations ---@param socketGroup table function SkillsTabClass:ProcessSocketGroup(socketGroup) @@ -1209,6 +1224,9 @@ function SkillsTabClass:ProcessSocketGroup(socketGroup) if gemInstance.gemData or gemInstance.grantedEffect then gemInstance.new = nil local grantedEffect = gemInstance.grantedEffect or gemInstance.gemData.grantedEffect + if grantedEffect.skillTypes and grantedEffect.skillTypes[SkillType.Minion] then + self:GetMinionSourceId(gemInstance) + end if grantedEffect.color == 1 then gemInstance.color = colorCodes.STRENGTH elseif grantedEffect.color == 2 then diff --git a/src/Data/Skills/other.lua b/src/Data/Skills/other.lua index f164918f814..b73f43bc0c7 100644 --- a/src/Data/Skills/other.lua +++ b/src/Data/Skills/other.lua @@ -1266,6 +1266,7 @@ skills["DeathWish"] = { statDescriptionScope = "skill_stat_descriptions", castTime = 0.2, fromItem = true, + defaultPart = 2, parts = { { name = "Channelling", @@ -1279,13 +1280,6 @@ skills["DeathWish"] = { stages = true, }, }, - preDamageFunc = function(activeSkill, output) - if activeSkill.skillPart == 2 then - local skillData = activeSkill.skillData - skillData.FireBonusMin = output.Life * skillData.selfFireExplosionLifeMultiplier - skillData.FireBonusMax = output.Life * skillData.selfFireExplosionLifeMultiplier - end - end, statMap = { ["spell_minimum_base_fire_damage"] = { skill("FireMin", nil, { type = "SkillPart", skillPart = 2 }), diff --git a/src/Export/Skills/other.txt b/src/Export/Skills/other.txt index eea4450a7aa..a93ef34d65f 100644 --- a/src/Export/Skills/other.txt +++ b/src/Export/Skills/other.txt @@ -401,6 +401,7 @@ return function(skills, mod, flag, skill) #skill DeathWish #flags spell area fromItem = true, + defaultPart = 2, parts = { { name = "Channelling", @@ -414,13 +415,6 @@ return function(skills, mod, flag, skill) stages = true, }, }, - preDamageFunc = function(activeSkill, output) - if activeSkill.skillPart == 2 then - local skillData = activeSkill.skillData - skillData.FireBonusMin = output.Life * skillData.selfFireExplosionLifeMultiplier - skillData.FireBonusMax = output.Life * skillData.selfFireExplosionLifeMultiplier - end - end, statMap = { ["spell_minimum_base_fire_damage"] = { skill("FireMin", nil, { type = "SkillPart", skillPart = 2 }), diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index de16231644e..8f5bb455326 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -248,10 +248,10 @@ function calcs.buildActiveSkillModList(env, activeSkill) local activeGemParts = activeGrantedEffect.parts if activeGemParts and #activeGemParts > 1 then if env.mode == "CALCS" and activeSkill == env.player.mainSkill then - activeEffect.srcInstance.skillPartCalcs = m_min(#activeGemParts, activeEffect.srcInstance.skillPartCalcs or 1) + activeEffect.srcInstance.skillPartCalcs = m_min(#activeGemParts, activeEffect.srcInstance.skillPartCalcs or activeGrantedEffect.defaultPart or 1) activeSkill.skillPart = activeEffect.srcInstance.skillPartCalcs else - activeEffect.srcInstance.skillPart = m_min(#activeGemParts, activeEffect.srcInstance.skillPart or 1) + activeEffect.srcInstance.skillPart = m_min(#activeGemParts, activeEffect.srcInstance.skillPart or activeGrantedEffect.defaultPart or 1) activeSkill.skillPart = activeEffect.srcInstance.skillPart end local part = activeGemParts[activeSkill.skillPart] @@ -932,3 +932,22 @@ function calcs.createMinionSkills(env, activeSkill) end minion.mainSkill = minion.activeSkillList[skillIndex] end + +-- Keep duplicate summoning gems distinct, even when they summon the same minion. +function calcs.minionSourceKey(activeSkill, skillsTab) + if not activeSkill.minion or activeSkill.minion.hostile or activeSkill.skillFlags.disable or activeSkill.skillTypes[SkillType.MinionsAreUndamagable] then + return + end + for groupIndex, group in ipairs(skillsTab.socketGroupList) do + if group == activeSkill.socketGroup then + for gemIndex, gem in ipairs(group.gemList) do + if gem == activeSkill.activeEffect.srcInstance then + local effectId = activeSkill.activeEffect.grantedEffect.id + local key = "minion:"..skillsTab:GetMinionSourceId(gem)..":"..effectId + local legacyKey = groupIndex..":"..gemIndex..":"..effectId + return key, legacyKey + end + end + end + end +end diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 8458c4e468f..43d9e5dbbad 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -1913,8 +1913,8 @@ function calcs.offence(env, actor, activeSkill) end -- Handle corpse and enemy explosions - local monsterLife = skillData.corpseLife or (env.enemyLevel and data.monsterLifeTable[env.enemyLevel] or 100) - if skillData.explodeCorpse and (skillData.corpseLife or env.enemyLevel) then + local monsterLife = output.DeathWishMinionLife or skillData.corpseLife or (env.enemyLevel and data.monsterLifeTable[env.enemyLevel] or 100) + if skillData.explodeCorpse and (output.DeathWishMinionLife or skillData.corpseLife or env.enemyLevel) then local damageType = skillData.corpseExplosionDamageType or "Fire" skillData[damageType.."BonusMin"] = monsterLife * ( skillData.corpseExplosionLifeMultiplier or skillData.selfFireExplosionLifeMultiplier ) skillData[damageType.."BonusMax"] = monsterLife * ( skillData.corpseExplosionLifeMultiplier or skillData.selfFireExplosionLifeMultiplier ) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index c7f75eda6c4..d436951b5ae 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -3664,6 +3664,33 @@ function calcs.perform(env, skipEHP) enemyDB:NewMod("DamageTaken", "INC", m_floor(enemyDB:Sum("INC", nil, "DamageTakenConsecratedGround") * effect), "Consecrated Ground") end + local calculatedMinionLife = { } + local function getMinionLife(activeSkill) + local minion = activeSkill.minion + if not calculatedMinionLife[minion] then + if minion ~= env.minion then + initMinionModDB(env, activeSkill) + addMinionModifiers(activeSkill.skillModList, activeSkill.skillCfg, minion) + for _, modList in pairs(buffs) do + addMinionModifiers(modList, activeSkill.skillCfg, minion) + end + for _, modList in pairs(minionBuffs) do + minion.modDB:AddList(modList) + end + for _, name in ipairs(minion.modDB:List(nil, "Keystone")) do + if env.spec.tree.keystoneMap[name] then + minion.modDB:AddList(env.spec.tree.keystoneMap[name].modList) + end + end + doActorAttribsConditions(env, minion) + else + doActorLifeMana(minion) + end + calculatedMinionLife[minion] = minion.output.Life + end + return calculatedMinionLife[minion] + end + -- Full DPS and builds without a supported redirect do not need ally Life. local needsAllyLife = not skipEHP and modDB:Sum("BASE", nil, unpack(allyLifeRedirects)) ~= 0 env.player.allyLifeList = { } @@ -3707,25 +3734,7 @@ function calcs.perform(env, skipEHP) and modDB:Sum("BASE", nil, pool.redirect) ~= 0 and not modDB:Override(nil, pool.life) if canAdd then if not minionLife then - if minion ~= env.minion then - initMinionModDB(env, activeSkill) - addMinionModifiers(activeSkill.skillModList, activeSkill.skillCfg, minion) - for _, modList in pairs(buffs) do - addMinionModifiers(modList, activeSkill.skillCfg, minion) - end - for _, modList in pairs(minionBuffs) do - minion.modDB:AddList(modList) - end - for _, name in ipairs(minion.modDB:List(nil, "Keystone")) do - if env.spec.tree.keystoneMap[name] then - minion.modDB:AddList(env.spec.tree.keystoneMap[name].modList) - end - end - doActorAttribsConditions(env, minion) - else - doActorLifeMana(minion) - end - minionLife = minion.output.Life + minionLife = getMinionLife(activeSkill) end -- Void Spawn redirects scale from their summon limit, so their Life pool uses that same limit. @@ -3788,6 +3797,20 @@ function calcs.perform(env, skipEHP) end end + -- Resolve Death Wish's target after buffs so its Life matches the summoning skill. + local deathWishMinion = env.configInput.deathWishMinion + if env.player.mainSkill.activeEffect.grantedEffect.id == "DeathWish" and deathWishMinion and deathWishMinion ~= "None" then + for _, activeSkill in ipairs(env.player.activeSkillList) do + local key, legacyKey = calcs.minionSourceKey(activeSkill, env.build.skillsTab) + if key == deathWishMinion or legacyKey == deathWishMinion then + -- Migrate selections saved before minion sources had persistent identifiers. + env.configInput.deathWishMinion = key + output.DeathWishMinionLife = getMinionLife(activeSkill) + break + end + end + end + -- Defence/offence calculations calcs.defence(env, env.player) if not skipEHP then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index e6b2284aa57..48f63520338 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -925,6 +925,7 @@ return { { breakdown = "TotemChaosResist" }, { modName = { "TotemChaosResistMax", "TotemChaosResist" }, }, }, }, + { label = "Exploded Minion Life", haveOutput = "DeathWishMinionLife", { format = "{0:output:DeathWishMinionLife}", }, }, { label = "Corpse Level", haveOutput = "CorpseLevel", { format = "{0:output:CorpseLevel}", { breakdown = "CorpseLevel" }, { modName = "CorpseLevel", cfg = "skill" }, diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 8ff3e6f8c79..dac1aeb7027 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -415,6 +415,22 @@ return { modList:NewMod("Condition:DivineSentinelSelfCurseEffect", "FLAG", true, "Config") modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("Condition:DivineSentinelSelfCurseEffect", "FLAG", true, "Config") }) end }, + { label = "Death Wish:", ifSkill = "Death Wish" }, + { var = "deathWishMinion", type = "list", label = "Minion to explode:", ifSkill = "Death Wish", + list = {{val="None",label="Custom corpse life"}}, + tooltip = "Uses the selected minion's calculated maximum life for Minion Explosion, including its gem level, supports and minion life modifiers.\nWithout an available selection, Enemy Corpse Life is used instead.", + listFunc = function(build) + local list = {{val="None",label="Custom corpse life"}} + local env = build.calcsTab and build.calcsTab.mainEnv + for _, activeSkill in ipairs(env and env.player.activeSkillList or { }) do + local key = build.calcsTab.calcs.minionSourceKey(activeSkill, build.skillsTab) + if key then + table.insert(list, { val = key, label = activeSkill.minion.minionData.name.." ("..activeSkill.socketGroup.displayLabel..")" }) + end + end + return list + end, + }, { label = "Doom Blast:", ifSkill = "Doom Blast" }, { var = "doomBlastSource", type = "list", label = "Doom Blast Trigger Source:", ifSkill = "Doom Blast", list = {{val="expiration",label="Curse Expiration"},{val="replacement",label="Curse Replacement"},{val="vixen",label="Vixen's Curse"},{val="hexblast",label="Hexblast Replacement"}}, defaultIndex = 3}, { var = "curseOverlaps", type = "count", label = "Curse overlaps:", ifSkill = "Doom Blast", ifFlag = "UsesCurseOverlaps", apply = function(val, modList, enemyModList)