From 51f0d77bb1d80a0229d4f1dfb04ed1ff81987581 Mon Sep 17 00:00:00 2001 From: Alexander Karrer Date: Wed, 28 Oct 2026 20:29:06 +0100 Subject: [PATCH 1/4] Improve configuration maximum defaults and Focus uptime --- src/Classes/CalcsTab.lua | 1 + src/Classes/ConfigTab.lua | 44 +++++++++++++++++++++++++++++++++++ src/Classes/ModStore.lua | 16 +++++++++++++ src/Modules/CalcPerform.lua | 25 ++++++++++++++++++-- src/Modules/ConfigOptions.lua | 25 ++++++++++++-------- 5 files changed, 99 insertions(+), 12 deletions(-) diff --git a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua index 7d79e865d98..184adcef9b0 100644 --- a/src/Classes/CalcsTab.lua +++ b/src/Classes/CalcsTab.lua @@ -460,6 +460,7 @@ function CalcsTabClass:BuildOutput() self.mainOutput = self.mainEnv.player.output self.calcsEnv = self.calcs.buildOutput(self.build, "CALCS") self.calcsOutput = self.calcsEnv.player.output + self.build.configTab:UpdateMaximumPlaceholders(self.mainEnv) if self.displayData then self.controls.breakdown:SetBreakdownData() diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index 3d1f007cd63..55c5d2896af 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -1005,6 +1005,50 @@ function ConfigTabClass:Save(xml) end end +-- These hints describe calculated defaults only; saving/applying them as config +-- placeholders would turn them into overrides and prevent maxima from updating. +function ConfigTabClass:UpdateMaximumPlaceholders(env) + local output = env.player.output + local skill = env.player.mainSkill + local skillModList, cfg = skill.skillModList, skill.skillCfg + local values = { + overrideCrabBarriers = output.CrabBarriersMax, + BrandsAttachedToEnemy = output.BrandsAttachedLimit, + overrideCruelty = 40, + overrideGhostShrouds = 3, + overrideFortification = output.MaximumFortification, + multiplierRage = output.MaximumRage, + multiplierGaleForce = output.MaximumGaleForce, + TotemsSummoned = output.ActiveTotemLimit, + multiplierSummonedMinion = output.SummonedMinionsMax, + multiplierPermanentMinion = output.PermanentMinionsMax, + multiplierImpalesOnEnemy = output.ImpaleStacksMax or skillModList:Sum("BASE", cfg, "ImpaleStacksMax") * (1 + skillModList:Sum("BASE", cfg, "ImpaleAdditionalDurationChance") / 100), + multiplierBleedsOnEnemy = output.BleedStacksMax or skillModList:Override(cfg, "BleedStacksMax") or skillModList:Sum("BASE", cfg, "BleedStacksMax"), + overrideBuffBlinded = calcLib.mod(env.enemy.modDB, nil, "BlindEffect", "BuffEffectOnSelf") * 100, + } + for _, charge in ipairs({ "Power", "Frenzy", "Endurance", "Siphoning", "Challenger", "Blitz", "Inspiration", "Blood" }) do + values["override"..charge.."Charges"] = output[charge.."ChargesMax"] + end + for _, charge in ipairs({ "Power", "Frenzy", "Endurance" }) do + values["minionsOverride"..charge.."Charges"] = env.minion and env.minion.output[charge.."ChargesMax"] + end + for _, activeSkill in ipairs(env.player.activeSkillList) do + if activeSkill.activeEffect.grantedEffect.name == "Rage Vortex" then + local maxRage = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "MaximumRage") + values.sacrificedRageCount = m_floor(maxRage * (activeSkill.skillData.MaxRageVortexSacrificePercentage or 0) / 100) + end + end + for _, varData in ipairs(varList) do + if varData.label and varData.label:find("(if not maximum)", 1, true) then + local control = self.varControls[varData.var] + if control then + local value = values[varData.var] + control:SetPlaceholder(value ~= nil and string.format("%g", value) or "", false) + end + end + end +end + function ConfigTabClass:UpdateControls() for var, control in pairs(self.varControls) do if control._className == "EditControl" or control._className == "ResizableEditControl" then diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index 0dd30e41d66..706add4552d 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -362,6 +362,7 @@ end ---@return any function ModStoreClass:EvalMod(mod, cfg, globalLimits) local value = mod.value + local focusUptime local GetStat = self.GetStat local GetMultiplier = self.GetMultiplier local GetCondition = self.GetCondition @@ -631,6 +632,12 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) elseif tag.type == "Limit" then value = m_min(value, tag.limit or self:GetMultiplier(tag.limitVar, cfg)) elseif tag.type == "Condition" then + if tag.var == "Focused" and not tag.neg + and (type(value) == "number" or (type(value) == "table" and value.mod and type(value.mod.value) == "number")) + and mod.name ~= "FocusCooldownRecovery" and mod.name ~= "CooldownRecovery" + and GetCondition(self, "AverageFocus", cfg) then + focusUptime = GetMultiplier(self, "FocusUptime", cfg) + end local match = false local allOneH = ((self.actor.weaponData1 and self.actor.weaponData1.countsAsAll1H) and self.actor.weaponData1) or ((self.actor.weaponData2 and self.actor.weaponData2.countsAsAll1H) and self.actor.weaponData2) if tag.varList then @@ -956,6 +963,15 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) end end + if focusUptime then + if type(value) == "number" then + value = value * focusUptime + elseif type(value) == "table" and value.mod and type(value.mod.value) == "number" then + value = copyTable(value) + value.mod.value = value.mod.value * focusUptime + end + end + -- Apply global limits for _, tag in ipairs(mod) do if globalLimits and tag.globalLimit and tag.globalLimitKey then diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index c7f75eda6c4..833c19e4cf9 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -643,6 +643,11 @@ local function doActorMisc(env, actor) -- Add misc buffs/debuffs if env.mode_combat then + if modDB:Flag(nil, "Condition:CanGainGaleForce") then + output.MaximumGaleForce = m_max(modDB:Sum("BASE", nil, "MaximumGaleForce"), 0) + output.GaleForce = m_max(0, m_min(modDB:Override(nil, "GaleForce") or output.MaximumGaleForce, output.MaximumGaleForce)) + modDB.multipliers["GaleForce"] = output.GaleForce + end if env.player.mainSkill.baseSkillModList:Flag(nil, "Cruelty") then modDB.multipliers["Cruelty"] = modDB:Override(nil, "Cruelty") or 40 end @@ -911,14 +916,18 @@ local function doActorMisc(env, actor) condList["Leeching"] = true condList["LeechingEnergyShield"] = true end - if modDB:Flag(nil, "Condition:CanGainRage") or modDB:Sum("BASE", nil, "RageRegen") > 0 then + if not modDB:Flag(nil, "Condition:CanGainRage") and modDB:Sum("BASE", nil, "RageRegen") > 0 then + modDB:NewMod("Condition:CanGainRage", "FLAG", true, "Base") + end + if modDB:Flag(nil, "Condition:CanGainRage") then local maxStacks = m_floor(modDB:Sum("BASE", skillCfg, "MaximumRage") * modDB:More(skillCfg, "MaximumRage")) local minStacks = m_min(modDB:Sum("BASE", nil, "MinimumRage"), maxStacks) - local rageConfig = modDB:Sum("BASE", nil, "Multiplier:RageStack") + local rageConfig = modDB:Override(nil, "RageStacks") or maxStacks local stacks = m_max(m_min(rageConfig, maxStacks), (minStacks > 0 and minStacks) or 0) output.RageEffect = m_floor(stacks * calcLib.mod(modDB, nil, "RageEffect")) modDB:NewMod("Multiplier:RageEffect", "BASE", output.RageEffect, "Base") output.Rage = stacks + modDB.multipliers["RageStack"] = stacks output.MaximumRage = maxStacks modDB:NewMod("Multiplier:Rage", "BASE", output.Rage, "Base") if modDB:Flag(nil, "Condition:RageSpellDamage") then @@ -1287,6 +1296,13 @@ function calcs.perform(env, skipEHP) local modDB = env.modDB local enemyDB = env.enemyDB + if modDB:Flag(nil, "Condition:AverageFocus") then + local focus = env.data.skills.Focus + local duration = focus.constantStats[1][2] / 1000 + local recovery = calcLib.mod(modDB, nil, "CooldownRecovery", "FocusCooldownRecovery") + modDB.multipliers["FocusUptime"] = recovery > 0 and duration / (duration + focus.levels[1].cooldown / recovery) or 0 + end + -- Merge keystone modifiers env.keystonesAdded = { } modLib.mergeKeystones(env, env.modDB) @@ -1357,6 +1373,7 @@ function calcs.perform(env, skipEHP) for _, activeSkill in ipairs(env.player.activeSkillList) do if activeSkill.skillTypes[SkillType.Brand] then local attachLimit = m_min(activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "BrandsAttachedLimit"), activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "ActiveBrandLimit")) + output.BrandsAttachedLimit = m_max(attachLimit, output.BrandsAttachedLimit or 0) local configured = modDB:Sum("BASE", nil, "Multiplier:ConfigBrandsAttachedToEnemy") local attached = configured > 0 and m_min(configured, attachLimit) or attachLimit activeSkill.skillData.attachedBrandCount = attached @@ -1489,6 +1506,7 @@ function calcs.perform(env, skipEHP) end local summonedMinions = 0 + output.PermanentMinionsMax = 0 for _, counts in pairs(minionCounts) do summonedMinions = summonedMinions + counts.total modDB:NewMod("Multiplier:SummonedMinion", "BASE", counts.total, "Config", { type = "Condition", var = "Combat" }) @@ -1496,10 +1514,13 @@ function calcs.perform(env, skipEHP) modDB:NewMod("Multiplier:NonVaalSummonedMinion", "BASE", counts.nonVaal, "Config", { type = "Condition", var = "Combat" }) end if counts.permanent then + output.PermanentMinionsMax = output.PermanentMinionsMax + counts.permanent modDB:NewMod("Multiplier:PermanentMinion", "BASE", counts.permanent, "Config", { type = "Condition", var = "Combat" }) end end + output.SummonedMinionsMax = summonedMinions + -- Companionship only works while exactly one Minion is summoned. local summonedMinionOverride = env.configInput.multiplierSummonedMinion summonedMinionOverride = summonedMinionOverride ~= 0 and summonedMinionOverride or nil diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 8ff3e6f8c79..3195c91d2e3 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -933,8 +933,8 @@ Huge sets the radius to 11. { var = "overrideBlitzCharges", type = "count", label = "# of Blitz Charges (if not maximum):", ifOption = "useBlitzCharges", apply = function(val, modList, enemyModList) modList:NewMod("BlitzCharges", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierGaleForce", type = "count", label = "# of Gale Force:", ifFlag = "Condition:CanGainGaleForce", tooltip = "Base maximum Gale Force is 10.", apply = function(val, modList, enemyModList) - modList:NewMod("Multiplier:GaleForce", "BASE", val, "Config", { type = "IgnoreCond" }, { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanGainGaleForce" }) + { var = "multiplierGaleForce", type = "countAllowZero", label = "# of Gale Force (if not maximum):", ifFlag = "Condition:CanGainGaleForce", tooltip = "Base maximum Gale Force is 10.", apply = function(val, modList, enemyModList) + modList:NewMod("GaleForce", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) end }, { var = "overrideInspirationCharges", type = "countAllowZero", label = "# of Inspiration Charges (if not maximum):", ifMult = "InspirationCharge", apply = function(val, modList, enemyModList) modList:NewMod("InspirationCharges", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) @@ -976,18 +976,18 @@ Huge sets the radius to 11. { var = "minionsUsePowerCharges", type = "check", label = "Do your Minions use Power Charges?", ifFlag = "haveMinion", apply = function(val, modList, enemyModList) modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("UsePowerCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) }, "Config") end }, - { var = "minionsUseFrenzyCharges", type = "check", label = "Do your Minions use Frenzy Charges?", ifFlag = "haveMinion", apply = function(val, modList, enemyModList) - modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("UseFrenzyCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) }, "Config") - end }, - { var = "minionsUseEnduranceCharges", type = "check", label = "Do your Minions use Endur. Charges?", ifFlag = "haveMinion", apply = function(val, modList, enemyModList) - modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("UseEnduranceCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) }, "Config") - end }, { var = "minionsOverridePowerCharges", type = "count", label = "# of Power Charges (if not maximum):", ifFlag = "haveMinion", ifOption = "minionsUsePowerCharges", apply = function(val, modList, enemyModList) modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("PowerCharges", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) }, "Config") end }, + { var = "minionsUseFrenzyCharges", type = "check", label = "Do your Minions use Frenzy Charges?", ifFlag = "haveMinion", apply = function(val, modList, enemyModList) + modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("UseFrenzyCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) }, "Config") + end }, { var = "minionsOverrideFrenzyCharges", type = "count", label = "# of Frenzy Charges (if not maximum):", ifFlag = "haveMinion", ifOption = "minionsUseFrenzyCharges", apply = function(val, modList, enemyModList) modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("FrenzyCharges", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) }, "Config") end }, + { var = "minionsUseEnduranceCharges", type = "check", label = "Do your Minions use Endur. Charges?", ifFlag = "haveMinion", apply = function(val, modList, enemyModList) + modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("UseEnduranceCharges", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) }, "Config") + end }, { var = "minionsOverrideEnduranceCharges", type = "count", label = "# of Endurance Charges (if not maximum):", ifFlag = "haveMinion", ifOption = "minionsUseEnduranceCharges", apply = function(val, modList, enemyModList) modList:NewMod("MinionModifier", "LIST", { mod = modLib.createMod("EnduranceCharges", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) }, "Config") end }, @@ -1003,6 +1003,11 @@ Huge sets the radius to 11. { var = "conditionFocused", type = "check", label = "Are you Focused?", ifCond = "Focused", apply = function(val, modList, enemyModList) modList:NewMod("Condition:Focused", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, + { var = "focusMode", type = "list", label = "Focus mode:", ifOption = "conditionFocused", tooltip = "Maximum: applies the full effect of Focus.\nAverage uptime: scales numeric Focus modifiers by duration divided by duration plus cooldown, including global and Focus cooldown recovery.\nOn/off effects such as immunity remain active in both modes.", list = {{val="MAX",label="Maximum"},{val="AVERAGE",label="Average uptime"}}, apply = function(val, modList, enemyModList) + if val == "AVERAGE" then + modList:NewMod("Condition:AverageFocus", "FLAG", true, "Config", { type = "Condition", var = "Focused" }) + end + end }, { var = "buffLifetap", type = "check", label = "Do you have Lifetap?", ifCond = "Lifetap", apply = function(val, modList, enemyModList) modList:NewMod("Condition:Lifetap", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("FlaskLifeRecovery", "INC", 20, "Lifetap") @@ -1070,8 +1075,8 @@ Huge sets the radius to 11. { var = "multiplierDefiance", type = "count", label = "Defiance:", ifMult = "Defiance", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:Defiance", "BASE", m_min(val, 10), "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierRage", type = "count", label = "^xFF9922Rage:", ifFlag = "Condition:CanGainRage", tooltip = "Base Maximum ^xFF9922Rage ^7is 30, and inherently grants 1% More Attack Damage per 1 ^xFF9922Rage^7\nYou lose 10 ^xFF9922Rage ^7every second if you have not been Hit or gained ^xFF9922Rage ^7in the last 2 seconds.", apply = function(val, modList, enemyModList) - modList:NewMod("Multiplier:RageStack", "BASE", val, "Config", { type = "IgnoreCond" }, { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanGainRage" }) + { var = "multiplierRage", type = "countAllowZero", label = "^xFF9922Rage ^7(if not maximum):", ifFlag = "Condition:CanGainRage", tooltip = "Base Maximum ^xFF9922Rage ^7is 30, and inherently grants 1% More Attack Damage per 1 ^xFF9922Rage^7\nYou lose 10 ^xFF9922Rage ^7every second if you have not been Hit or gained ^xFF9922Rage ^7in the last 2 seconds.", apply = function(val, modList, enemyModList) + modList:NewMod("RageStacks", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) end }, { var = "buffWildSavagery", type = "check", label = "Do you have Wild Savagery?", ifFlag = "WildSavagery", tooltip = "From Oshabi's Bloodline, grants:\n\t100% increased Physical Damage\n\t10% increased Action Speed\n\tHits ignore Enemy Physical Damage Reduction\n\tCannot be Stunned", apply = function(val, modList, enemyModList) modList:NewMod("Condition:WildSavagery", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) From 3b52a74efe30a0b627962a6bdde48b291ca14f28 Mon Sep 17 00:00:00 2001 From: Alexander Karrer Date: Thu, 29 Oct 2026 01:43:47 +0100 Subject: [PATCH 2/4] Expand configuration defaults and conditional option visibility --- src/Classes/CalcsTab.lua | 2 +- src/Classes/ConfigTab.lua | 51 ++++++++++++++++---- src/Classes/ModStore.lua | 13 +++-- src/Modules/CalcOffence.lua | 15 ++++++ src/Modules/CalcPerform.lua | 30 ++++++++++-- src/Modules/CalcSetup.lua | 6 ++- src/Modules/ConfigOptions.lua | 82 +++++++++++++++++--------------- src/Modules/ConfigVisibility.lua | 2 +- 8 files changed, 142 insertions(+), 59 deletions(-) diff --git a/src/Classes/CalcsTab.lua b/src/Classes/CalcsTab.lua index 184adcef9b0..9b3826c6241 100644 --- a/src/Classes/CalcsTab.lua +++ b/src/Classes/CalcsTab.lua @@ -460,7 +460,7 @@ function CalcsTabClass:BuildOutput() self.mainOutput = self.mainEnv.player.output self.calcsEnv = self.calcs.buildOutput(self.build, "CALCS") self.calcsOutput = self.calcsEnv.player.output - self.build.configTab:UpdateMaximumPlaceholders(self.mainEnv) + self.build.configTab:UpdateCalculatedPlaceholders(self.mainEnv) if self.displayData then self.controls.breakdown:SetBreakdownData() diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index 55c5d2896af..c37fb86613b 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -760,8 +760,10 @@ function ConfigTabClass:ConfigTab(build) local valueMapped if varData.type == "check" then valueMapped = not cur + elseif type(value) == "table" then + valueMapped = value.val else - valueMapped = type(value) == "table" and value.val or value + valueMapped = value end if (valueMapped ~= cur) then local buildFlag = self.build.buildFlag @@ -1006,12 +1008,24 @@ function ConfigTabClass:Save(xml) end -- These hints describe calculated defaults only; saving/applying them as config --- placeholders would turn them into overrides and prevent maxima from updating. -function ConfigTabClass:UpdateMaximumPlaceholders(env) +-- placeholders would turn them into overrides and prevent defaults from updating. +function ConfigTabClass:UpdateCalculatedPlaceholders(env) local output = env.player.output + local modDB = env.player.modDB local skill = env.player.mainSkill local skillModList, cfg = skill.skillModList, skill.skillCfg local values = { + manabondMissingUnreservedManaPercentage = 100, + perforateSpikeOverlap = 1, + ShrapnelBallistaProjectileOverlap = 1, + stormRainBeamOverlap = 1, + stormRainActiveArrows = 1, + toxicRainPodOverlap = 1, + raiseSpectreBladeVortexBladeCount = 1, + curseOverlaps = 1, + detonateDeadCorpseLife = env.data.monsterLifeTable[env.enemyLevel], + multiplierPvpDamage = 100, + enemyMultiplierPvpDamage = 100, overrideCrabBarriers = output.CrabBarriersMax, BrandsAttachedToEnemy = output.BrandsAttachedLimit, overrideCruelty = 40, @@ -1032,18 +1046,33 @@ function ConfigTabClass:UpdateMaximumPlaceholders(env) for _, charge in ipairs({ "Power", "Frenzy", "Endurance" }) do values["minionsOverride"..charge.."Charges"] = env.minion and env.minion.output[charge.."ChargesMax"] end + for _, stat in ipairs({ "TotalMinionLife", "TotalSpectreLife", "TotalTotemLife", "TotalRadianceSentinelLife", "TotalVoidSpawnLife", "TotalStoneGolemLife", "TotalVaalRejuvenationTotemLife" }) do + local source = modDB:Flag(nil, "MinionLifeShares"..stat) and "TotalMinionLife" or stat + values[stat] = env.configDefaults[source] or modDB:Sum("BASE", nil, source) + end for _, activeSkill in ipairs(env.player.activeSkillList) do - if activeSkill.activeEffect.grantedEffect.name == "Rage Vortex" then + local name = activeSkill.activeEffect.grantedEffect.name + if name == "Tornado Shot" then + values.tornadoShotSecondaryHitChance = m_min(20 * activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "tornadoShotSecondaryProjectiles"), 100) + elseif name:match("^Shrapnel Ballista") and activeSkill.skillTypes[SkillType.Rain] then + local mods, skillCfg = activeSkill.skillModList, activeSkill.skillCfg + if mods:Flag(skillCfg, "NoAdditionalProjectiles", "SingleProjectile") then + values.ShrapnelBallistaProjectileOverlap = 1 + else + local projectiles = m_floor(mods:Sum("BASE", skillCfg, "ProjectileCount") * mods:More(skillCfg, "ProjectileCount")) + values.ShrapnelBallistaProjectileOverlap = m_max(m_min(projectiles, mods:Override(skillCfg, "ProjectileCountMaximum") or math.huge), mods:Sum("BASE", skillCfg, "ProjectileCountMinimum")) + end + elseif name == "Rage Vortex" then local maxRage = activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "MaximumRage") values.sacrificedRageCount = m_floor(maxRage * (activeSkill.skillData.MaxRageVortexSacrificePercentage or 0) / 100) end end for _, varData in ipairs(varList) do - if varData.label and varData.label:find("(if not maximum)", 1, true) then + if varData.showDefaultPlaceholder or varData.placeholderStat or (varData.label and varData.label:find("(if not maximum)", 1, true)) then local control = self.varControls[varData.var] if control then - local value = values[varData.var] - control:SetPlaceholder(value ~= nil and string.format("%g", value) or "", false) + local value = varData.placeholderStat and output[varData.placeholderStat] or env.configDefaults[varData.var] or values[varData.var] + control:SetPlaceholder(type(value) == "number" and string.format("%g", value) or "", false) end end end @@ -1162,13 +1191,15 @@ end function ConfigTabClass:UpdateLevel() local input = self.configSets[self.activeConfigSetId].input local placeholder = self.configSets[self.activeConfigSetId].placeholder + local defaultLevel = placeholder.enemyLevel and placeholder.enemyLevel > 0 and placeholder.enemyLevel or m_min(83, self.build.characterLevel) if input.enemyLevel and input.enemyLevel > 0 then self.enemyLevel = m_min(data.misc.MaxEnemyLevel, input.enemyLevel) - elseif placeholder.enemyLevel and placeholder.enemyLevel > 0 then - self.enemyLevel = m_min(data.misc.MaxEnemyLevel, placeholder.enemyLevel) else - self.enemyLevel = m_min(data.misc.MaxEnemyLevel, self.build.characterLevel) + self.enemyLevel = m_min(data.misc.MaxEnemyLevel, defaultLevel) end + -- Boss-mode changes and tooltip previews rebuild the mod list without always + -- rebuilding the calculated output. Keep this display-only hint in sync here. + self.varControls.enemyLevel:SetPlaceholder(m_min(data.misc.MaxEnemyLevel, defaultLevel), false) end function ConfigTabClass:BuildModList() diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index 706add4552d..e0fe512e1c5 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -362,7 +362,7 @@ end ---@return any function ModStoreClass:EvalMod(mod, cfg, globalLimits) local value = mod.value - local focusUptime + local conditionEffect local GetStat = self.GetStat local GetMultiplier = self.GetMultiplier local GetCondition = self.GetCondition @@ -636,7 +636,10 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) and (type(value) == "number" or (type(value) == "table" and value.mod and type(value.mod.value) == "number")) and mod.name ~= "FocusCooldownRecovery" and mod.name ~= "CooldownRecovery" and GetCondition(self, "AverageFocus", cfg) then - focusUptime = GetMultiplier(self, "FocusUptime", cfg) + conditionEffect = GetMultiplier(self, "FocusUptime", cfg) + elseif tag.var == "BrandLastQuarter" and not tag.neg and mod.name == "BrandActivationFrequency" + and GetCondition(self, "AverageBrandLastQuarter", cfg) then + conditionEffect = 0.25 end local match = false local allOneH = ((self.actor.weaponData1 and self.actor.weaponData1.countsAsAll1H) and self.actor.weaponData1) or ((self.actor.weaponData2 and self.actor.weaponData2.countsAsAll1H) and self.actor.weaponData2) @@ -963,12 +966,12 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) end end - if focusUptime then + if conditionEffect then if type(value) == "number" then - value = value * focusUptime + value = value * conditionEffect elseif type(value) == "table" and value.mod and type(value.mod.value) == "number" then value = copyTable(value) - value.mod.value = value.mod.value * focusUptime + value.mod.value = value.mod.value * conditionEffect end end diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 8458c4e468f..d4e937a268a 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -1038,6 +1038,9 @@ function calcs.offence(env, actor, activeSkill) if skillModList:Flag(nil, "SupportedByMomentum") then local maxMomentumStacks = skillModList:Sum("BASE", skillCfg, "MomentumStacksMax") local extraMomentumStacks = skillModList:Sum("BASE", skillCfg, "MomentumStacksExtra") + if actor == env.player then + env.configDefaults.MomentumStacks = m_min((maxMomentumStacks + extraMomentumStacks) / 2, maxMomentumStacks) + end if maxMomentumStacks > 0 then if not modDB:HasMod("BASE", nil, "Multiplier:MomentumStacks") then modDB:NewMod("Multiplier:MomentumStacks", "BASE", m_min((maxMomentumStacks + extraMomentumStacks) / 2, maxMomentumStacks), "Config", { type = "Condition", var = "Combat" }) @@ -1266,6 +1269,9 @@ function calcs.offence(env, actor, activeSkill) trapThrowCount = 1 end output.TrapThrowCount = env.modDB:Override(nil, "TrapThrowCount") or trapThrowCount + if actor == env.player then + env.configDefaults.trapsPerThrow = trapThrowCount + end output.TrapThrowingSpeed = m_min(output.TrapThrowingSpeed, data.misc.ServerTickRate) output.TrapThrowingTime = 1 / output.TrapThrowingSpeed skillData.timeOverride = output.TrapThrowingTime / output.TrapThrowCount @@ -1355,6 +1361,9 @@ function calcs.offence(env, actor, activeSkill) mineThrowCount = 1 end output.MineThrowCount = env.modDB:Override(nil, "MineThrowCount") or mineThrowCount + if actor == env.player then + env.configDefaults.minesPerThrow = mineThrowCount + end if output.MineThrowCount >= 1 then -- Throwing Mines takes 10% more time for each *additional* Mine thrown output.MineLayingSpeed = output.MineLayingSpeed / (1 + (output.MineThrowCount - 1) * 0.1) @@ -4461,6 +4470,9 @@ function calcs.offence(env, actor, activeSkill) end -- ratio of bleeds applied : max effective bleeds + if actor == env.player then + env.configDefaults.overrideBleedStackPotential = bleedStacks + end globalOutput.BleedStackPotential = overrideStackPotential or (bleedStacks / maxStacks) if globalBreakdown then @@ -5039,6 +5051,9 @@ function calcs.offence(env, actor, activeSkill) end end -- ratio of ignites applied : max effective ignites + if actor == env.player then + env.configDefaults.overrideIgniteStackPotential = igniteStacks + end globalOutput.IgniteStackPotential = overrideStackPotential or (igniteStacks / maxStacks) if globalBreakdown then globalBreakdown.IgniteStackPotential = { diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 833c19e4cf9..a48b90fe8cb 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -838,6 +838,9 @@ local function doActorMisc(env, actor) end -- if we want the max skill to not be noted as its own breakdown table entry, comment out below modDB:NewMod("ElusiveEffect", "INC", maxSkillInc, "Max Skill Effect") + if actor == env.player then + env.configDefaults.overrideBuffElusive = output.ElusiveEffectMod + end -- Override elusive effect if set. if modDB:Override(nil, "ElusiveEffect") then output.ElusiveEffectMod = m_min(modDB:Override(nil, "ElusiveEffect"), peakElusiveEffect) @@ -1354,6 +1357,11 @@ function calcs.perform(env, skipEHP) modDB:NewMod("Multiplier:BannerValour", "BASE", m_min(stacks, max), "Base") end + local defaultWarcryPower = m_max(modDB:Sum("BASE", nil, "WarcryPower") * (1 + modDB:Sum("INC", nil, "WarcryPower") / 100), modDB:Sum("BASE", nil, "MinimumWarcryPower")) + if modDB:Flag(nil, "CryWolfMinimumPower") and modDB:Sum("BASE", nil, "WarcryPower") < 10 then + defaultWarcryPower = 10 + end + env.configDefaults.multiplierWarcryPower = modDB:Flag(nil, "WarcryInfinitePower") and 999999 or defaultWarcryPower if modDB:Flag(nil, "CryWolfMinimumPower") and modDB:Sum("BASE", nil, "WarcryPower") < 10 then modDB:NewMod("WarcryPower", "OVERRIDE", 10, "Minimum Warcry Power from CryWolf") end @@ -1506,11 +1514,13 @@ function calcs.perform(env, skipEHP) end local summonedMinions = 0 + env.configDefaults.multiplierNonVaalSummonedMinion = 0 output.PermanentMinionsMax = 0 for _, counts in pairs(minionCounts) do summonedMinions = summonedMinions + counts.total modDB:NewMod("Multiplier:SummonedMinion", "BASE", counts.total, "Config", { type = "Condition", var = "Combat" }) if counts.nonVaal then + env.configDefaults.multiplierNonVaalSummonedMinion = env.configDefaults.multiplierNonVaalSummonedMinion + counts.nonVaal modDB:NewMod("Multiplier:NonVaalSummonedMinion", "BASE", counts.nonVaal, "Config", { type = "Condition", var = "Combat" }) end if counts.permanent then @@ -3725,7 +3735,7 @@ function calcs.perform(env, skipEHP) for _, pool in ipairs(pools) do local canAdd = ((pool == spectreLifePool and spectreCount < spectreLimit) or (pool ~= spectreLifePool and not calculatedLifePool[pool.life])) - and modDB:Sum("BASE", nil, pool.redirect) ~= 0 and not modDB:Override(nil, pool.life) + and modDB:Sum("BASE", nil, pool.redirect) ~= 0 and (not modDB:Override(nil, pool.life) or env.mode == "MAIN") if canAdd then if not minionLife then if minion ~= env.minion then @@ -3756,7 +3766,11 @@ function calcs.perform(env, skipEHP) spectreCount = spectreCount + 1 end local life = minionLife * count - modDB:NewMod(pool.life, "BASE", life, pool.source) + if modDB:Override(nil, pool.life) then + env.configDefaults[pool.life] = (env.configDefaults[pool.life] or modDB:Sum("BASE", nil, pool.life)) + life + else + modDB:NewMod(pool.life, "BASE", life, pool.source) + end env.player.allyLifeList[pool.life] = env.player.allyLifeList[pool.life] or { } local entry = { name = minion.minionData.name, life = life, count = count } t_insert(env.player.allyLifeList[pool.life], entry) @@ -3775,7 +3789,11 @@ function calcs.perform(env, skipEHP) local life = firstSpectre.life * count firstSpectre.entry.count = firstSpectre.entry.count + count firstSpectre.entry.life = firstSpectre.entry.life + life - modDB:NewMod(spectreLifePool.life, "BASE", life, spectreLifePool.source) + if modDB:Override(nil, spectreLifePool.life) then + env.configDefaults[spectreLifePool.life] = env.configDefaults[spectreLifePool.life] + life + else + modDB:NewMod(spectreLifePool.life, "BASE", life, spectreLifePool.source) + end end local normalTotem @@ -3798,6 +3816,12 @@ function calcs.perform(env, skipEHP) local vaalPool = totemLifePoolByStat.TotalVaalRejuvenationTotemLife local totemLifeOverride = modDB:Override(nil, "TotalTotemLife") local totemRedirect = modDB:Sum("BASE", nil, totemPool.redirect) + if nearestTotem then + env.configDefaults.TotalTotemLife = nearestTotem.life + modDB:Sum("BASE", nil, "TotalTotemLife") + end + if vaalRejuvenationTotem then + env.configDefaults.TotalVaalRejuvenationTotemLife = vaalRejuvenationTotem.life + modDB:Sum("BASE", nil, "TotalVaalRejuvenationTotemLife") + end local nearestIsVaal = nearestTotem and nearestTotem == vaalRejuvenationTotem and not totemLifeOverride if nearestTotem and not nearestIsVaal and totemRedirect ~= 0 and not totemLifeOverride then modDB:NewMod("TotalTotemLife", "BASE", nearestTotem.life, totemPool.source) diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 70301168360..86e8e10ea95 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -495,6 +495,7 @@ function calcs.initEnv(build, mode, override, specEnv) env.data = build.data env.configInput = build.configTab.input env.configPlaceholder = build.configTab.placeholder + env.configDefaults = { } env.calcsInput = build.calcsTab.input env.mode = mode env.buildBreakdown = mode == "MAIN" or mode == "CALCS" @@ -508,7 +509,7 @@ function calcs.initEnv(build, mode, override, specEnv) env.enemyDB = enemyDB env.itemModDB = new("ModDB"):ModDB() - env.enemyLevel = build.configTab.enemyLevel or m_min(data.misc.MaxEnemyLevel, build.characterLevel) + env.enemyLevel = build.configTab.enemyLevel or m_min(83, build.characterLevel) -- Create player/enemy actors env.player = { @@ -1361,6 +1362,9 @@ function calcs.initEnv(build, mode, override, specEnv) end end -- Override empty socket calculation if set in config + for _, colour in ipairs({ "Red", "Green", "Blue", "White" }) do + env.configDefaults["overrideEmpty"..colour.."Sockets"] = env.itemModDB.multipliers["Empty"..colour.."SocketsInAnySlot"] or 0 + end env.itemModDB.multipliers.EmptyRedSocketsInAnySlot = (env.configInput.overrideEmptyRedSockets or env.itemModDB.multipliers.EmptyRedSocketsInAnySlot) env.itemModDB.multipliers.EmptyGreenSocketsInAnySlot = (env.configInput.overrideEmptyGreenSockets or env.itemModDB.multipliers.EmptyGreenSocketsInAnySlot) env.itemModDB.multipliers.EmptyBlueSocketsInAnySlot = (env.configInput.overrideEmptyBlueSockets or env.itemModDB.multipliers.EmptyBlueSocketsInAnySlot) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 3195c91d2e3..843825f1e34 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -152,7 +152,7 @@ return { { label = "Soul of Ryslatha", val = "Ryslatha" }, { label = "Soul of Shakari", val = "Shakari" }, } }, - { var = "detonateDeadCorpseLife", type = "count", label = "Enemy Corpse ^xE05030Life:", ifSkillData = "explodeCorpse", tooltip = "Sets the maximum ^xE05030life ^7of the target corpse for Detonate Dead and similar skills.\nFor reference, a level 70 monster has "..data.monsterLifeTable[70].." base ^xE05030life^7, and a level 80 monster has "..data.monsterLifeTable[80]..".", apply = function(val, modList, enemyModList) + { var = "detonateDeadCorpseLife", type = "count", showDefaultPlaceholder = true, label = "Enemy Corpse ^xE05030Life:", ifSkillData = "explodeCorpse", tooltip = "Sets the maximum ^xE05030life ^7of the target corpse for Detonate Dead and similar skills.\nFor reference, a level 70 monster has "..data.monsterLifeTable[70].." base ^xE05030life^7, and a level 80 monster has "..data.monsterLifeTable[80]..".", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "corpseLife", value = val }, "Config") end }, { var = "conditionStationary", type = "count", label = "Time spent stationary", ifCond = "Stationary", @@ -247,10 +247,10 @@ return { end }, { var = "ignoreItemDisablers", type = "check", label = "Don't disable items", ifTagType = "DisablesItem", tooltip = "Ignore the effects of things which disable items, like Bringer of Rain" }, { var = "ignoreJewelLimits", type = "check", label = "Ignore Jewel Limits", tooltip = "Ignore the limits on jewels" }, - { var = "overrideEmptyRedSockets", type = "count", label = "# of Empty ^xE05030Red^7 Sockets", ifMult = "EmptyRedSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^xE05030Red^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyGreenSockets", type = "count", label = "# of Empty ^x70FF70Green^7 Sockets", ifMult = "EmptyGreenSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x70FF70Green^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyBlueSockets", type = "count", label = "# of Empty ^x7070FFBlue^7 Sockets", ifMult = "EmptyBlueSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x7070FFBlue^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, - { var = "overrideEmptyWhiteSockets", type = "count", label = "# of Empty White Sockets", ifMult = "EmptyWhiteSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty White Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyRedSockets", type = "count", showDefaultPlaceholder = true, label = "# of Empty ^xE05030Red^7 Sockets", ifMult = "EmptyRedSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^xE05030Red^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyGreenSockets", type = "count", showDefaultPlaceholder = true, label = "# of Empty ^x70FF70Green^7 Sockets", ifMult = "EmptyGreenSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x70FF70Green^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyBlueSockets", type = "count", showDefaultPlaceholder = true, label = "# of Empty ^x7070FFBlue^7 Sockets", ifMult = "EmptyBlueSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty ^x7070FFBlue^7 Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, + { var = "overrideEmptyWhiteSockets", type = "count", showDefaultPlaceholder = true, label = "# of Empty White Sockets", ifMult = "EmptyWhiteSocketsInAnySlot", tooltip = "This option allows you to override the default calculation for the number of Empty White Sockets.\nThe default calculation assumes enabled gems in skill socket groups fill the item in socket order disregarding gem colour.\nLeave blank for default calculation." }, -- Section: Skill-specific options { section = "Skill Options", col = 2 }, @@ -337,9 +337,15 @@ return { { var = "targetBrandedEnemy", type = "check", label = "Skill is targeting the Branded enemy", ifCond = "TargetingBrandedEnemy", defaultState = true, apply = function(val, modList, enemyModList) modList:NewMod("Condition:TargetingBrandedEnemy", "FLAG", true, "Config") end }, - { var = "BrandsInLastQuarter", type = "check", label = "Last 25% of attached duration?", ifCond = "BrandLastQuarter", apply = function(val, modList, enemyModList) - modList:NewMod("Condition:BrandLastQuarter", "FLAG", true, "Config") - modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") + { var = "BrandsInLastQuarter", type = "list", label = "Sign of Purpose mode:", ifCond = "BrandLastQuarter", tooltip = "Inactive: excludes the activation frequency bonus.\nAverage: averages the bonus over the full attached duration, giving 25% more Activation Frequency for Sign of Purpose. Assumes Brands remain attached for their full duration.\nLast 25%: applies the full bonus during the final quarter of attached duration.", list = {{val=false,label="Inactive"},{val="AVERAGE",label="Average"},{val=true,label="Last 25%"}}, apply = function(val, modList, enemyModList) + if val then + modList:NewMod("Condition:BrandLastQuarter", "FLAG", true, "Config") + if val == "AVERAGE" then + modList:NewMod("Condition:AverageBrandLastQuarter", "FLAG", true, "Config") + else + modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") + end + end end }, { var = "BrandsInLastHalf", type = "check", label = "Last 50% of attached duration?", ifCond = "BrandLastHalf", apply = function(val, modList, enemyModList) modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") @@ -417,7 +423,7 @@ return { 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) + { var = "curseOverlaps", type = "count", showDefaultPlaceholder = true, label = "Curse overlaps:", ifSkill = "Doom Blast", ifFlag = "UsesCurseOverlaps", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:CurseOverlaps", "BASE", val, "Config", { type = "Condition", var = "Effective" }) end }, { label = "Elemental Army:", ifSkill = "Elemental Army" }, @@ -528,7 +534,7 @@ return { modList:NewMod("IntuitiveLinkSourceRate", "BASE", val, "Config") end }, { label = "Manabond:", ifSkill = "Manabond" }, - { var = "manabondMissingUnreservedManaPercentage", type = "count", label = "Missing Unreserved ^x7070FFMana^7 %:", tooltip = "Ignores values outside the 0-100 range, defaults to 100% if not specified. \nA more realistic value would be to match your Arcane Cloak spend %.", ifSkill = "Manabond", apply = function(val, modList, enemyModList) + { var = "manabondMissingUnreservedManaPercentage", type = "count", showDefaultPlaceholder = true, label = "Missing Unreserved ^x7070FFMana^7 %:", tooltip = "Ignores values outside the 0-100 range, defaults to 100% if not specified. \nA more realistic value would be to match your Arcane Cloak spend %.", ifSkill = "Manabond", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "ManabondMissingUnreservedManaPercentage", value = m_max(m_min(val,100), 0) }, "Config", { type = "SkillName", skillName = "Manabond" }) end }, { label = "Communion:", ifSkill = "Communion" }, @@ -548,7 +554,7 @@ return { enemyModList:NewMod("Condition:MistyReflection", "FLAG", true, "Config") end }, { label = "Momentum:", ifSkill = "Momentum" }, - { var = "MomentumStacks", type = "count", label = "# of Momentum (if not average):", ifSkill = "Momentum", apply = function(val, modList, enemyModList) + { var = "MomentumStacks", type = "count", showDefaultPlaceholder = true, label = "# of Momentum (if not average):", ifSkill = "Momentum", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:MomentumStacks", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, { var = "MomentumSwiftnessStacks", type = "count", label = "Swiftness # of Momentum Removed:", ifSkill = "Momentum", apply = function(val, modList, enemyModList) @@ -563,7 +569,7 @@ return { end end }, { label = "Perforate:", ifSkill = "Perforate", includeTransfigured = true }, - { var = "perforateSpikeOverlap", type = "count", label = "# of Overlapping Spikes:", tooltip = "Affects the DPS of Perforate in Blood Stance.\nMaximum is limited by the number of Spikes of Perforate.", ifSkill = "Perforate", includeTransfigured = true, apply = function(val, modList, enemyModList) + { var = "perforateSpikeOverlap", type = "count", showDefaultPlaceholder = true, label = "# of Overlapping Spikes:", tooltip = "Affects the DPS of Perforate in Blood Stance.\nMaximum is limited by the number of Spikes of Perforate.", ifSkill = "Perforate", includeTransfigured = true, apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:PerforateSpikeOverlap", "BASE", val, "Config", { type = "SkillName", skillName = "Perforate", includeTransfigured = true }) end }, { label = "Physical Aegis:", ifSkill = "Physical Aegis" }, @@ -595,7 +601,7 @@ return { { var = "conditionSummonedSpectreInPast8Sec", type = "check", label = "Summoned Spectre in past 8 Seconds?", ifCond = "SummonedSpectreInPast8Sec", ifSkill = "Raise Spectre", includeTransfigured = true, apply = function(val, modList, enemyModList) modList:NewMod("Condition:SummonedSpectreInPast8Sec", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "raiseSpectreBladeVortexBladeCount", type = "count", label = "Blade Vortex blade count:", ifSkill = {"DemonModularBladeVortexSpectre","GhostPirateBladeVortexSpectre"}, tooltip = "Sets the blade count for Blade Vortex skills used by spectres.\nDefault is 1; maximum is 5.", apply = function(val, modList, enemyModList) + { var = "raiseSpectreBladeVortexBladeCount", type = "count", showDefaultPlaceholder = true, label = "Blade Vortex blade count:", ifSkill = {"DemonModularBladeVortexSpectre","GhostPirateBladeVortexSpectre"}, tooltip = "Sets the blade count for Blade Vortex skills used by spectres.\nDefault is 1; maximum is 5.", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "dpsMultiplier", value = val }, "Config", { type = "SkillId", skillId = "DemonModularBladeVortexSpectre" }) modList:NewMod("SkillData", "LIST", { key = "dpsMultiplier", value = val }, "Config", { type = "SkillId", skillId = "GhostPirateBladeVortexSpectre" }) end }, @@ -624,7 +630,7 @@ return { modList:NewMod("Condition:AnimatingLingeringBlades", "FLAG", true, "Config") end }, { label = "Shrapnel Ballista:", ifSkill = "Shrapnel Ballista", includeTransfigured = true }, - { var = "ShrapnelBallistaProjectileOverlap", type = "count", label = "# of Shotgunning Projectiles:", tooltip = "Maximum is limited by the number of Projectiles., default of 1, if Arrow nova then default of maximum projectiles", ifSkill = "Shrapnel Ballista", includeTransfigured = true, apply = function(val, modList, enemyModList) + { var = "ShrapnelBallistaProjectileOverlap", type = "count", showDefaultPlaceholder = true, label = "# of Shotgunning Projectiles:", tooltip = "Maximum is limited by the number of Projectiles., default of 1, if Arrow nova then default of maximum projectiles", ifSkill = "Shrapnel Ballista", includeTransfigured = true, apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "ShrapnelBallistaProjectileOverlap", value = val }, "Config", { type = "SkillName", skillName = "Shrapnel Ballista", includeTransfigured = true }) end }, { label = "Sigil of Power:", ifSkill = "Sigil of Power" }, @@ -667,11 +673,11 @@ return { modList:NewMod("Multiplier:SteelWardCount", "BASE", val, "Config") end }, { label = "Storm Rain:", ifSkill = "Storm Rain" }, - { var = "stormRainBeamOverlap", type = "count", label = "# of Overlapping Beams:", ifSkill = "Storm Rain", apply = function(val, modList, enemyModList) + { var = "stormRainBeamOverlap", type = "count", showDefaultPlaceholder = true, label = "# of Overlapping Beams:", ifSkill = "Storm Rain", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "beamOverlapMultiplier", value = val }, "Config", { type = "SkillName", skillName = "Storm Rain" }) end }, { label = "Storm Rain of the Conduit:", ifSkill = "Storm Rain of the Conduit" }, - { var = "stormRainActiveArrows", type = "count", label = "# of Active Arrows:", ifSkill = "Storm Rain of the Conduit", apply = function(val, modList, enemyModList) + { var = "stormRainActiveArrows", type = "count", showDefaultPlaceholder = true, label = "# of Active Arrows:", ifSkill = "Storm Rain of the Conduit", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "activeArrowMultiplier", value = val }, "Config", { type = "SkillName", skillName = "Storm Rain of the Conduit" }) end }, { label = "Summon Elemental Relic:", ifSkill = "Summon Elemental Relic" }, @@ -704,15 +710,15 @@ return { modList:NewMod("Multiplier:NearbyBleedingEnemies", "BASE", val, "Config" ) end }, { label = "Tornado Shot:", ifSkill = "Tornado Shot" }, - { var = "tornadoShotSecondaryHitChance", type = "count", label = "% chance for second proj to hit:", tooltip = "Override to the percent chance for the secondary projectiles to hit, default of 60% or 80% with helm enchant. (20% per secondary projectile)", ifSkill = "Tornado Shot", apply = function(val, modList, enemyModList) + { var = "tornadoShotSecondaryHitChance", type = "count", showDefaultPlaceholder = true, label = "% chance for second proj to hit:", tooltip = "Override to the percent chance for the secondary projectiles to hit, default of 60% or 80% with helm enchant. (20% per secondary projectile)", ifSkill = "Tornado Shot", apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "tornadoShotSecondaryHitChance", value = val }, "Config", { type = "SkillName", skillName = "Tornado Shot" }) end }, { label = "Toxic Rain:", ifSkill = "Toxic Rain", includeTransfigured = true }, - { var = "toxicRainPodOverlap", type = "count", label = "# of Overlapping Pods:", tooltip = "Maximum is limited by the number of Projectiles.", ifSkill = "Toxic Rain", includeTransfigured = true, apply = function(val, modList, enemyModList) + { var = "toxicRainPodOverlap", type = "count", showDefaultPlaceholder = true, label = "# of Overlapping Pods:", tooltip = "Maximum is limited by the number of Projectiles.", ifSkill = "Toxic Rain", includeTransfigured = true, apply = function(val, modList, enemyModList) modList:NewMod("SkillData", "LIST", { key = "podOverlapMultiplier", value = val }, "Config", { type = "SkillName", skillName = "Toxic Rain", includeTransfigured = true }) end }, { label = "Trauma:", ifFlag = "HasTrauma" }, - { var = "traumaStacks", type = "count", label = "# of Trauma Stacks:", ifFlag = "HasTrauma", apply = function(val, modList, enemyModList) + { var = "traumaStacks", type = "count", label = "# of Trauma Stacks (if not calculated):", ifFlag = "HasTrauma", placeholderStat = "SustainableTrauma", tooltip = "Leave blank to use the automatically calculated sustainable Trauma stacks for damage calculations.\nEnter a positive value to override the calculated stack count.\nThe automatic calculation accounts for attack speed, hit chance, Trauma duration and repeats; it does not check whether you can survive the self-damage.", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:TraumaStacks", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, { label = "Trinity Support:", ifSkill = "Trinity" }, @@ -740,7 +746,7 @@ return { modList:NewMod("Condition:CastOnFrostbolt", "FLAG", true, "Config", { type = "SkillName", skillName = "Vortex of Projection" }) end }, { label = "Warcry Skills:", ifFlag = "UsesWarcryPower" }, - { var = "multiplierWarcryPower", type = "count", label = "Warcry Power:", ifFlag = "UsesWarcryPower", tooltip = "Power determines how strong your Warcry buffs will be, and is based on the total strength of nearby enemies.\nPower is assumed to be 20 if your target is a Boss, but you can override it here if necessary.\n\tEach Normal enemy grants 1 Power\n\tEach Magic enemy grants 2 Power\n\tEach Rare enemy grants 10 Power\n\tEach Unique enemy grants 20 Power", apply = function(val, modList, enemyModList) + { var = "multiplierWarcryPower", type = "count", showDefaultPlaceholder = true, label = "Warcry Power:", ifFlag = "UsesWarcryPower", tooltip = "Power determines how strong your Warcry buffs will be, and is based on the total strength of nearby enemies.\nPower is assumed to be 20 if your target is a Boss, but you can override it here if necessary.\n\tEach Normal enemy grants 1 Power\n\tEach Magic enemy grants 2 Power\n\tEach Rare enemy grants 10 Power\n\tEach Unique enemy grants 20 Power", apply = function(val, modList, enemyModList) modList:NewMod("WarcryPower", "OVERRIDE", val, "Config") end }, { label = "Wave of Conviction:", ifSkill = "Wave of Conviction" }, @@ -802,25 +808,25 @@ Huge sets the radius to 11. { var = "enemyRadius", type = "integer", label = "Enemy radius:", ifSkill = { "Seismic Trap", "Lightning Spire Trap", "Explosive Trap", "Molten Strike", "Ball Lightning" }, includeTransfigured = true, tooltip = "Configure the radius of an enemy hitbox to calculate some area overlapping (shotgunning) effects.", apply = function(val, modList, enemyModList) modList:NewMod("EnemyRadius", "OVERRIDE", m_max(val, 1), "Config") end }, - { var = "TotalMinionLife", type = "integer", label = "Minion Life override:", ifMod = "takenFromMinionBeforeYou", tooltip = "Overrides the automatically calculated Life of the minion supported by Companionship.", apply = function(val, modList, enemyModList) + { var = "TotalMinionLife", type = "integer", showDefaultPlaceholder = true, label = "Minion Life override:", ifMod = "takenFromMinionBeforeYou", tooltip = "Overrides the automatically calculated Life of the minion supported by Companionship.", apply = function(val, modList, enemyModList) modList:NewMod("TotalMinionLife", "OVERRIDE", val, "Config") end }, - { var = "TotalSpectreLife", type = "integer", label = "Total Spectre Life override:", ifMod = "takenFromSpectresBeforeYou", ifSkill = "Raise Spectre", includeTransfigured = true, tooltip = "Overrides the automatically calculated total Life of your Spectres that can be taken before yours (used by Jinxed Juju).", apply = function(val, modList, enemyModList) + { var = "TotalSpectreLife", type = "integer", showDefaultPlaceholder = true, label = "Total Spectre Life override:", ifMod = "takenFromSpectresBeforeYou", ifSkill = "Raise Spectre", includeTransfigured = true, tooltip = "Overrides the automatically calculated total Life of your Spectres that can be taken before yours (used by Jinxed Juju).", apply = function(val, modList, enemyModList) modList:NewMod("TotalSpectreLife", "OVERRIDE", val, "Config") end }, - { var = "TotalTotemLife", type = "integer", label = "Nearest Totem Life override:", ifOption = "conditionHaveTotem", ifMod = "takenFromTotemsBeforeYou", tooltip = "Overrides the automatically calculated Life of your nearest Totem (excluding Vaal Rejuvenation Totem) that can be taken before yours (used by Totem Mastery).", apply = function(val, modList, enemyModList) + { var = "TotalTotemLife", type = "integer", showDefaultPlaceholder = true, label = "Nearest Totem Life override:", ifOption = "conditionHaveTotem", ifMod = "takenFromTotemsBeforeYou", tooltip = "Overrides the automatically calculated Life of your nearest Totem (excluding Vaal Rejuvenation Totem) that can be taken before yours (used by Totem Mastery).", apply = function(val, modList, enemyModList) modList:NewMod("TotalTotemLife", "OVERRIDE", val, "Config") end }, - { var = "TotalRadianceSentinelLife", type = "integer", label = "Sentinel of Radiance Life override:", ifMod = "takenFromRadianceSentinelBeforeYou", tooltip = "Overrides the automatically calculated Life of your Sentinel of Radiance that can be taken before yours.", apply = function(val, modList, enemyModList) + { var = "TotalRadianceSentinelLife", type = "integer", showDefaultPlaceholder = true, label = "Sentinel of Radiance Life override:", ifMod = "takenFromRadianceSentinelBeforeYou", tooltip = "Overrides the automatically calculated Life of your Sentinel of Radiance that can be taken before yours.", apply = function(val, modList, enemyModList) modList:NewMod("TotalRadianceSentinelLife", "OVERRIDE", val, "Config") end }, - { var = "TotalVoidSpawnLife", type = "integer", label = "Total Void Spawn Life override:", ifMod = "takenFromVoidSpawnBeforeYou", tooltip = "Overrides the automatically calculated total Life of your Void Spawns that can be taken before yours.", apply = function(val, modList, enemyModList) + { var = "TotalVoidSpawnLife", type = "integer", showDefaultPlaceholder = true, label = "Total Void Spawn Life override:", ifMod = "takenFromVoidSpawnBeforeYou", tooltip = "Overrides the automatically calculated total Life of your Void Spawns that can be taken before yours.", apply = function(val, modList, enemyModList) modList:NewMod("TotalVoidSpawnLife", "OVERRIDE", val, "Config") end }, - { var = "TotalStoneGolemLife", type = "integer", label = "Stone Golem Life override:", ifSkill = "Summon Stone Golem of Safeguarding", ifMod = "takenFromStoneGolemBeforeYou", tooltip = "Overrides the automatically calculated Life of your Stone Golem of Safeguarding that can be taken before yours.", apply = function(val, modList, enemyModList) + { var = "TotalStoneGolemLife", type = "integer", showDefaultPlaceholder = true, label = "Stone Golem Life override:", ifSkill = "Summon Stone Golem of Safeguarding", ifMod = "takenFromStoneGolemBeforeYou", tooltip = "Overrides the automatically calculated Life of your Stone Golem of Safeguarding that can be taken before yours.", apply = function(val, modList, enemyModList) modList:NewMod("TotalStoneGolemLife", "OVERRIDE", val, "Config") end }, - { var = "TotalVaalRejuvenationTotemLife", type = "integer", label = "Vaal Rejuvenation Totem Life override:", ifSkill = "Vaal Rejuvenation Totem", ifMod = "takenFromVaalRejuvenationTotemsBeforeYou", tooltip = "Overrides the automatically calculated Life of your Vaal Rejuvenation Totem that can be taken before yours.", apply = function(val, modList, enemyModList) + { var = "TotalVaalRejuvenationTotemLife", type = "integer", showDefaultPlaceholder = true, label = "Vaal Rejuvenation Totem Life override:", ifSkill = "Vaal Rejuvenation Totem", ifMod = "takenFromVaalRejuvenationTotemsBeforeYou", tooltip = "Overrides the automatically calculated Life of your Vaal Rejuvenation Totem that can be taken before yours.", apply = function(val, modList, enemyModList) modList:NewMod("TotalVaalRejuvenationTotemLife", "OVERRIDE", val, "Config") end }, { label = "^xAF6025Balance of Terror ^7Curse Disable:", ifCond = { "SelfCastConductivity", "SelfCastDespair", "SelfCastElementalWeakness", "SelfCastEnfeeble", "SelfCastFlammability", "SelfCastFrostbite", "SelfCastPunishment", "SelfCastTemporalChains", "SelfCastVulnerability" } }, @@ -1066,7 +1072,7 @@ Huge sets the radius to 11. modList:NewMod("Condition:Elusive", "FLAG", true, "Config", { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanBeElusive" }) modList:NewMod("Elusive", "FLAG", true, "Config", { type = "Condition", var = "Combat" }, { type = "Condition", var = "CanBeElusive" }) end }, - { var = "overrideBuffElusive", type = "count", label = "Effect of Elusive (if not average):", ifOption = "buffElusive", tooltip = "If you have a guaranteed source of Elusive, the strongest one will apply. \nYou can change this to see various buff values", apply = function(val, modList, enemyModList) + { var = "overrideBuffElusive", type = "count", showDefaultPlaceholder = true, label = "Effect of Elusive (if not average):", ifOption = "buffElusive", tooltip = "If you have a guaranteed source of Elusive, the strongest one will apply. \nYou can change this to see various buff values", apply = function(val, modList, enemyModList) modList:NewMod("ElusiveEffect", "OVERRIDE", val, "Config", {type = "GlobalEffect", effectType = "Buff" }) end }, { var = "buffDivinity", type = "check", label = "Do you have Divinity?", ifCond = "Divinity", tooltip = "This will enable the Divinity buff, which grants:\n\t75% more Elemental Damage\n\t25% less Elemental Damage taken", apply = function(val, modList, enemyModList) @@ -1118,7 +1124,7 @@ Huge sets the radius to 11. { var = "conditionUsingTincture", type = "check", label = "Do you have a Tincture active?", ifCond = "UsingTincture", tooltip = "This is automatically enabled if you have a tincture active,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) modList:NewMod("Condition:UsingTincture", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierManaBurnStacks", type = "count", label = "Mana Burn Stacks:", tooltip = "Mana Burn Applies a 1% of mana degen per stack\nThis also applies Weeping Wounds if the Keystone is Allocated"}, + { var = "multiplierManaBurnStacks", type = "count", label = "Mana Burn Stacks:", ifCondTrue = "UsingTincture", tooltip = "Mana Burn Applies a 1% of mana degen per stack\nThis also applies Weeping Wounds if the Keystone is Allocated"}, { var = "conditionHaveTotem", type = "check", label = "Do you have a Totem summoned?", ifCond = "HaveTotem", tooltip = "You will automatically be considered to have a Totem if your main skill is a Totem,\nbut you can use this option to force it if necessary.", apply = function(val, modList, enemyModList) modList:NewMod("Condition:HaveTotem", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, @@ -1144,7 +1150,7 @@ Huge sets the radius to 11. { var = "multiplierSummonedMinion", type = "count", label = "# of Summoned Minions (if not maximum):", ifMult = "SummonedMinion", tooltip = "Use this to override the count if you do not have all your minions summoned", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:SummonedMinion", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierNonVaalSummonedMinion", type = "count", label = "# of non-vaal skill Summoned Minions:", ifMult = "NonVaalSummonedMinion", tooltip = "Use this to override the count if you do not have all your minions summoned", apply = function(val, modList, enemyModList) + { var = "multiplierNonVaalSummonedMinion", type = "count", showDefaultPlaceholder = true, label = "# of non-vaal skill Summoned Minions:", ifMult = "NonVaalSummonedMinion", tooltip = "Use this to override the count if you do not have all your minions summoned", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:NonVaalSummonedMinion", "OVERRIDE", val, "Config", { type = "Condition", var = "Combat" }) end }, { var = "multiplierPermanentMinion", type = "count", label = "# of Permanent Minions (if not maximum):", ifMult = "PermanentMinion", tooltip = "Use this to override the count if you do not have all your permanent minions summoned", apply = function(val, modList, enemyModList) @@ -1571,7 +1577,7 @@ Huge sets the radius to 11. { var = "conditionSacrificeMinion", type = "check", label = "Sacrifice Minion on Attack", ifCond = "SacrificeMinionOnAttack", ifFlag = "Condition:HaveDamageableMinion", defaultState = true, tooltip = "Each Attack is sacrificing a damage minion to grant you extra projectiles.", apply = function(val, modList, enemyModList) modList:NewMod("Condition:SacrificeMinionOnAttack", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "conditionUsedWarcryRecently", type = "check", label = "Have you used a Warcry Recently?", {ifFlag = "warcry", ifCond = "UsedWarcryRecently"}, implyCondList = {"UsedWarcryInPast8Seconds", "UsedSkillRecently"}, tooltip = "This also implies that you have used a Skill Recently.", apply = function(val, modList, enemyModList) + { var = "conditionUsedWarcryRecently", type = "check", label = "Have you used a Warcry Recently?", ifCond = "UsedWarcryRecently", implyCondList = {"UsedWarcryInPast8Seconds"}, tooltip = "This also implies that you have used a Skill Recently.", apply = function(val, modList, enemyModList) modList:NewMod("Condition:UsedWarcryRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:UsedWarcryInPast8Seconds", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:UsedSkillRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) @@ -1588,7 +1594,7 @@ Huge sets the radius to 11. { var = "multiplierMineDetonatedRecently", type = "count", label = "# of Mines Detonated Recently:", ifMult = "MineDetonatedRecently", implyCond = "DetonatedMinesRecently", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:MineDetonatedRecently", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "minesPerThrow", type = "count", label = "# of Mines per throw:", ifFlag = "mine", tooltip = "This will override the number of Mines per throw", apply = function(val, modList, enemyModList) + { var = "minesPerThrow", type = "count", showDefaultPlaceholder = true, label = "# of Mines per throw:", ifFlag = "mine", tooltip = "This will override the number of Mines per throw", apply = function(val, modList, enemyModList) modList:NewMod("MineThrowCount", "OVERRIDE", val, "Config", {type = "Condition", var = "Combat"}) end }, { var = "TriggeredTrapsRecently", type = "check", label = "Have you Triggered a Trap Recently?", ifCond = "TriggeredTrapsRecently", apply = function(val, modList, enemyModList) @@ -1600,7 +1606,7 @@ Huge sets the radius to 11. { var = "conditionThrownTrapOrMineRecently", type = "check", label = "Have you thrown a Trap or Mine Recently?", ifCond = "TrapOrMineThrownRecently", apply = function(val, modList, enemyModList) modList:NewMod("Condition:TrapOrMineThrownRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "trapsPerThrow", type = "count", label = "# of Traps per throw:", ifFlag = "trap", tooltip = "This will override the number of Traps per throw", apply = function(val, modList, enemyModList) + { var = "trapsPerThrow", type = "count", showDefaultPlaceholder = true, label = "# of Traps per throw:", ifFlag = "trap", tooltip = "This will override the number of Traps per throw", apply = function(val, modList, enemyModList) modList:NewMod("TrapThrowCount", "OVERRIDE", val, "Config", {type = "Condition", var = "Combat"}) end }, { var = "conditionCursedEnemyRecently", type = "check", label = "Have you Cursed an enemy Recently?", ifCond="CursedEnemyRecently", apply = function(val, modList, enemyModList) @@ -1625,7 +1631,7 @@ Huge sets the radius to 11. { var = "conditionRavenousCorpseConsumed", type = "check", label = "Has Ravenous consumed a corpse?", ifSkill = "Ravenous", implyCond = "ConsumedCorpseRecently", tooltip = "Corpse must be the same type as the monster you're fighting.\nThis also implies you have 'Consumed a corpse Recently'", apply = function(val, modList, enemyModList) modList:NewMod("Condition:RavenousCorpseConsumed", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierWarcryUsedRecently", type = "count", label = "# of Warcries Used Recently:", {ifFlag = "warcry", ifMult = "WarcryUsedRecently"}, implyCondList = {"UsedWarcryRecently", "UsedWarcryInPast8Seconds", "UsedSkillRecently"}, tooltip = "This also implies you have 'Used a Warcry Recently', 'Used a Warcry in the past 8 seconds', and 'Used a Skill Recently'", apply = function(val, modList, enemyModList) + { var = "multiplierWarcryUsedRecently", type = "count", label = "# of Warcries Used Recently:", ifMult = "WarcryUsedRecently", tooltip = "This also implies you have 'Used a Warcry Recently', 'Used a Warcry in the past 8 seconds', and 'Used a Skill Recently'", apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:WarcryUsedRecently", "BASE", m_min(val, 100), "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:UsedWarcryRecently", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) modList:NewMod("Condition:UsedWarcryInPast8Seconds", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) @@ -1702,7 +1708,7 @@ Huge sets the radius to 11. { var = "multiplierPvpTvalueOverride", type = "count", label = "PvP Tvalue override (ms):", ifFlag = "isPvP", tooltip = "Tvalue in milliseconds. This overrides the Tvalue of a given skill, for instance any with fixed Tvalues, or modified Tvalues", apply = function(val, modList, enemyModList) modList:NewMod("MultiplierPvpTvalueOverride", "BASE", val, "Config", { type = "Condition", var = "Combat" }) end }, - { var = "multiplierPvpDamage", type = "count", label = "Custom PvP Damage multiplier percent:", ifFlag = "isPvP", tooltip = "This multiplies the damage of a given skill in pvp, for instance any with damage multiplier specific to pvp (from skill or support or item like sire of shards)", apply = function(val, modList, enemyModList) + { var = "multiplierPvpDamage", type = "count", showDefaultPlaceholder = true, label = "Custom PvP Damage multiplier percent:", ifFlag = "isPvP", tooltip = "This multiplies the damage of a given skill in pvp, for instance any with damage multiplier specific to pvp (from skill or support or item like sire of shards)", apply = function(val, modList, enemyModList) modList:NewMod("PvpDamageMultiplier", "MORE", val - 100, "Config") end }, { var = "buffAccelerationShrine", type = "check", label = "Have Acceleration Shrine?", ifFlag = "Condition:CanHaveRegularShrines", tooltip = "This will enable the Acceleration Shrine buff.\n\t50% increased Action Speed\n\t80% increased Projectile Speed", apply = function(val, modList, enemyModList) @@ -1817,7 +1823,7 @@ Huge sets the radius to 11. { var = "conditionEnemyBleeding", type = "check", label = "Is the enemy Bleeding?", ifEnemyCond = "Bleeding", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Bleeding", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "overrideBleedStackPotential", type = "count", label = "Bleed Stack Potential override:", ifOption = "conditionEnemyBleeding", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict a Bleed on an enemy before the duration of your first Bleed expires", apply = function(val, modList, enemyModList) + { var = "overrideBleedStackPotential", type = "count", showDefaultPlaceholder = true, label = "Bleed Stack Potential override:", ifOption = "conditionEnemyBleeding", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict a Bleed on an enemy before the duration of your first Bleed expires", apply = function(val, modList, enemyModList) modList:NewMod("BleedStackPotentialOverride", "OVERRIDE", val, "Config", { type = "Condition", var = "Effective" }) end }, { var = "conditionSingleBleed", type = "check", label = "Cap to Single Bleed on enemy?", ifCond = "SingleBleed", tooltip = "This is for Blood Sap Tincture, but will limit you to only applying a single Bleed on the enemy", apply = function(val, modList, enemyModList) @@ -1883,7 +1889,7 @@ Huge sets the radius to 11. { var = "conditionEnemyIgnited", type = "check", label = "Is the enemy ^xB97123Ignited?", ifEnemyCond = "Ignited", implyCond = "Burning", tooltip = "This also implies that the enemy is ^xB97123Burning.", apply = function(val, modList, enemyModList) enemyModList:NewMod("Condition:Ignited", "FLAG", true, "Config", { type = "Condition", var = "Effective" }) end }, - { var = "overrideIgniteStackPotential", type = "count", label = "^xB97123Ignite^7 Stack Potential override:", ifOption = "conditionEnemyIgnited", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict an Ignite on an enemy before the duration of your first Ignite expires", apply = function(val, modList, enemyModList) + { var = "overrideIgniteStackPotential", type = "count", showDefaultPlaceholder = true, label = "^xB97123Ignite^7 Stack Potential override:", ifOption = "conditionEnemyIgnited", tooltip = "Allows you to manually set the Stack Potential value for a skill.\nStack Potential equates to the number of times you are able to inflict an Ignite on an enemy before the duration of your first Ignite expires", apply = function(val, modList, enemyModList) modList:NewMod("IgniteStackPotentialOverride", "OVERRIDE", val, "Config", { type = "Condition", var = "Effective" }) end }, { var = "conditionEnemyScorched", type = "check", ifFlag = "inflictScorch", label = "Is the enemy ^xB97123Scorched?", tooltip = "^xB97123Scorched ^7enemies have lowered elemental resistances, up to -30%.\nThis option will also allow you to input the effect of ^xB97123Scorched.", apply = function(val, modList, enemyModList) @@ -2365,7 +2371,7 @@ Huge sets the radius to 11. {val="SpellProjectile",label="Projectile Spell"} } }, { var = "enemySpeed", type = "countAllowZero", label = "Enemy attack / cast time in ms:", defaultPlaceholderState = 700 }, - { var = "enemyMultiplierPvpDamage", type = "count", label = "Custom PvP Damage multiplier percent:", ifFlag = "isPvP", tooltip = "This multiplies the damage of a given skill in pvp, for instance any with damage multiplier specific to pvp (from skill or support or item like sire of shards)", apply = function(val, modList, enemyModList) + { var = "enemyMultiplierPvpDamage", type = "count", showDefaultPlaceholder = true, label = "Custom PvP Damage multiplier percent:", ifFlag = "isPvP", tooltip = "This multiplies the damage of a given skill in pvp, for instance any with damage multiplier specific to pvp (from skill or support or item like sire of shards)", apply = function(val, modList, enemyModList) enemyModList:NewMod("MultiplierPvpDamage", "BASE", val, "Config") end }, { var = "enemyCritChance", type = "countAllowZero", label = "Enemy critical strike chance:", defaultPlaceholderState = 5 }, diff --git a/src/Modules/ConfigVisibility.lua b/src/Modules/ConfigVisibility.lua index 94692f953aa..efaa3793790 100644 --- a/src/Modules/ConfigVisibility.lua +++ b/src/Modules/ConfigVisibility.lua @@ -142,7 +142,7 @@ end -- Options with these properties or label keywords stay hidden even when "Show All Configurations" is on. local function isShowAllExcluded(varData) - if varData.ifOption or varData.ifSkill or varData.ifSkillData or varData.ifSkillFlag or varData.legacy then + if varData.ifOption or varData.ifCondTrue or varData.ifSkill or varData.ifSkillData or varData.ifSkillFlag or varData.legacy then return true end if varData.label then From ae037fa28a112182eb2ca2190af381ff21b14b06 Mon Sep 17 00:00:00 2001 From: Alexander Karrer Date: Thu, 29 Oct 2026 02:10:15 +0100 Subject: [PATCH 3/4] Default Sign of Purpose to average mode --- src/Classes/ConfigTab.lua | 6 +++++- src/Modules/ConfigOptions.lua | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index c37fb86613b..fda5b0b76f0 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -1088,7 +1088,11 @@ function ConfigTabClass:UpdateControls() elseif control._className == "CheckBoxControl" then control.state = self.configSets[self.activeConfigSetId].input[var] elseif control._className == "DropDownControl" then - control:SelByValue(self.configSets[self.activeConfigSetId].input[var] or self:GetDefaultState(var), "val") + local value = self.configSets[self.activeConfigSetId].input[var] + if value == nil then + value = self:GetDefaultState(var) + end + control:SelByValue(value, "val") end end self:UpdateCustomModsControls() diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 843825f1e34..ea334672883 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -337,7 +337,7 @@ return { { var = "targetBrandedEnemy", type = "check", label = "Skill is targeting the Branded enemy", ifCond = "TargetingBrandedEnemy", defaultState = true, apply = function(val, modList, enemyModList) modList:NewMod("Condition:TargetingBrandedEnemy", "FLAG", true, "Config") end }, - { var = "BrandsInLastQuarter", type = "list", label = "Sign of Purpose mode:", ifCond = "BrandLastQuarter", tooltip = "Inactive: excludes the activation frequency bonus.\nAverage: averages the bonus over the full attached duration, giving 25% more Activation Frequency for Sign of Purpose. Assumes Brands remain attached for their full duration.\nLast 25%: applies the full bonus during the final quarter of attached duration.", list = {{val=false,label="Inactive"},{val="AVERAGE",label="Average"},{val=true,label="Last 25%"}}, apply = function(val, modList, enemyModList) + { var = "BrandsInLastQuarter", type = "list", defaultIndex = 2, label = "Sign of Purpose mode:", ifCond = "BrandLastQuarter", tooltip = "Inactive: excludes the activation frequency bonus.\nAverage: averages the bonus over the full attached duration, giving 25% more Activation Frequency for Sign of Purpose. Assumes Brands remain attached for their full duration.\nLast 25%: applies the full bonus during the final quarter of attached duration.", list = {{val=false,label="Inactive"},{val="AVERAGE",label="Average"},{val=true,label="Last 25%"}}, apply = function(val, modList, enemyModList) if val then modList:NewMod("Condition:BrandLastQuarter", "FLAG", true, "Config") if val == "AVERAGE" then From 9c0cc8485b0e505e4a4bc8c61a0498a48a481557 Mon Sep 17 00:00:00 2001 From: Alexander Karrer Date: Thu, 29 Oct 2026 02:24:49 +0100 Subject: [PATCH 4/4] Unify attached Brand duration configuration modes --- src/Classes/ConfigTab.lua | 18 ++++++++++++++++++ src/Classes/ModStore.lua | 5 ++++- src/Modules/ConfigOptions.lua | 18 ++++++++---------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/Classes/ConfigTab.lua b/src/Classes/ConfigTab.lua index fda5b0b76f0..845e98f714e 100644 --- a/src/Classes/ConfigTab.lua +++ b/src/Classes/ConfigTab.lua @@ -842,6 +842,7 @@ function ConfigTabClass:Load(xml, fileName) self.activeConfigSetId = 1 self.configSets = { } self.configSetOrderList = { 1 } + local brandDurationModeProvided = { } local function setInputAndPlaceholder(node, configSetId) if node.elem == "Input" then @@ -849,6 +850,9 @@ function ConfigTabClass:Load(xml, fileName) launch:ShowErrMsg("^1Error parsing '%s': 'Input' element missing name attribute", fileName) return true end + if node.attrib.name == "brandAttachedDurationMode" then + brandDurationModeProvided[configSetId] = true + end if node.attrib.number then self.configSets[configSetId].input[node.attrib.name] = tonumber(node.attrib.number) elseif node.attrib.string then @@ -925,6 +929,20 @@ function ConfigTabClass:Load(xml, fileName) -- Migration check for legacy builds for _, configSetId in ipairs(self.configSetOrderList) do local configSet = self.configSets[configSetId] + local input = configSet.input + if not brandDurationModeProvided[configSetId] then + if input.BrandsInLastQuarter == true then + input.brandAttachedDurationMode = "LAST_QUARTER" + elseif input.BrandsInLastQuarter == "AVERAGE" then + input.brandAttachedDurationMode = "AVERAGE" + elseif input.BrandsInLastHalf == true then + input.brandAttachedDurationMode = "LAST_HALF" + elseif input.BrandsInLastQuarter == false or input.BrandsInLastHalf == false then + input.brandAttachedDurationMode = "EARLY" + end + end + input.BrandsInLastQuarter = nil + input.BrandsInLastHalf = nil local legacyText = configSet.input and configSet.input.customMods or "" if legacyText ~= "" and (not configSet.customModsList or #configSet.customModsList == 0 or (#configSet.customModsList == 1 and (configSet.customModsList[1].text or "") == "")) then configSet.customModsList = { { title = "Default", enabled = true, text = legacyText } } diff --git a/src/Classes/ModStore.lua b/src/Classes/ModStore.lua index e0fe512e1c5..326ebd35e86 100644 --- a/src/Classes/ModStore.lua +++ b/src/Classes/ModStore.lua @@ -638,8 +638,11 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits) and GetCondition(self, "AverageFocus", cfg) then conditionEffect = GetMultiplier(self, "FocusUptime", cfg) elseif tag.var == "BrandLastQuarter" and not tag.neg and mod.name == "BrandActivationFrequency" - and GetCondition(self, "AverageBrandLastQuarter", cfg) then + and GetCondition(self, "AverageBrandAttachedDuration", cfg) then conditionEffect = 0.25 + elseif tag.var == "BrandLastHalf" and not tag.neg and mod.name == "AreaOfEffect" + and GetCondition(self, "AverageBrandAttachedDuration", cfg) then + conditionEffect = 0.5 end local match = false local allOneH = ((self.actor.weaponData1 and self.actor.weaponData1.countsAsAll1H) and self.actor.weaponData1) or ((self.actor.weaponData2 and self.actor.weaponData2.countsAsAll1H) and self.actor.weaponData2) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index ea334672883..8866f331acd 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -337,18 +337,16 @@ return { { var = "targetBrandedEnemy", type = "check", label = "Skill is targeting the Branded enemy", ifCond = "TargetingBrandedEnemy", defaultState = true, apply = function(val, modList, enemyModList) modList:NewMod("Condition:TargetingBrandedEnemy", "FLAG", true, "Config") end }, - { var = "BrandsInLastQuarter", type = "list", defaultIndex = 2, label = "Sign of Purpose mode:", ifCond = "BrandLastQuarter", tooltip = "Inactive: excludes the activation frequency bonus.\nAverage: averages the bonus over the full attached duration, giving 25% more Activation Frequency for Sign of Purpose. Assumes Brands remain attached for their full duration.\nLast 25%: applies the full bonus during the final quarter of attached duration.", list = {{val=false,label="Inactive"},{val="AVERAGE",label="Average"},{val=true,label="Last 25%"}}, apply = function(val, modList, enemyModList) - if val then + { var = "brandAttachedDurationMode", type = "list", defaultIndex = 2, label = "Attached Brand duration mode:", ifCond = {"BrandLastQuarter", "BrandLastHalf"}, list = {{val="EARLY",label="First 50%"},{val="AVERAGE",label="Average"},{val="LAST_HALF",label="50-75% expired"},{val="LAST_QUARTER",label="Last 25%"}}, apply = function(val, modList, enemyModList) + if val == "AVERAGE" or val == "LAST_QUARTER" then modList:NewMod("Condition:BrandLastQuarter", "FLAG", true, "Config") - if val == "AVERAGE" then - modList:NewMod("Condition:AverageBrandLastQuarter", "FLAG", true, "Config") - else - modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") - end end - end }, - { var = "BrandsInLastHalf", type = "check", label = "Last 50% of attached duration?", ifCond = "BrandLastHalf", apply = function(val, modList, enemyModList) - modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") + if val == "AVERAGE" or val == "LAST_HALF" or val == "LAST_QUARTER" then + modList:NewMod("Condition:BrandLastHalf", "FLAG", true, "Config") + end + if val == "AVERAGE" then + modList:NewMod("Condition:AverageBrandAttachedDuration", "FLAG", true, "Config") + end end }, { label = "Carrion Golem:", ifSkill = "Summon Carrion Golem", includeTransfigured = true }, { var = "carrionGolemNearbyMinion", type = "count", label = "# of Nearby Non-Golem Minions:", ifSkill = "Summon Carrion Golem", includeTransfigured = true, apply = function(val, modList, enemyModList)