From 56e151b66528d258d510d1582c5e6d734af61a6c Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 12 May 2026 02:14:34 -0500 Subject: [PATCH 01/19] add support for Ancestral Call, Crescendo II and III, ancestral boost tree nodes --- src/Data/ModCache.lua | 12 +++--- src/Data/SkillStatMap.lua | 7 ++++ src/Data/Skills/sup_int.lua | 5 +++ src/Data/Skills/sup_str.lua | 18 +++++++++ src/Export/Skills/sup_int.txt | 5 +++ src/Export/Skills/sup_str.txt | 14 +++++++ src/Modules/CalcOffence.lua | 70 ++++++++++++++++++++++++++++++++--- src/Modules/CalcSections.lua | 9 ++++- src/Modules/ModParser.lua | 3 ++ 9 files changed, 129 insertions(+), 14 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index ad786db07a..bcdfe19a54 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -2325,7 +2325,7 @@ c["30% increased Accuracy Rating against Rare or Unique Enemies"]={{[1]={[1]={ac c["30% increased Accuracy Rating at Close Range"]={{[1]={[1]={type="Condition",var="AtCloseRange"},flags=0,keywordFlags=0,name="AccuracyVsEnemy",type="INC",value=30}},nil} c["30% increased Accuracy Rating while moving"]={{[1]={[1]={type="Condition",var="Moving"},flags=0,keywordFlags=0,name="Accuracy",type="INC",value=30}},nil} c["30% increased Archon Buff duration"]={{[1]={flags=0,keywordFlags=0,name="Duration",type="INC",value=30}}," Archon Buff "} -c["30% increased Area of Effect of Ancestrally Boosted Attacks"]={{[1]={flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=30}}," of Ancestrally Boosted Attacks "} +c["30% increased Area of Effect of Ancestrally Boosted Attacks"]={{[1]={flags=1,keywordFlags=0,name="AncestralBoostAreaOfEffect",type="INC",value=30}},nil} c["30% increased Armour"]={{[1]={flags=0,keywordFlags=0,name="Armour",type="INC",value=30}},nil} c["30% increased Armour while Bleeding"]={{[1]={[1]={type="Condition",var="Bleeding"},flags=0,keywordFlags=0,name="Armour",type="INC",value=30}},nil} c["30% increased Armour while Surrounded"]={{[1]={[1]={type="Condition",var="Surrounded"},flags=0,keywordFlags=0,name="Armour",type="INC",value=30}},nil} @@ -2563,8 +2563,7 @@ c["4% chance that if you would gain Rage on Hit, you instead gain up to your max c["4% increased Area of Effect"]={{[1]={flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}},nil} c["4% increased Area of Effect for Attacks"]={{[1]={flags=1,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}},nil} c["4% increased Area of Effect for Attacks per Enemy you've Ignited in the last 8 seconds, up to 40%"]={{[1]={flags=1,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}}," per Enemy you've Ignited in the last 8 seconds, up to 40% "} -c["4% increased Area of Effect of Ancestrally Boosted Attacks"]={{[1]={flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}}," of Ancestrally Boosted Attacks "} -c["4% increased Area of Effect of Ancestrally Boosted Attacks Ancestrally Boosted Attacks deal 8% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}}," of Ancestrally Boosted Attacks Ancestrally Boosted Attacks deal 8% increased Damage "} +c["4% increased Area of Effect of Ancestrally Boosted Attacks"]={{[1]={flags=1,keywordFlags=0,name="AncestralBoostAreaOfEffect",type="INC",value=4}},nil} c["4% increased Attack Damage per 75 Item Armour and Evasion Rating on Equipped Shield"]={{[1]={[1]={div=75,statList={[1]="ArmourOnWeapon 2",[2]="EvasionOnWeapon 2"},type="PerStat"},[2]={type="Condition",var="UsingShield"},flags=1,keywordFlags=0,name="Damage",type="INC",value=4}},nil} c["4% increased Attack Speed"]={{[1]={flags=1,keywordFlags=0,name="Speed",type="INC",value=4}},nil} c["4% increased Attack Speed while a Rare or Unique Enemy is in your Presence"]={{[1]={[1]={actor="enemy",type="ActorCondition",varList={[1]="NearbyRareOrUniqueEnemy",[2]="RareOrUnique"}},flags=1,keywordFlags=0,name="Speed",type="INC",value=4}},nil} @@ -4338,10 +4337,9 @@ c["Alternating every 5 seconds: Take 40% less Damage from Hits"]={nil,"Alternati c["Always Hits"]={{[1]={[1]={type="Condition",var="{Hand}Attack"},flags=0,keywordFlags=0,name="CannotBeEvaded",type="FLAG",value=true}},nil} c["Always Poison on Hit with this weapon"]={{[1]={[1]={type="Condition",var="{Hand}Attack"},[2]={neg=true,skillType=167,type="SkillType"},flags=8192,keywordFlags=0,name="PoisonChance",type="OVERRIDE",value=100}},nil} c["Always deals Critical Hits against Heavy Stunned Enemies"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="HeavyStunned"},[2]={type="Condition",var="{Hand}Attack"},flags=0,keywordFlags=0,name="CritChance",type="OVERRIDE",value=100}},nil} -c["Ancestrally Boosted Attacks deal 16% increased Damage"]={nil,"Ancestrally Boosted Attacks deal 16% increased Damage "} -c["Ancestrally Boosted Attacks deal 30% increased Damage"]={nil,"Ancestrally Boosted Attacks deal 30% increased Damage "} -c["Ancestrally Boosted Attacks deal 30% increased Damage On Heavy Stunning a Rare or Unique Enemy, your next Attack within 4 seconds will be Ancestrally Boosted"]={nil,"Ancestrally Boosted Attacks deal 30% increased Damage On Heavy Stunning a Rare or Unique Enemy, your next Attack within 4 seconds will be Ancestrally Boosted "} -c["Ancestrally Boosted Attacks deal 8% increased Damage"]={nil,"Ancestrally Boosted Attacks deal 8% increased Damage "} +c["Ancestrally Boosted Attacks deal 16% increased Damage"]={{[1]={flags=1,keywordFlags=0,name="AncestralBoostDamage",type="INC",value=16}},nil} +c["Ancestrally Boosted Attacks deal 30% increased Damage"]={{[1]={flags=1,keywordFlags=0,name="AncestralBoostDamage",type="INC",value=30}},nil} +c["Ancestrally Boosted Attacks deal 8% increased Damage"]={{[1]={flags=1,keywordFlags=0,name="AncestralBoostDamage",type="INC",value=8}},nil} c["Any number of Poisons from this Weapon can affect a target at the same time"]={{[1]={flags=0,keywordFlags=0,name="PoisonCanStack",type="FLAG",value=true},[2]={[1]={type="Condition",var="{Hand}Attack"},[2]={neg=true,skillType=167,type="SkillType"},flags=0,keywordFlags=0,name="PoisonStacks",type="OVERRIDE",value=math.huge}},nil} c["Apply 10 Critical Weakness to Enemies when Consuming a Mark on them"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Apply Debilitate to Enemies 3 Metres in front of you while your Shield is raised"]={nil,"Apply Debilitate to Enemies 3 Metres in front of you while your Shield is raised "} diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 78811af1a6..67493c6200 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -2530,6 +2530,13 @@ return { ["slam_aftershock_chance_%"] = { mod("AftershockChance", "BASE", nil) }, +-- Final Strike +["final_strike_is_ancestrally_boosted"] = { + flag("FinalStrikeAncestrallyBoosted"), +}, +["is_final_strike"] = { + flag("Condition:FinalStrike"), +}, -- Curse ["curse_effect_+%"] = { mod("CurseEffect", "INC", nil), diff --git a/src/Data/Skills/sup_int.lua b/src/Data/Skills/sup_int.lua index 80cd96b6bd..7109d0a233 100644 --- a/src/Data/Skills/sup_int.lua +++ b/src/Data/Skills/sup_int.lua @@ -2590,6 +2590,11 @@ skills["SupportCrescendoPlayerTwo"] = { label = "Crescendo II", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["support_crescendo_non_final_strike_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Condition", var = "FinalStrike", neg = true}) + }, + }, baseFlags = { }, constantStats = { diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 29b4d9390f..10f917c186 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -149,8 +149,17 @@ skills["SupportAncestralCallPlayer"] = { label = "Ancestral Call I", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["ancestral_call_spirit_strike_interval_ms"] = { + mod("AncestralCallCooldown", "BASE", nil), + div = 1000, + }, + }, baseFlags = { }, + baseMods = { + mod("AdditionalStrikeTarget", "BASE", 2), + }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 5000 }, }, @@ -181,8 +190,17 @@ skills["SupportAncestralCallPlayerTwo"] = { label = "Ancestral Call II", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["ancestral_call_spirit_strike_interval_ms"] = { + mod("AncestralCallCooldown", "BASE", nil), + div = 1000, + }, + }, baseFlags = { }, + baseMods = { + mod("AdditionalStrikeTarget", "BASE", 2), + }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 3000 }, }, diff --git a/src/Export/Skills/sup_int.txt b/src/Export/Skills/sup_int.txt index 36db0880d2..98cc8d3548 100644 --- a/src/Export/Skills/sup_int.txt +++ b/src/Export/Skills/sup_int.txt @@ -442,6 +442,11 @@ statMap = { #skill SupportCrescendoPlayerTwo #set SupportCrescendoPlayerTwo +statMap = { + ["support_crescendo_non_final_strike_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack, 0, { type = "Condition", var = "FinalStrike", neg = true}) + }, +}, #mods #skillEnd diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index fd963167b5..54664f1bdf 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -26,11 +26,25 @@ local skills, mod, flag, skill = ... #skill SupportAncestralCallPlayer #set SupportAncestralCallPlayer +statMap = { + ["ancestral_call_spirit_strike_interval_ms"] = { + mod("AncestralCallCooldown", "BASE", nil), + div = 1000, + }, +}, +#baseMod mod("AdditionalStrikeTarget", "BASE", 2) #mods #skillEnd #skill SupportAncestralCallPlayerTwo #set SupportAncestralCallPlayerTwo +statMap = { + ["ancestral_call_spirit_strike_interval_ms"] = { + mod("AncestralCallCooldown", "BASE", nil), + div = 1000, + }, +}, +#baseMod mod("AdditionalStrikeTarget", "BASE", 2) #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 03b0072011..21f4525c5e 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3337,6 +3337,7 @@ function calcs.offence(env, actor, activeSkill) end output.FistOfWarDamageEffect = 1 + output.AncestralCallDamageEffect = 1 if env.mode_combat then local ruthlessEffect = env.configInput.ruthlessSupportMode or "AVERAGE" local ruthlessBlowMaxCount = skillModList:Sum("BASE", cfg, "RuthlessBlowMaxCount") @@ -3355,6 +3356,16 @@ function calcs.offence(env, actor, activeSkill) local ruthlessBlowStunEffect = (ruthlessBlowChance / 100) * ruthlessBlowStunMultiplier skillModList:NewMod("EnemyHeavyStunBuildup", "MORE", ruthlessBlowStunEffect * 100, "Ruthless Blows") + -- passive nodes + local ancestrallyBoostedIncDamageMulti = 1 + modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 + local ancestrallyBoostedIncArea = modDB:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense + if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then + local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree + local sourceName = "Ancestral Boost - "..modSource:match("Support(.-)Player") -- crude way to grab Support name, there may be a way in data now or a way to create a map in data with the above structured key + skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) + end + globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 -- If Fist of War & Active Skill is a Slam Skill & NOT a Vaal Skill & NOT used by mirage or other if globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then @@ -3367,8 +3378,8 @@ function calcs.offence(env, actor, activeSkill) s_format("= %d%%", globalOutput.FistOfWarUptimeRatio), } end - globalOutput.AvgFistOfWarDamage = globalOutput.FistOfWarDamageMultiplier - globalOutput.AvgFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * (globalOutput.FistOfWarUptimeRatio / 100) + globalOutput.AvgFistOfWarDamage = globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncDamageMulti + globalOutput.AvgFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncDamageMulti * (globalOutput.FistOfWarUptimeRatio / 100) if globalBreakdown then globalBreakdown.AvgFistOfWarDamageEffect = { s_format("1 + (%.2f ^8(fist of war damage multiplier)", globalOutput.FistOfWarDamageMultiplier), @@ -3376,13 +3387,15 @@ function calcs.offence(env, actor, activeSkill) s_format("= %.2f", globalOutput.AvgFistOfWarDamageEffect), } end - globalOutput.MaxFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier + globalOutput.MaxFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncArea if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output.FistOfWarDamageEffect = globalOutput.MaxFistOfWarDamageEffect skillModList:NewMod("AreaOfEffect", "MORE", skillModList:Sum("BASE", nil, "FistOfWarMOREAoE"), "Max Fist of War Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max Fist of War Boosted AoE") else output.FistOfWarDamageEffect = globalOutput.AvgFistOfWarDamageEffect - skillModList:NewMod("AreaOfEffect", "MORE", m_floor(skillModList:Sum("BASE", nil, "FistOfWarMOREAoE") / 100 * globalOutput.FistOfWarUptimeRatio), "Avg Fist Of War Boosted AoE") + skillModList:NewMod("AreaOfEffect", "MORE", m_floor(skillModList:Sum("BASE", nil, "FistOfWarMOREAoE") * globalOutput.FistOfWarUptimeRatio / 100), "Avg Fist Of War Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput.FistOfWarUptimeRatio / 100), "Avg Fist Of War Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput.AvgFistOfWarDamageEffect @@ -3390,6 +3403,48 @@ function calcs.offence(env, actor, activeSkill) else output.FistOfWarDamageEffect = 1 end + + globalOutput.AncestralCallCooldown = skillModList:Sum("BASE", cfg, "AncestralCallCooldown") or 0 + -- If Ancestral Call & Active Skill is NOT a Vaal Skill & NOT used by mirage or other & NOT a Channel Skill + if globalOutput.AncestralCallCooldown ~= 0 and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] and not activeSkill.skillTypes[SkillType.Channel] then + globalOutput.AncestralCallAdditionalStrike = skillModList:Sum("BASE", nil, "AncestralCallAdditionalStrike") + skillModList:NewMod("AdditionalStrikeTarget", "BASE", globalOutput.AncestralCallAdditionalStrike, "Ancestral Call when Ancestrally Boosted") + + globalOutput.AncestralCallDamageMultiplier = ancestrallyBoostedIncDamageMulti + globalOutput.AncestralCallUptimeRatio = m_min( (1 / globalOutput.Speed) / globalOutput.AncestralCallCooldown, 1) * 100 + if globalBreakdown then + globalBreakdown.AncestralCallUptimeRatio = { + s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), + s_format("/ %.2f, 1) ^8(ancestral call cooldown)", globalOutput.AncestralCallCooldown), + s_format("= %d%%", globalOutput.AncestralCallUptimeRatio), + } + end + globalOutput.AvgAncestralCallDamage = globalOutput.AncestralCallDamageMultiplier + globalOutput.AvgAncestralCallDamageEffect = 1 + if ancestrallyBoostedIncDamageMulti > 1 then -- if there is no increased damage, then Ancestrally Boosted Strikes do not have any damage portion + globalOutput.AvgAncestralCallDamageEffect = 1 + ancestrallyBoostedIncDamageMulti * (globalOutput.AncestralCallUptimeRatio / 100) + end + if globalBreakdown then + globalBreakdown.AvgAncestralCallDamageEffect = { + s_format("1 + (%.2f ^8(ancestral call damage multiplier)", ancestrallyBoostedIncDamageMulti > 1 and globalOutput.AncestralCallDamageMultiplier or 0), + s_format("x %.2f) ^8(ancestral call uptime ratio)", globalOutput.AncestralCallUptimeRatio / 100 or 0), + s_format("= %.2f", globalOutput.AvgAncestralCallDamageEffect), + } + end + globalOutput.MaxAncestralCallDamageEffect = ancestrallyBoostedIncDamageMulti + if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then + output.AncestralCallDamageEffect = globalOutput.MaxAncestralCallDamageEffect + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max Ancestral Call Boosted AoE") + else + output.AncestralCallDamageEffect = globalOutput.AvgAncestralCallDamageEffect + skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput.AncestralCallUptimeRatio / 100), "Avg Ancestral Call Boosted AoE") + end + calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) + globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput.AvgAncestralCallDamageEffect + globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput.MaxAncestralCallDamageEffect + else + output.AncestralCallDamageEffect = 1 + end end -- Calculate maximum sustainable fuses and explosion rate for Explosive Arrow @@ -3729,6 +3784,9 @@ function calcs.offence(env, actor, activeSkill) if output.FistOfWarDamageEffect ~= 1 then t_insert(breakdown[damageType], s_format("x %.2f ^8(fist of war effect modifier)", output.FistOfWarDamageEffect)) end + if output.AncestralCallDamageEffect ~= 1 then + t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral call effect modifier)", output.AncestralCallDamageEffect)) + end if globalOutput.OffensiveWarcryEffect ~= 1 and not activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then t_insert(breakdown[damageType], s_format("x %.2f ^8(aggregated warcry exerted effect modifier)", globalOutput.OffensiveWarcryEffect)) end @@ -3737,9 +3795,9 @@ function calcs.offence(env, actor, activeSkill) end end if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * globalOutput.MaxOffensiveWarcryEffect + output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * globalOutput.MaxOffensiveWarcryEffect else - output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * globalOutput.OffensiveWarcryEffect + output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * globalOutput.OffensiveWarcryEffect end local allMult = output.allMult if pass == 1 then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 9434a4a2cb..5bc20f1ef0 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -417,11 +417,18 @@ return { }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, - { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, }, + { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, { format = "{0:output:FistOfWarUptimeRatio}%", { breakdown = "FistOfWarUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxFistOfWarDamageEffect}" }, }, + { label = "Ancestral Call", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralCallUptimeRatio", + { format = "{2:output:AvgAncestralCallDamageEffect}", { breakdown = "AvgAncestralCallDamageEffect"}, }, + { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{0:output:AncestralCallUptimeRatio}%", { breakdown = "AncestralCallUptimeRatio" }, }, + { format = "" }, + { format = "{2:output:MaxAncestralCallDamageEffect}" }, + }, } } } }, { 3, "Dot", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Skill Damage over Time", data = { diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index cc20d66c35..51dabe6cc4 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2622,6 +2622,9 @@ local specialModList = { -- Exerted Attacks ["exerted attacks deal (%d+)%% increased damage"] = function(num) return { mod("ExertIncrease", "INC", num, nil, ModFlag.Attack, 0) } end, ["exerted attacks have (%d+)%% chance to deal double damage"] = function(num) return { mod("ExertDoubleDamageChance", "BASE", num, nil, ModFlag.Attack, 0) } end, + -- Ancestrally Boosted + ["ancestrally boosted attacks deal (%d+)%% increased damage"] = function(num) return { mod("AncestralBoostDamage", "INC", num, nil, ModFlag.Attack, 0) } end, + ["(%d+)%% increased area of effect of ancestrally boosted attacks"] = function(num) return { mod("AncestralBoostAreaOfEffect", "INC", num, nil, ModFlag.Attack, 0) } end, -- Leech Related ["life leech is instant"] = { mod("InstantLifeLeech", "BASE", 100), }, ["mana leech is instant"] = { mod("InstantManaLeech", "BASE", 100), }, From fa20a0297ef2b0125712a4c4ed8f1189c111523d Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 12 May 2026 02:40:03 -0500 Subject: [PATCH 02/19] fix ancestral call inc dmg from tree --- src/Modules/CalcOffence.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 21f4525c5e..5e5c23a088 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3357,7 +3357,7 @@ function calcs.offence(env, actor, activeSkill) skillModList:NewMod("EnemyHeavyStunBuildup", "MORE", ruthlessBlowStunEffect * 100, "Ruthless Blows") -- passive nodes - local ancestrallyBoostedIncDamageMulti = 1 + modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 + local ancestrallyBoostedIncDamageMulti = modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 local ancestrallyBoostedIncArea = modDB:Sum("INC", cfg, "AncestralBoostAreaOfEffect") -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then @@ -3421,17 +3421,17 @@ function calcs.offence(env, actor, activeSkill) end globalOutput.AvgAncestralCallDamage = globalOutput.AncestralCallDamageMultiplier globalOutput.AvgAncestralCallDamageEffect = 1 - if ancestrallyBoostedIncDamageMulti > 1 then -- if there is no increased damage, then Ancestrally Boosted Strikes do not have any damage portion + if ancestrallyBoostedIncDamageMulti > 0 then -- if there is no increased damage, then Ancestrally Boosted Strikes do not have any damage portion globalOutput.AvgAncestralCallDamageEffect = 1 + ancestrallyBoostedIncDamageMulti * (globalOutput.AncestralCallUptimeRatio / 100) end if globalBreakdown then globalBreakdown.AvgAncestralCallDamageEffect = { - s_format("1 + (%.2f ^8(ancestral call damage multiplier)", ancestrallyBoostedIncDamageMulti > 1 and globalOutput.AncestralCallDamageMultiplier or 0), + s_format("1 + (%.2f ^8(ancestral call damage multiplier)", ancestrallyBoostedIncDamageMulti > 0 and globalOutput.AncestralCallDamageMultiplier or 0), s_format("x %.2f) ^8(ancestral call uptime ratio)", globalOutput.AncestralCallUptimeRatio / 100 or 0), s_format("= %.2f", globalOutput.AvgAncestralCallDamageEffect), } end - globalOutput.MaxAncestralCallDamageEffect = ancestrallyBoostedIncDamageMulti + globalOutput.MaxAncestralCallDamageEffect = 1 + ancestrallyBoostedIncDamageMulti if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output.AncestralCallDamageEffect = globalOutput.MaxAncestralCallDamageEffect skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max Ancestral Call Boosted AoE") From 8b4a161b3646fa353531fbf1782dbed41cc8cdda Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 12 May 2026 09:17:41 -0500 Subject: [PATCH 03/19] big ole refactor so we stop duplicating code one commit so I can revert if it goes boom --- src/Modules/CalcOffence.lua | 93 +++++++++++++++---------------------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 5e5c23a088..bae75d7b49 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3366,40 +3366,52 @@ function calcs.offence(env, actor, activeSkill) skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) end - globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 - -- If Fist of War & Active Skill is a Slam Skill & NOT a Vaal Skill & NOT used by mirage or other - if globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then - globalOutput.FistOfWarDamageMultiplier = skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100 - globalOutput.FistOfWarUptimeRatio = m_min( (1 / globalOutput.Speed) / globalOutput.FistOfWarCooldown, 1) * 100 + -- dynamic way of calcing the Ancestral Boost for supports without duplicating the code for each unique support + local function calcAncestralBoost(skillName, moreDmg, moreArea) + local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar + local skillNameLabel = skillName:lower() + + if moreDmg then + globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg * (1 + ancestrallyBoostedIncDamageMulti) + else + globalOutput[skillNameVar.."DamageMultiplier"] = ancestrallyBoostedIncDamageMulti + end + globalOutput[skillNameVar.."UptimeRatio"] = m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 if globalBreakdown then - globalBreakdown.FistOfWarUptimeRatio = { + globalBreakdown[skillNameVar.."UptimeRatio"] = { s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), - s_format("/ %.2f, 1) ^8(fist of war cooldown)", globalOutput.FistOfWarCooldown), - s_format("= %d%%", globalOutput.FistOfWarUptimeRatio), + s_format("/ %.2f, 1) ^8("..skillNameLabel.." cooldown)", globalOutput[skillNameVar.."Cooldown"]), + s_format("= %d%%", globalOutput[skillNameVar.."UptimeRatio"]), } end - globalOutput.AvgFistOfWarDamage = globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncDamageMulti - globalOutput.AvgFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncDamageMulti * (globalOutput.FistOfWarUptimeRatio / 100) + globalOutput["Avg"..skillNameVar.."Damage"] = globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput["Avg"..skillNameVar.."DamageEffect"] = 1 + globalOutput["Avg"..skillNameVar.."Damage"] * (globalOutput[skillNameVar.."UptimeRatio"] / 100) if globalBreakdown then - globalBreakdown.AvgFistOfWarDamageEffect = { - s_format("1 + (%.2f ^8(fist of war damage multiplier)", globalOutput.FistOfWarDamageMultiplier), - s_format("x %.2f) ^8(fist of war uptime ratio)", globalOutput.FistOfWarUptimeRatio / 100), - s_format("= %.2f", globalOutput.AvgFistOfWarDamageEffect), + globalBreakdown["Avg"..skillNameVar.."DamageEffect"] = { + s_format("1 + (%.2f ^8("..skillNameLabel.." damage multiplier)", globalOutput[skillNameVar.."DamageMultiplier"]), + s_format("x %.2f) ^8("..skillNameLabel.." uptime ratio)", globalOutput[skillNameVar.."UptimeRatio"] / 100), + s_format("= %.2f", globalOutput["Avg"..skillNameVar.."DamageEffect"]), } end - globalOutput.MaxFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * ancestrallyBoostedIncArea + globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - output.FistOfWarDamageEffect = globalOutput.MaxFistOfWarDamageEffect - skillModList:NewMod("AreaOfEffect", "MORE", skillModList:Sum("BASE", nil, "FistOfWarMOREAoE"), "Max Fist of War Boosted AoE") - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max Fist of War Boosted AoE") + output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] + skillModList:NewMod("AreaOfEffect", "MORE", moreArea or 0, "Max "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") else - output.FistOfWarDamageEffect = globalOutput.AvgFistOfWarDamageEffect - skillModList:NewMod("AreaOfEffect", "MORE", m_floor(skillModList:Sum("BASE", nil, "FistOfWarMOREAoE") * globalOutput.FistOfWarUptimeRatio / 100), "Avg Fist Of War Boosted AoE") - skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput.FistOfWarUptimeRatio / 100), "Avg Fist Of War Boosted AoE") + output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] + skillModList:NewMod("AreaOfEffect", "MORE", m_floor((moreArea or 0) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) - globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput.AvgFistOfWarDamageEffect - globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput.MaxFistOfWarDamageEffect + globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] + globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput["Max"..skillNameVar.."DamageEffect"] + end + + globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 + -- If Fist of War & Active Skill is a Slam Skill & NOT a Vaal Skill & NOT used by mirage or other + if globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then + calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarMOREAoE")) else output.FistOfWarDamageEffect = 1 end @@ -3409,39 +3421,8 @@ function calcs.offence(env, actor, activeSkill) if globalOutput.AncestralCallCooldown ~= 0 and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] and not activeSkill.skillTypes[SkillType.Channel] then globalOutput.AncestralCallAdditionalStrike = skillModList:Sum("BASE", nil, "AncestralCallAdditionalStrike") skillModList:NewMod("AdditionalStrikeTarget", "BASE", globalOutput.AncestralCallAdditionalStrike, "Ancestral Call when Ancestrally Boosted") - - globalOutput.AncestralCallDamageMultiplier = ancestrallyBoostedIncDamageMulti - globalOutput.AncestralCallUptimeRatio = m_min( (1 / globalOutput.Speed) / globalOutput.AncestralCallCooldown, 1) * 100 - if globalBreakdown then - globalBreakdown.AncestralCallUptimeRatio = { - s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), - s_format("/ %.2f, 1) ^8(ancestral call cooldown)", globalOutput.AncestralCallCooldown), - s_format("= %d%%", globalOutput.AncestralCallUptimeRatio), - } - end - globalOutput.AvgAncestralCallDamage = globalOutput.AncestralCallDamageMultiplier - globalOutput.AvgAncestralCallDamageEffect = 1 - if ancestrallyBoostedIncDamageMulti > 0 then -- if there is no increased damage, then Ancestrally Boosted Strikes do not have any damage portion - globalOutput.AvgAncestralCallDamageEffect = 1 + ancestrallyBoostedIncDamageMulti * (globalOutput.AncestralCallUptimeRatio / 100) - end - if globalBreakdown then - globalBreakdown.AvgAncestralCallDamageEffect = { - s_format("1 + (%.2f ^8(ancestral call damage multiplier)", ancestrallyBoostedIncDamageMulti > 0 and globalOutput.AncestralCallDamageMultiplier or 0), - s_format("x %.2f) ^8(ancestral call uptime ratio)", globalOutput.AncestralCallUptimeRatio / 100 or 0), - s_format("= %.2f", globalOutput.AvgAncestralCallDamageEffect), - } - end - globalOutput.MaxAncestralCallDamageEffect = 1 + ancestrallyBoostedIncDamageMulti - if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - output.AncestralCallDamageEffect = globalOutput.MaxAncestralCallDamageEffect - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max Ancestral Call Boosted AoE") - else - output.AncestralCallDamageEffect = globalOutput.AvgAncestralCallDamageEffect - skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput.AncestralCallUptimeRatio / 100), "Avg Ancestral Call Boosted AoE") - end - calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) - globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput.AvgAncestralCallDamageEffect - globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput.MaxAncestralCallDamageEffect + -- for special cases, the logic ^ can be done outside the generic calc + calcAncestralBoost("Ancestral Call") else output.AncestralCallDamageEffect = 1 end From 06f5dec603524df0996ac115695dde0b971d197a Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 12 May 2026 09:58:07 -0500 Subject: [PATCH 04/19] added test update CalcSection from "Exerted Warcries" to "Ancestral Boosts" --- spec/System/TestSkills_spec.lua | 17 +++++++++++++++++ src/Modules/CalcOffence.lua | 1 + src/Modules/CalcSections.lua | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index 99379fa2d8..749d14b147 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -382,4 +382,21 @@ describe("TestSkills", function() runCallback("OnFrame") assert.True(build.calcsTab.mainOutput.TotalDPS > iceShotDPS) end) + + it("Test Ancestral Call - Ancestral Boost calcs", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Fanatic Greathammer + Quality: 0 + ]]) + build.itemsTab:AddDisplayItem() + runCallback("OnFrame") + + build.skillsTab:PasteSocketGroup("Boneshatter 20/0 1\nAncestral Call I 1/0 1") + runCallback("OnFrame") + + assert.True(build.calcsTab.calcsOutput.AvgAncestralCallDamageEffect ~= nil) + assert.True(build.calcsTab.calcsOutput.AncestralCallUptimeRatio ~= nil) + assert.are.equal(3, build.calcsTab.calcsOutput.StrikeTargets) + end) end) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index bae75d7b49..ecfd552b54 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3368,6 +3368,7 @@ function calcs.offence(env, actor, activeSkill) -- dynamic way of calcing the Ancestral Boost for supports without duplicating the code for each unique support local function calcAncestralBoost(skillName, moreDmg, moreArea) + globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 5bc20f1ef0..b4687e679d 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -355,7 +355,7 @@ return { { label = "Skill DPS", flag = "triggered", { format = "{1:output:TotalDPS}", { breakdown = "TotalDPS" }, { label = "DPS Multiplier", modName = "DPS", cfg = "skill" }, }, }, } } } }, -{ 3, "Warcries", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Exerting Warcries", data = { +{ 3, "Warcries", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Ancestral Boosts", data = { extra = "{2:output:TheoreticalOffensiveWarcryEffect} Avg Combined Impact | {2:output:TheoreticalMaxOffensiveWarcryEffect} Max Combined Impact", colWidth = 114, { From 25f4ba52ae7e48936dfc05d6df6cf4361c8da943 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 12 May 2026 10:16:40 -0500 Subject: [PATCH 05/19] add data map for gemName given a modSource --- src/Modules/CalcOffence.lua | 2 +- src/Modules/Data.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index ecfd552b54..c50edd6c19 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3362,7 +3362,7 @@ function calcs.offence(env, actor, activeSkill) -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree - local sourceName = "Ancestral Boost - "..modSource:match("Support(.-)Player") -- crude way to grab Support name, there may be a way in data now or a way to create a map in data with the above structured key + local sourceName = "Ancestral Boost - "..data.gemNameForModSource[modSource] skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) end diff --git a/src/Modules/Data.lua b/src/Modules/Data.lua index 340d528619..3295b0e688 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -890,6 +890,7 @@ data.gems = LoadModule("Data/Gems") data.gemForSkill = { } data.gemForBaseName = { } data.gemsByGameId = { } +data.gemNameForModSource = { } -- Lookup table - [Gem.grantedEffectId] = VaalGemId data.gemGrantedEffectIdForVaalGemId = { } data.gemVaalGemIdForBaseGemId = { } @@ -899,6 +900,7 @@ local function setupGem(gem, gemId) data.gemForSkill[gem.grantedEffect] = gemId data.gemsByGameId[gem.gameId] = data.gemsByGameId[gem.gameId] or {} data.gemsByGameId[gem.gameId][gem.variantId] = gem + data.gemNameForModSource[gem.grantedEffect.modSource] = gem.name local baseName = gem.name if gem.grantedEffect.support and gem.grantedEffectId ~= "SupportBarrage" then baseName = baseName .. " Support" From d4f5dd646d95ea665bb5a98c9e1e11e0227d38e9 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 12:29:15 -0500 Subject: [PATCH 06/19] boosted attacks configOption --- src/Modules/ConfigOptions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index b148d9a4a5..47ddf2466a 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -193,7 +193,7 @@ local configSettings = { modList:NewMod("Condition:ArmourAvg", "FLAG", true, "Config") end end }, - { var = "warcryMode", type = "list", label = "Exerted/Boosted calc mode:", ifSkill = { "Fist of War", "Infernal Cry", "Ancestral Cry", "Enduring Cry", "General's Cry", "Intimidating Cry", "Rallying Cry", "Seismic Cry", "Battlemage's Cry", "Vengeful Cry" }, tooltip = "Controls how exerted attacks from Warcries are calculated:\nAverage: Averages out Warcry usage with cast time, attack speed and warcry cooldown.\nMax Hit: Shows maximum hit for lining up all warcries.", list = {{val="AVERAGE",label="Average"},{val="MAX",label="Max Hit"}}, apply = function(val, modList, enemyModList) + { var = "warcryMode", type = "list", label = "Boosted calc mode:", tooltip = "Controls how ancestrally boosted attacks are calculated:\nAverage: Averages out Boost usage with cast time, attack speed and cooldown.\nMax Hit: Shows maximum hit for lining up all sources of ancestral boost.", list = {{val="AVERAGE",label="Average"},{val="MAX",label="Max Hit"}}, apply = function(val, modList, enemyModList) if val == "MAX" then modList:NewMod("Condition:WarcryMaxHit", "FLAG", true, "Config") end From b8b1104f13c0aa96d816a7b7709aa785fad25749 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 14:12:36 -0500 Subject: [PATCH 07/19] add support for Ancestral Empowerment, including combining Ancestral Empowerment with Fist of War fix Fist of War/ancestrally boosted slams more AOE to inc AOE add test for Combined logic for Ancestral Empowerment and Fist of War --- spec/System/TestSkills_spec.lua | 38 +++++++++++++ src/Data/ModCache.lua | 2 +- src/Data/Skills/sup_str.lua | 6 +- src/Export/Skills/sup_str.txt | 6 +- src/Modules/CalcOffence.lua | 97 +++++++++++++++++++++++++++++---- src/Modules/CalcSections.lua | 14 +++++ src/Modules/ModParser.lua | 5 ++ 7 files changed, 149 insertions(+), 19 deletions(-) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index 749d14b147..4c191c93ce 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -399,4 +399,42 @@ describe("TestSkills", function() assert.True(build.calcsTab.calcsOutput.AncestralCallUptimeRatio ~= nil) assert.are.equal(3, build.calcsTab.calcsOutput.StrikeTargets) end) + + it("Test Combined Ancestral Boosts - Ancestral Empowerment and Fist of War", function() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Fanatic Greathammer + Quality: 0 + ]]) + build.itemsTab:AddDisplayItem() + runCallback("OnFrame") + build.skillsTab:PasteSocketGroup("Leap Slam 20/0 1\nFist of War I 1/0 1") + runCallback("OnFrame") + build.configTab.input.customMods = "every second slam skill you use yourself is ancestrally boosted" + build.configTab:BuildModList() + runCallback("OnFrame") + local fistOfWarOneMaxDmgEffect = build.calcsTab.calcsOutput.MaxAncestralEmpowermentCombinedDamageEffect + + -- test that we are using the calcCombinedAncestralBoost function and the calcSection triggers are correct + assert.True(build.calcsTab.calcsOutput.AncestralEmpowermentCombinedUptimeRatio ~= nil) + assert.True(build.calcsTab.calcsOutput.AncestralEmpowermentUptimeRatio == nil) + assert.True(build.calcsTab.calcsOutput.FistOfWarUptimeRatio == nil) + + newBuild() + build.itemsTab:CreateDisplayItemFromRaw([[ + New Item + Fanatic Greathammer + Quality: 0 + ]]) + build.itemsTab:AddDisplayItem() + runCallback("OnFrame") + build.skillsTab:PasteSocketGroup("Leap Slam 20/0 1\nFist of War III 1/0 1") + runCallback("OnFrame") + build.configTab.input.customMods = "every second slam skill you use yourself is ancestrally boosted" + build.configTab:BuildModList() + runCallback("OnFrame") + + -- test doubled effects of Fist of War III with Ancestral Empowerment + assert.True(fistOfWarOneMaxDmgEffect < build.calcsTab.calcsOutput.MaxAncestralEmpowermentCombinedDamageEffect) + end) end) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index bcdfe19a54..7af0043821 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -4866,7 +4866,7 @@ c["Every Rage also grants 2% increased Stun Threshold"]={{[1]={[1]={type="Multip c["Every Rage also grants you 1% increased Minion Attack Speed"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=1,keywordFlags=0,name="Speed",type="INC",value=1}}}},nil} c["Every Rage also grants you 1% increased Minion Damage"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=0,keywordFlags=0,name="Damage",type="INC",value=1}}}},nil} c["Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area"]={nil,"Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area "} -c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={nil,"Every second Slam Skill you use yourself is Ancestrally Boosted "} +c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={{[1]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowerment",type="FLAG",value=true},[2]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowermentDamageMultiplier",type="BASE",value=30},[3]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowermentIncAoE",type="BASE",value=25}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 1 second"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 15 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 18 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 10f917c186..2c2ab2be76 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -3436,7 +3436,7 @@ skills["FistOfWarSupportPlayer"] = { }, baseMods = { mod("FistOfWarDamageMultiplier", "BASE", 30), - mod("FistOfWarMOREAoE", "BASE", 25), + mod("FistOfWarIncAoE", "BASE", 25), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, @@ -3477,7 +3477,7 @@ skills["FistOfWarSupportPlayerTwo"] = { }, baseMods = { mod("FistOfWarDamageMultiplier", "BASE", 30), - mod("FistOfWarMOREAoE", "BASE", 25), + mod("FistOfWarIncAoE", "BASE", 25), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, @@ -3521,7 +3521,7 @@ skills["FistOfWarSupportPlayerThree"] = { }, baseMods = { mod("FistOfWarDamageMultiplier", "BASE", 60), - mod("FistOfWarMOREAoE", "BASE", 50), + mod("FistOfWarIncAoE", "BASE", 50), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 54664f1bdf..9b4a6f715a 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -769,7 +769,7 @@ statMap = { }, }, #baseMod mod("FistOfWarDamageMultiplier", "BASE", 30) -#baseMod mod("FistOfWarMOREAoE", "BASE", 25) +#baseMod mod("FistOfWarIncAoE", "BASE", 25) #mods #skillEnd @@ -782,7 +782,7 @@ statMap = { }, }, #baseMod mod("FistOfWarDamageMultiplier", "BASE", 30) -#baseMod mod("FistOfWarMOREAoE", "BASE", 25) +#baseMod mod("FistOfWarIncAoE", "BASE", 25) #mods #skillEnd @@ -798,7 +798,7 @@ statMap = { }, }, #baseMod mod("FistOfWarDamageMultiplier", "BASE", 60) -#baseMod mod("FistOfWarMOREAoE", "BASE", 50) +#baseMod mod("FistOfWarIncAoE", "BASE", 50) #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index c50edd6c19..f52ed03e79 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3338,6 +3338,8 @@ function calcs.offence(env, actor, activeSkill) output.FistOfWarDamageEffect = 1 output.AncestralCallDamageEffect = 1 + output.AncestralEmpowermentDamageEffect = 1 + output.AncestralEmpowermentCombinedDamageEffect = 1 if env.mode_combat then local ruthlessEffect = env.configInput.ruthlessSupportMode or "AVERAGE" local ruthlessBlowMaxCount = skillModList:Sum("BASE", cfg, "RuthlessBlowMaxCount") @@ -3366,8 +3368,9 @@ function calcs.offence(env, actor, activeSkill) skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) end - -- dynamic way of calcing the Ancestral Boost for supports without duplicating the code for each unique support - local function calcAncestralBoost(skillName, moreDmg, moreArea) + -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code + -- uptimeOverride: Ancestral Empowerment + local function calcAncestralBoost(skillName, moreDmg, incArea, uptimeOverride) globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() @@ -3377,11 +3380,11 @@ function calcs.offence(env, actor, activeSkill) else globalOutput[skillNameVar.."DamageMultiplier"] = ancestrallyBoostedIncDamageMulti end - globalOutput[skillNameVar.."UptimeRatio"] = m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 + globalOutput[skillNameVar.."UptimeRatio"] = uptimeOverride or m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 if globalBreakdown then globalBreakdown[skillNameVar.."UptimeRatio"] = { s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), - s_format("/ %.2f, 1) ^8("..skillNameLabel.." cooldown)", globalOutput[skillNameVar.."Cooldown"]), + s_format("/ %.2f, 1) ^8("..skillNameLabel.." cooldown)", uptimeOverride and (1 / globalOutput.Speed / (uptimeOverride / 100)) or globalOutput[skillNameVar.."Cooldown"]), s_format("= %d%%", globalOutput[skillNameVar.."UptimeRatio"]), } end @@ -3397,12 +3400,64 @@ function calcs.offence(env, actor, activeSkill) globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "MORE", moreArea or 0, "Max "..skillName.." Boosted AoE") - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", (incArea or 0) + ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "MORE", m_floor((moreArea or 0) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") - skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + end + calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) + globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] + globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput["Max"..skillNameVar.."DamageEffect"] + end + + -- combine Ancentral Empowerment with other sources of Slam Ancestral Boost, namely Fist of War, when both active + local function calcCombinedAncestralBoost(skillName, moreDmg, incArea, uptimeOverride, additionalSkillName) + globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection + local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar + local skillNameLabel = skillName:lower() + + if moreDmg then + globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg * (1 + ancestrallyBoostedIncDamageMulti) + else + globalOutput[skillNameVar.."DamageMultiplier"] = ancestrallyBoostedIncDamageMulti + end + -- for CalcSections, set the AncestralEmpowerment damage for mod breakdown + globalOutput[skillNameVar.."CombinedDamageMultiplier"] = globalOutput[skillNameVar.."DamageMultiplier"] + skillNameVar = skillNameVar.."Combined" + local additionalSkillNameVar = additionalSkillName:gsub(" ", "") + local additionalSkillNameLabel = additionalSkillName:lower() + + -- a lot of these are doubled up because it would be very long lines otherwise and hopefully this helps legibility + globalOutput[skillNameVar.."UptimeRatio"] = uptimeOverride or m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 + globalOutput[skillNameVar.."UptimeRatio"] = globalOutput[skillNameVar.."UptimeRatio"] + (globalOutput[additionalSkillNameVar.."UptimeRatio"] or 0) / 2 + if globalBreakdown then + globalBreakdown[skillNameVar.."UptimeRatio"] = { + s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), + s_format("/ %.2f, 1) ^8("..skillNameLabel.." cooldown)", uptimeOverride and (1 / globalOutput.Speed / (uptimeOverride / 100)) or globalOutput[skillNameVar.."Cooldown"]), + "+", + s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), + s_format("/ %.2f, 1) ^8("..additionalSkillNameLabel.." cooldown)", globalOutput[additionalSkillNameVar.."Cooldown"]), + s_format("= %d%%", globalOutput[skillNameVar.."UptimeRatio"]), + } + end + globalOutput["Avg"..skillNameVar.."Damage"] = globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput["Avg"..skillNameVar.."DamageEffect"] = 1 + globalOutput["Avg"..skillNameVar.."Damage"] * (uptimeOverride and uptimeOverride / 100 or (globalOutput[skillNameVar.."UptimeRatio"] / 100)) + globalOutput["Avg"..skillNameVar.."DamageEffect"] = (globalOutput["Avg"..skillNameVar.."DamageEffect"] * (1 + globalOutput["Avg"..additionalSkillNameVar.."Damage"] * globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2)) + if globalBreakdown then + globalBreakdown["Avg"..skillNameVar.."DamageEffect"] = { + s_format("1 + (%.2f x %.2f) ^8("..skillNameLabel.." damage multiplier x ^8"..skillNameLabel.." uptime ratio)", globalOutput[skillNameVar.."DamageMultiplier"], uptimeOverride / 100), + s_format(" + (%.2f x %.2f) ^8("..additionalSkillNameLabel.." damage multiplier x ^8"..additionalSkillNameLabel.." uptime ratio)", globalOutput[additionalSkillNameVar.."DamageMultiplier"], globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2), + s_format("= %.2f", globalOutput["Avg"..skillNameVar.."DamageEffect"]), + } + end + globalOutput["Avg"..skillNameVar.."Damage"] = globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput[additionalSkillNameVar.."DamageMultiplier"] + globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput[additionalSkillNameVar.."DamageMultiplier"] + if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then + output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] + skillModList:NewMod("AreaOfEffect", "INC", (incArea or 0) + ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") + else + output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] + skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3410,9 +3465,21 @@ function calcs.offence(env, actor, activeSkill) end globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 + if skillModList:Flag(cfg, "AncestralEmpowerment") and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then + if globalOutput.FistOfWarCooldown ~= 0 then -- get the fist of war calcs in output to use in Empowerment + calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE")) + globalOutput.TheoreticalOffensiveWarcryEffect = 1 -- reset effects from FistOfWar calc, we combine later + globalOutput.TheoreticalMaxOffensiveWarcryEffect = 1 + + calcCombinedAncestralBoost("Ancestral Empowerment", (skillModList:Sum("BASE", cfg, "AncestralEmpowermentDamageMultiplier") / 100), skillModList:Sum("BASE", cfg, "AncestralEmpowermentIncAoE"), 50, "Fist Of War") + globalOutput.FistOfWarUptimeRatio = nil -- hide from CalcSections, but we need it for the combined calc first + else + calcAncestralBoost("Ancestral Empowerment", (skillModList:Sum("BASE", cfg, "AncestralEmpowermentDamageMultiplier") / 100), skillModList:Sum("BASE", cfg, "AncestralEmpowermentIncAoE"), 50) + end + end -- If Fist of War & Active Skill is a Slam Skill & NOT a Vaal Skill & NOT used by mirage or other - if globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then - calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarMOREAoE")) + if not skillModList:Flag(cfg, "AncestralEmpowerment") and globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then + calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE")) else output.FistOfWarDamageEffect = 1 end @@ -3769,6 +3836,12 @@ function calcs.offence(env, actor, activeSkill) if output.AncestralCallDamageEffect ~= 1 then t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral call effect modifier)", output.AncestralCallDamageEffect)) end + if output.AncestralEmpowermentDamageEffect ~= 1 then + t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral empowerment effect modifier)", output.AncestralEmpowermentDamageEffect)) + end + if output.AncestralEmpowermentCombinedDamageEffect ~= 1 then + t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral empowerment + effect modifier)", output.AncestralEmpowermentCombinedDamageEffect)) + end if globalOutput.OffensiveWarcryEffect ~= 1 and not activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then t_insert(breakdown[damageType], s_format("x %.2f ^8(aggregated warcry exerted effect modifier)", globalOutput.OffensiveWarcryEffect)) end @@ -3777,9 +3850,9 @@ function calcs.offence(env, actor, activeSkill) end end if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * globalOutput.MaxOffensiveWarcryEffect + output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * output.AncestralEmpowermentDamageEffect * output.AncestralEmpowermentCombinedDamageEffect * globalOutput.MaxOffensiveWarcryEffect else - output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * globalOutput.OffensiveWarcryEffect + output.allMult = output.ScaledDamageEffect * output.FistOfWarDamageEffect * output.AncestralCallDamageEffect * output.AncestralEmpowermentDamageEffect * output.AncestralEmpowermentCombinedDamageEffect * globalOutput.OffensiveWarcryEffect end local allMult = output.allMult if pass == 1 then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index b4687e679d..5862357a56 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -415,6 +415,20 @@ return { { format = "" }, { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, }, + { label = "Ancest. Empower +", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", + { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, + { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, + { format = "" }, + { format = "{2:output:MaxAncestralEmpowermentCombinedDamageEffect}" }, + }, + { label = "Anc. Empowerment", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentUptimeRatio", + { format = "{2:output:AvgAncestralEmpowermentDamageEffect}", { breakdown = "AvgAncestralEmpowermentDamageEffect"}, }, + { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{0:output:AncestralEmpowermentUptimeRatio}%", { breakdown = "AncestralEmpowermentUptimeRatio" }, }, + { format = "" }, + { format = "{2:output:MaxAncestralEmpowermentDamageEffect}" }, + }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 51dabe6cc4..c64b9c7d6c 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2625,6 +2625,11 @@ local specialModList = { -- Ancestrally Boosted ["ancestrally boosted attacks deal (%d+)%% increased damage"] = function(num) return { mod("AncestralBoostDamage", "INC", num, nil, ModFlag.Attack, 0) } end, ["(%d+)%% increased area of effect of ancestrally boosted attacks"] = function(num) return { mod("AncestralBoostAreaOfEffect", "INC", num, nil, ModFlag.Attack, 0) } end, + ["every second slam skill you use yourself is ancestrally boosted"] = { + flag("AncestralEmpowerment", { type = "SkillType", skillType = SkillType.Slam }), + mod("AncestralEmpowermentDamageMultiplier", "BASE", 30, { type = "SkillType", skillType = SkillType.Slam }), + mod("AncestralEmpowermentIncAoE", "BASE", 25, { type = "SkillType", skillType = SkillType.Slam }), + }, -- Leech Related ["life leech is instant"] = { mod("InstantLifeLeech", "BASE", 100), }, ["mana leech is instant"] = { mod("InstantManaLeech", "BASE", 100), }, From 44d3424942b62da006f431edddab6a1cd7768938 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 14:25:26 -0500 Subject: [PATCH 08/19] comment spelling --- src/Modules/CalcOffence.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index f52ed03e79..66c928ca75 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3410,7 +3410,7 @@ function calcs.offence(env, actor, activeSkill) globalOutput.TheoreticalMaxOffensiveWarcryEffect = globalOutput.TheoreticalMaxOffensiveWarcryEffect * globalOutput["Max"..skillNameVar.."DamageEffect"] end - -- combine Ancentral Empowerment with other sources of Slam Ancestral Boost, namely Fist of War, when both active + -- combine Ancestral Empowerment with other sources of Slam Ancestral Boost, namely Fist of War, when both active local function calcCombinedAncestralBoost(skillName, moreDmg, incArea, uptimeOverride, additionalSkillName) globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar From 1abbaa1f6c4e46fb3a0c99b153687fbbab856071 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 20:07:26 -0500 Subject: [PATCH 09/19] better label --- src/Modules/CalcSections.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 5862357a56..312d4bea9e 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -415,7 +415,7 @@ return { { format = "" }, { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, }, - { label = "Ancest. Empower +", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", + { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, }, { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, From 99d7ea74e3aa08449e1de8dbe973931793857914 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 20:35:41 -0500 Subject: [PATCH 10/19] fix avg aoe from fist of war --- src/Modules/CalcOffence.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 66c928ca75..7f3ccdae7a 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3370,7 +3370,8 @@ function calcs.offence(env, actor, activeSkill) -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code -- uptimeOverride: Ancestral Empowerment - local function calcAncestralBoost(skillName, moreDmg, incArea, uptimeOverride) + -- combinedCalcs: ignore INC AoE as we will run that in calcCombinedAncestralBoost + local function calcAncestralBoost(skillName, moreDmg, incArea, uptimeOverride, combinedCalcs) globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() @@ -3403,7 +3404,9 @@ function calcs.offence(env, actor, activeSkill) skillModList:NewMod("AreaOfEffect", "INC", (incArea or 0) + ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + if not combinedCalcs then + skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + end end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3458,6 +3461,7 @@ function calcs.offence(env, actor, activeSkill) else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2), "Avg "..additionalSkillName.." Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3467,7 +3471,7 @@ function calcs.offence(env, actor, activeSkill) globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 if skillModList:Flag(cfg, "AncestralEmpowerment") and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then if globalOutput.FistOfWarCooldown ~= 0 then -- get the fist of war calcs in output to use in Empowerment - calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE")) + calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE"), nil, true) globalOutput.TheoreticalOffensiveWarcryEffect = 1 -- reset effects from FistOfWar calc, we combine later globalOutput.TheoreticalMaxOffensiveWarcryEffect = 1 From dcf59422729d867ba6c1764d4704adc7a3c6bba9 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Fri, 15 May 2026 21:45:16 -0500 Subject: [PATCH 11/19] forgot AOE portion for Crescendo III --- src/Modules/CalcOffence.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 7f3ccdae7a..3358d8de60 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3366,6 +3366,8 @@ function calcs.offence(env, actor, activeSkill) local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree local sourceName = "Ancestral Boost - "..data.gemNameForModSource[modSource] skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, sourceName, { type = "Condition", var = "FinalStrike" }) + calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) end -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code From 04f89c8c5eed2bb68adde39097f07fce6b43f02e Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Thu, 21 May 2026 02:15:17 -0500 Subject: [PATCH 12/19] add support for Infernal Cry's empowered buff --- src/Data/SkillStatMap.lua | 6 ++++++ src/Data/Skills/act_str.lua | 5 +++++ src/Export/Skills/act_str.txt | 5 +++++ src/Modules/CalcOffence.lua | 25 +++++++++++++------------ src/Modules/CalcPerform.lua | 4 +++- src/Modules/CalcSections.lua | 24 ++++++++++++------------ src/Modules/CalcTriggers.lua | 2 +- 7 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 67493c6200..984eef1230 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -586,6 +586,12 @@ return { ["warcry_speed_+%"] = { mod("WarcrySpeed", "INC", nil, 0, KeywordFlag.Warcry), }, +["warcry_empowers_per_X_monster_power_mp_cap"] = { + mod("WarcryPowerCap", "BASE", nil), +}, +["warcry_empowers_per_X_monster_power"] = { + mod("WarcryPowerPer", "BASE", nil), +}, ["display_this_skill_cooldown_does_not_recover_during_buff"] = { flag("NoCooldownRecoveryInDuration"), }, diff --git a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua index 23d10619e6..65d76e141c 100644 --- a/src/Data/Skills/act_str.lua +++ b/src/Data/Skills/act_str.lua @@ -7500,6 +7500,11 @@ skills["InfernalCryPlayer"] = { label = "Infernal Cry", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "infernal_cry", + statMap = { + ["infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%"] = { + mod("DamageGainAsFire", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Warcry" }, { type = "Condition", var = "Empowered" }), + }, + }, baseFlags = { warcry = true, area = true, diff --git a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt index c2c2b7c9aa..74ea3e0622 100644 --- a/src/Export/Skills/act_str.txt +++ b/src/Export/Skills/act_str.txt @@ -481,6 +481,11 @@ statMap = { #skill InfernalCryPlayer #set InfernalCryPlayer #flags warcry area duration +statMap = { + ["infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%"] = { + mod("DamageGainAsFire", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Warcry" }, { type = "Condition", var = "Empowered" }), + }, +}, #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 3358d8de60..d34fba141a 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3104,26 +3104,27 @@ function calcs.offence(env, actor, activeSkill) end globalOutput.AncestralCryCalculated = true elseif value.activeEffect.grantedEffect.name == "Infernal Cry" and not globalOutput.InfernalCryCalculated then + globalOutput.CreateWarcryOffensiveCalcSection = true globalOutput.InfernalCryDuration = calcSkillDuration(value.skillModList, value.skillCfg, value.skillData, env, enemyDB) globalOutput.InfernalCryCooldown = calcSkillCooldown(value.skillModList, value.skillCfg, value.skillData) globalOutput.InfernalCryCastTime = calcWarcryCastTime(value.skillModList, value.skillCfg, value.skillData, actor) if activeSkill.skillTypes[SkillType.Melee] then - globalOutput.InfernalExertsCount = env.modDB:Sum("BASE", nil, "NumInfernalExerts") or 0 - local baseUptimeRatio = m_min((globalOutput.InfernalExertsCount / globalOutput.Speed) / (globalOutput.InfernalCryCooldown + globalOutput.InfernalCryCastTime), 1) * 100 + globalOutput.InfernalEmpoweredCount = (modDB:Override(nil, "WarcryPower") or value.skillModList:Sum("BASE", nil, "WarcryPowerCap")) / value.skillModList:Sum("BASE", nil, "WarcryPowerPer") + local baseUptimeRatio = m_min((globalOutput.InfernalEmpoweredCount / globalOutput.Speed) / (globalOutput.InfernalCryCooldown + globalOutput.InfernalCryCastTime), 1) * 100 local storedUses = value.skillData.storedUses or 0 + value.skillModList:Sum("BASE", value.skillCfg, "AdditionalCooldownUses") - globalOutput.InfernalUpTimeRatio = m_min(100, baseUptimeRatio * storedUses) - globalOutput.GlobalWarcryUptimeRatio = globalOutput.GlobalWarcryUptimeRatio + globalOutput.InfernalUpTimeRatio + globalOutput.InfernalCryUptimeRatio = m_min(100, baseUptimeRatio * storedUses) + globalOutput.GlobalWarcryUptimeRatio = globalOutput.GlobalWarcryUptimeRatio + globalOutput.InfernalCryUptimeRatio if globalBreakdown then - globalBreakdown.InfernalUpTimeRatio = { } - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("(%d ^8(number of exerts)", globalOutput.InfernalExertsCount)) - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("/ %.2f) ^8(attacks per second)", globalOutput.Speed)) + globalBreakdown.InfernalCryUptimeRatio = { } + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("(%.2f ^8(number of empowered)", globalOutput.InfernalEmpoweredCount)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f) ^8(attacks per second)", globalOutput.Speed)) if globalOutput.InfernalCryCastTime > 0 then - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("/ (%.2f ^8(warcry cooldown)", globalOutput.InfernalCryCooldown)) - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("+ %.2f) ^8(warcry casttime)", globalOutput.InfernalCryCastTime)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ (%.2f ^8(warcry cooldown)", globalOutput.InfernalCryCooldown)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("+ %.2f) ^8(warcry cast time)", globalOutput.InfernalCryCastTime)) else - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("/ %.2f ^8(average warcry cooldown)", globalOutput.InfernalCryCooldown)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f ^8(average warcry cooldown)", globalOutput.InfernalCryCooldown)) end - t_insert(globalBreakdown.InfernalUpTimeRatio, s_format("= %d%%", globalOutput.InfernalUpTimeRatio)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("= %d%%", globalOutput.InfernalCryUptimeRatio)) end end globalOutput.InfernalCryCalculated = true @@ -3287,7 +3288,7 @@ function calcs.offence(env, actor, activeSkill) -- Calculate Exerted Attack Uptime -- There are various strategies a player could use to maximize either warcry effect stacking or staggering -- 1) they don't pay attention and therefore we calculated exerted attack uptime as just the maximum uptime of any enabled warcries that exert attacks - local warcryList = {"AncestralUpTimeRatio", "InfernalUpTimeRatio", "IntimidatingUpTimeRatio", "RallyingUpTimeRatio", "SeismicUpTimeRatio", "BattlemageUpTimeRatio"} + local warcryList = {"AncestralUpTimeRatio", "InfernalCryUptimeRatio", "IntimidatingUpTimeRatio", "RallyingUpTimeRatio", "SeismicUpTimeRatio", "BattlemageUpTimeRatio"} for _, cryTimeRatio in ipairs(warcryList) do globalOutput.ExertedAttackUptimeRatio = m_max(globalOutput.ExertedAttackUptimeRatio or 0, globalOutput[cryTimeRatio] or 0) end diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index ee090a7c65..d32db5b79e 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1919,7 +1919,9 @@ function calcs.perform(env, skipEHP) end local full_duration = calcSkillDuration(modStore, skillCfg, activeSkill.skillData, env, enemyDB) local actual_cooldown = calcSkillCooldown(modStore, skillCfg, activeSkill.skillData) - local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or m_min(full_duration / actual_cooldown, 1) + -- need to scale warcry buffs by their actual uptime + local warcryOutputUptime = env.build.calcsTab.mainOutput and (env.build.calcsTab.mainOutput[warcryName.."CryUptimeRatio"] / 100) or nil + local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or warcryOutputUptime or m_min(full_duration / actual_cooldown, 1) local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList") or {} if not modDB:Flag(nil, "CannotGainWarcryBuffs") then if not buff.applyNotPlayer then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 312d4bea9e..967ac4ba65 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -355,7 +355,7 @@ return { { label = "Skill DPS", flag = "triggered", { format = "{1:output:TotalDPS}", { breakdown = "TotalDPS" }, { label = "DPS Multiplier", modName = "DPS", cfg = "skill" }, }, }, } } } }, -{ 3, "Warcries", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Ancestral Boosts", data = { +{ 3, "Warcries", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Empowered Stats", data = { extra = "{2:output:TheoreticalOffensiveWarcryEffect} Avg Combined Impact | {2:output:TheoreticalMaxOffensiveWarcryEffect} Max Combined Impact", colWidth = 114, { @@ -363,7 +363,7 @@ return { { format = "Effective Impact" }, { format = "Avg Dmg Effect" }, { format = "Uptime" }, - { format = "Number of Exerts" }, + { format = "# of Empowered" }, { format = "Max 1-Hit Impact"}, }, { label = "Seismic Cry", haveOutput = "SeismicUpTimeRatio", @@ -387,11 +387,11 @@ return { { format = "{0:output:RallyingExertsCount}" }, { format = "{2:output:RallyingMaxHitEffect}" }, }, - { label = "Infernal Cry", haveOutput = "InfernalUpTimeRatio", + { label = "Infernal Cry", haveOutput = "InfernalCryUptimeRatio", { format = "" }, { format = "" }, - { format = "{0:output:InfernalUpTimeRatio}%", { breakdown = "InfernalUpTimeRatio" }, }, - { format = "{0:output:InfernalExertsCount}" }, + { format = "{0:output:InfernalCryUptimeRatio}%", { breakdown = "InfernalCryUptimeRatio" }, }, + { format = "{0:output:InfernalEmpoweredCount}" }, { format = "" }, }, { label = "Battlemage's Cry", haveOutput = "BattlemageUpTimeRatio", @@ -408,13 +408,13 @@ return { { format = "{0:output:AncestralExertsCount}" }, { format = "" }, }, - { label = "Exerted Attacks", bgCol = colorCodes.MAINHANDBG, haveOutput = "ExertedAttackUptimeRatio", - { format = "{2:output:ExertedAttackHitEffect}", { breakdown = "ExertedAttackHitEffect"}, }, - { format = "{2:output:ExertedAttackAvgDmg}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, - { format = "{0:output:ExertedAttackUptimeRatio}%", { breakdown = "ExertedAttackUptimeRatio" }, }, - { format = "" }, - { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, - }, + --{ label = "Exerted Attacks", bgCol = colorCodes.MAINHANDBG, haveOutput = "ExertedAttackUptimeRatio", + -- { format = "{2:output:ExertedAttackHitEffect}", { breakdown = "ExertedAttackHitEffect"}, }, + -- { format = "{2:output:ExertedAttackAvgDmg}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, + -- { format = "{0:output:ExertedAttackUptimeRatio}%", { breakdown = "ExertedAttackUptimeRatio" }, }, + -- { format = "" }, + -- { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, + --}, { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, }, diff --git a/src/Modules/CalcTriggers.lua b/src/Modules/CalcTriggers.lua index 35fab416f8..639ed69419 100644 --- a/src/Modules/CalcTriggers.lua +++ b/src/Modules/CalcTriggers.lua @@ -489,7 +489,7 @@ local function defaultTriggerHandler(env, config) -- Infernal Cry uptime if actor.mainSkill.activeEffect.grantedEffect.name == "Combust" and GlobalCache.cachedData[env.mode][uuid] and source and source.skillTypes[SkillType.Melee] then - local infernalCryExertsCount = GlobalCache.cachedData[env.mode][uuid].Env.player.output.InfernalExertsCount + local infernalCryExertsCount = GlobalCache.cachedData[env.mode][uuid].Env.player.output.InfernalEmpoweredCount local infernalCryDuration = ceil_b(GlobalCache.cachedData[env.mode][uuid].Env.player.output.InfernalCryDuration, data.misc.ServerTickTime) local infernalCryCastTime = GlobalCache.cachedData[env.mode][uuid].Env.player.output.InfernalCryCastTime local infernalCryCooldown = ceil_b(GlobalCache.cachedData[env.mode][uuid].Env.player.output.InfernalCryCooldown, data.misc.ServerTickTime) From 7084c054fed3e43a6f95bdbdfe2076bc98519eb4 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Tue, 26 May 2026 13:27:48 -0500 Subject: [PATCH 13/19] refactor away from specific baseMod for FistOfWar fix Ancestral Empowerment not getting the double from fist of war III --- src/Data/ModCache.lua | 2 +- src/Data/Skills/sup_str.lua | 13 +++++-------- src/Export/Skills/sup_str.txt | 13 +++++-------- src/Modules/CalcOffence.lua | 32 ++++++++++++++++---------------- src/Modules/CalcPerform.lua | 2 +- src/Modules/CalcSections.lua | 6 +++--- src/Modules/CalcSetup.lua | 7 +++++++ src/Modules/ModParser.lua | 3 +-- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 154612404b..95ba6feef0 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -4921,7 +4921,7 @@ c["Every Rage also grants 2% increased Stun Threshold"]={{[1]={[1]={type="Multip c["Every Rage also grants you 1% increased Minion Attack Speed"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=1,keywordFlags=0,name="Speed",type="INC",value=1}}}},nil} c["Every Rage also grants you 1% increased Minion Damage"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=0,keywordFlags=0,name="Damage",type="INC",value=1}}}},nil} c["Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area"]={nil,"Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area "} -c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={{[1]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowerment",type="FLAG",value=true},[2]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowermentDamageMultiplier",type="BASE",value=30},[3]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowermentIncAoE",type="BASE",value=25}},nil} +c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={{[1]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowerment",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="Condition:AncestrallyBoosted",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 1 second"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 15 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 18 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 0727e76a23..181a4a1f61 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -158,7 +158,7 @@ skills["SupportAncestralCallPlayer"] = { baseFlags = { }, baseMods = { - mod("AdditionalStrikeTarget", "BASE", 2), + flag("Condition:AncestrallyBoosted"), }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 5000 }, @@ -199,7 +199,7 @@ skills["SupportAncestralCallPlayerTwo"] = { baseFlags = { }, baseMods = { - mod("AdditionalStrikeTarget", "BASE", 2), + flag("Condition:AncestrallyBoosted"), }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 3000 }, @@ -3430,8 +3430,7 @@ skills["FistOfWarSupportPlayer"] = { baseFlags = { }, baseMods = { - mod("FistOfWarDamageMultiplier", "BASE", 30), - mod("FistOfWarIncAoE", "BASE", 25), + flag("Condition:AncestrallyBoosted"), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, @@ -3471,8 +3470,7 @@ skills["FistOfWarSupportPlayerTwo"] = { baseFlags = { }, baseMods = { - mod("FistOfWarDamageMultiplier", "BASE", 30), - mod("FistOfWarIncAoE", "BASE", 25), + flag("Condition:AncestrallyBoosted"), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, @@ -3515,8 +3513,7 @@ skills["FistOfWarSupportPlayerThree"] = { baseFlags = { }, baseMods = { - mod("FistOfWarDamageMultiplier", "BASE", 60), - mod("FistOfWarIncAoE", "BASE", 50), + flag("Condition:AncestrallyBoostedDouble"), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 518317cef4..7a9ca0d1ef 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -32,7 +32,7 @@ statMap = { div = 1000, }, }, -#baseMod mod("AdditionalStrikeTarget", "BASE", 2) +#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd @@ -44,7 +44,7 @@ statMap = { div = 1000, }, }, -#baseMod mod("AdditionalStrikeTarget", "BASE", 2) +#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd @@ -763,8 +763,7 @@ statMap = { div = 1000, }, }, -#baseMod mod("FistOfWarDamageMultiplier", "BASE", 30) -#baseMod mod("FistOfWarIncAoE", "BASE", 25) +#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd @@ -776,8 +775,7 @@ statMap = { div = 1000, }, }, -#baseMod mod("FistOfWarDamageMultiplier", "BASE", 30) -#baseMod mod("FistOfWarIncAoE", "BASE", 25) +#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd @@ -792,8 +790,7 @@ statMap = { -- Accounted for in base mod }, }, -#baseMod mod("FistOfWarDamageMultiplier", "BASE", 60) -#baseMod mod("FistOfWarIncAoE", "BASE", 50) +#baseMod flag("Condition:AncestrallyBoostedDouble") #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index fb44db19c8..d43f524322 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3383,8 +3383,12 @@ function calcs.offence(env, actor, activeSkill) -- passive nodes local ancestrallyBoostedIncDamageMulti = modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 - local ancestrallyBoostedIncArea = modDB:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + local ancestrallyBoostedIncArea = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + -- Condition:AncestrallyBoosted or Condition:AncestrallyBoostedDouble + local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 + -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense + -- for generic Ancestrally Boosted skills that have 100% uptime if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree local sourceName = "Ancestral Boost - "..data.gemNameForModSource[modSource] @@ -3396,7 +3400,7 @@ function calcs.offence(env, actor, activeSkill) -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code -- uptimeOverride: Ancestral Empowerment -- combinedCalcs: ignore INC AoE as we will run that in calcCombinedAncestralBoost - local function calcAncestralBoost(skillName, moreDmg, incArea, uptimeOverride, combinedCalcs) + local function calcAncestralBoost(skillName, moreDmg, uptimeOverride, combinedCalcs) globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() @@ -3426,11 +3430,11 @@ function calcs.offence(env, actor, activeSkill) globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", (incArea or 0) + ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] if not combinedCalcs then - skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") end end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) @@ -3439,7 +3443,7 @@ function calcs.offence(env, actor, activeSkill) end -- combine Ancestral Empowerment with other sources of Slam Ancestral Boost, namely Fist of War, when both active - local function calcCombinedAncestralBoost(skillName, moreDmg, incArea, uptimeOverride, additionalSkillName) + local function calcCombinedAncestralBoost(skillName, moreDmg, uptimeOverride, additionalSkillName) globalOutput.CreateWarcryOffensiveCalcSection = true -- labels for the CalcSection local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() @@ -3482,11 +3486,10 @@ function calcs.offence(env, actor, activeSkill) globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput[additionalSkillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", (incArea or 0) + ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Combined Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") - skillModList:NewMod("AreaOfEffect", "INC", m_floor(((incArea or 0) + ancestrallyBoostedIncArea) * globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2), "Avg "..additionalSkillName.." Boosted AoE") + skillModList:NewMod("AreaOfEffect", "INC", m_floor((ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Combined Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3496,19 +3499,19 @@ function calcs.offence(env, actor, activeSkill) globalOutput.FistOfWarCooldown = skillModList:Sum("BASE", cfg, "FistOfWarCooldown") or 0 if skillModList:Flag(cfg, "AncestralEmpowerment") and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then if globalOutput.FistOfWarCooldown ~= 0 then -- get the fist of war calcs in output to use in Empowerment - calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE"), nil, true) + calcAncestralBoost("Fist Of War", ancestrallyBoostedMoreDamageMulti, nil, true) globalOutput.TheoreticalOffensiveWarcryEffect = 1 -- reset effects from FistOfWar calc, we combine later globalOutput.TheoreticalMaxOffensiveWarcryEffect = 1 - calcCombinedAncestralBoost("Ancestral Empowerment", (skillModList:Sum("BASE", cfg, "AncestralEmpowermentDamageMultiplier") / 100), skillModList:Sum("BASE", cfg, "AncestralEmpowermentIncAoE"), 50, "Fist Of War") + calcCombinedAncestralBoost("Ancestral Empowerment", ancestrallyBoostedMoreDamageMulti, 50, "Fist Of War") globalOutput.FistOfWarUptimeRatio = nil -- hide from CalcSections, but we need it for the combined calc first else - calcAncestralBoost("Ancestral Empowerment", (skillModList:Sum("BASE", cfg, "AncestralEmpowermentDamageMultiplier") / 100), skillModList:Sum("BASE", cfg, "AncestralEmpowermentIncAoE"), 50) + calcAncestralBoost("Ancestral Empowerment", ancestrallyBoostedMoreDamageMulti, 50) end end -- If Fist of War & Active Skill is a Slam Skill & NOT a Vaal Skill & NOT used by mirage or other if not skillModList:Flag(cfg, "AncestralEmpowerment") and globalOutput.FistOfWarCooldown ~= 0 and activeSkill.skillTypes[SkillType.Slam] and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] then - calcAncestralBoost("Fist Of War", (skillModList:Sum("BASE", nil, "FistOfWarDamageMultiplier") / 100), skillModList:Sum("BASE", nil, "FistOfWarIncAoE")) + calcAncestralBoost("Fist Of War", ancestrallyBoostedMoreDamageMulti) else output.FistOfWarDamageEffect = 1 end @@ -3516,9 +3519,6 @@ function calcs.offence(env, actor, activeSkill) globalOutput.AncestralCallCooldown = skillModList:Sum("BASE", cfg, "AncestralCallCooldown") or 0 -- If Ancestral Call & Active Skill is NOT a Vaal Skill & NOT used by mirage or other & NOT a Channel Skill if globalOutput.AncestralCallCooldown ~= 0 and not activeSkill.skillTypes[SkillType.Vaal] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] and not activeSkill.skillTypes[SkillType.Channel] then - globalOutput.AncestralCallAdditionalStrike = skillModList:Sum("BASE", nil, "AncestralCallAdditionalStrike") - skillModList:NewMod("AdditionalStrikeTarget", "BASE", globalOutput.AncestralCallAdditionalStrike, "Ancestral Call when Ancestrally Boosted") - -- for special cases, the logic ^ can be done outside the generic calc calcAncestralBoost("Ancestral Call") else output.AncestralCallDamageEffect = 1 @@ -3869,7 +3869,7 @@ function calcs.offence(env, actor, activeSkill) t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral empowerment effect modifier)", output.AncestralEmpowermentDamageEffect)) end if output.AncestralEmpowermentCombinedDamageEffect ~= 1 then - t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral empowerment + effect modifier)", output.AncestralEmpowermentCombinedDamageEffect)) + t_insert(breakdown[damageType], s_format("x %.2f ^8(ancestral empowerment combined effect modifier)", output.AncestralEmpowermentCombinedDamageEffect)) end if globalOutput.OffensiveWarcryEffect ~= 1 and not activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then t_insert(breakdown[damageType], s_format("x %.2f ^8(aggregated warcry exerted effect modifier)", globalOutput.OffensiveWarcryEffect)) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 1b2f3097f0..38ae5b7228 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1991,7 +1991,7 @@ function calcs.perform(env, skipEHP) local full_duration = calcSkillDuration(modStore, skillCfg, activeSkill.skillData, env, enemyDB) local actual_cooldown = calcSkillCooldown(modStore, skillCfg, activeSkill.skillData) -- need to scale warcry buffs by their actual uptime - local warcryOutputUptime = env.build.calcsTab.mainOutput and (env.build.calcsTab.mainOutput[warcryName.."CryUptimeRatio"] / 100) or nil + local warcryOutputUptime = env.build.calcsTab.mainOutput and ((env.build.calcsTab.mainOutput[warcryName.."CryUptimeRatio"] or 0) / 100) or nil local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or warcryOutputUptime or m_min(full_duration / actual_cooldown, 1) local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList") or {} if not modDB:Flag(nil, "CannotGainWarcryBuffs") then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 635c92b56b..10aaf14249 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -417,21 +417,21 @@ return { --}, { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentCombinedDamageEffect}" }, }, { label = "Anc. Empowerment", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentDamageEffect}", { breakdown = "AvgAncestralEmpowermentDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" } }, { format = "{0:output:AncestralEmpowermentUptimeRatio}%", { breakdown = "AncestralEmpowermentUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentDamageEffect}" }, }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, - { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" } }, { format = "{0:output:FistOfWarUptimeRatio}%", { breakdown = "FistOfWarUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxFistOfWarDamageEffect}" }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 37cb1c3f2c..1efd78d3ea 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -668,6 +668,13 @@ function calcs.initEnv(build, mode, override, specEnv) modDB:NewMod("Evasion", "INC", 10, "Base", { type = "Multiplier", var = "Tailwind", limit = 10 }) modDB:NewMod("SkillSlots", "BASE", 9, "Base") modDB:NewMod("MaxLineageCount", "BASE", 1, "Base") + modDB:NewMod("AncestralBoostMoreDamage", "BASE", 30, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }, { type = "Condition", var = "AncestrallyBoostedDouble", neg = true }) + modDB:NewMod("AncestralBoostMoreDamage", "BASE", 60, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) + modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }, { type = "Condition", var = "AncestrallyBoostedDouble", neg = true }) + modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 50, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) + + modDB:NewMod("AdditionalStrikeTarget", "BASE", 2, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam, neg = true }, { type = "Condition", var = "AncestrallyBoosted" }) + -- Initialise enemy modifier database calcs.initModDB(env, enemyDB) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index c5c31d06e5..5d7d5e330f 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2631,8 +2631,7 @@ local specialModList = { ["(%d+)%% increased area of effect of ancestrally boosted attacks"] = function(num) return { mod("AncestralBoostAreaOfEffect", "INC", num, nil, ModFlag.Attack, 0) } end, ["every second slam skill you use yourself is ancestrally boosted"] = { flag("AncestralEmpowerment", { type = "SkillType", skillType = SkillType.Slam }), - mod("AncestralEmpowermentDamageMultiplier", "BASE", 30, { type = "SkillType", skillType = SkillType.Slam }), - mod("AncestralEmpowermentIncAoE", "BASE", 25, { type = "SkillType", skillType = SkillType.Slam }), + flag("Condition:AncestrallyBoosted"), }, -- Leech Related ["life leech is instant"] = { mod("InstantLifeLeech", "BASE", 100), }, From 0610aae34a9cff595aab4592b5bd8f5a6cce522f Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Wed, 27 May 2026 00:00:40 -0500 Subject: [PATCH 14/19] empowered condition for all Ancestrally Boosted --- src/Data/Skills/sup_str.lua | 1 + src/Export/Skills/sup_str.txt | 1 + src/Modules/CalcOffence.lua | 2 +- src/Modules/CalcSetup.lua | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 181a4a1f61..b4c59f5981 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -3513,6 +3513,7 @@ skills["FistOfWarSupportPlayerThree"] = { baseFlags = { }, baseMods = { + flag("Condition:AncestrallyBoosted"), flag("Condition:AncestrallyBoostedDouble"), }, constantStats = { diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 7a9ca0d1ef..1d4562db63 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -790,6 +790,7 @@ statMap = { -- Accounted for in base mod }, }, +#baseMod flag("Condition:AncestrallyBoosted") #baseMod flag("Condition:AncestrallyBoostedDouble") #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index d43f524322..bba1969529 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3388,7 +3388,7 @@ function calcs.offence(env, actor, activeSkill) local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense - -- for generic Ancestrally Boosted skills that have 100% uptime + -- for special case/skillPart-specific Ancestrally Boosted skills that have 100% uptime if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree local sourceName = "Ancestral Boost - "..data.gemNameForModSource[modSource] diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 1efd78d3ea..8b4c5ebf03 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -672,8 +672,8 @@ function calcs.initEnv(build, mode, override, specEnv) modDB:NewMod("AncestralBoostMoreDamage", "BASE", 60, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }, { type = "Condition", var = "AncestrallyBoostedDouble", neg = true }) modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 50, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) - modDB:NewMod("AdditionalStrikeTarget", "BASE", 2, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam, neg = true }, { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("Condition:Empowered", "FLAG", 1, "Base", { type = "Condition", var = "AncestrallyBoosted" }) -- Initialise enemy modifier database From 9dc0d2f7f13c7a4295c16429a0f84d6230b3d061 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Wed, 27 May 2026 08:14:14 -0500 Subject: [PATCH 15/19] ancestralBoostEffect --- src/Data/SkillStatMap.lua | 4 ++++ src/Data/Skills/sup_str.lua | 4 ---- src/Export/Skills/sup_str.txt | 4 ---- src/Modules/CalcOffence.lua | 8 ++++---- src/Modules/CalcSections.lua | 8 ++++---- src/Modules/CalcSetup.lua | 6 ++---- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index f1622209f9..8c102b4792 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -2599,6 +2599,10 @@ return { ["is_final_strike"] = { flag("Condition:FinalStrike"), }, +["double_ancestral_boost_effect"] = { + mod("AncestralBoostEffect", "MORE", nil), + value = 100, +}, -- Curse ["curse_effect_+%"] = { mod("CurseEffect", "INC", nil), diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index b4c59f5981..0f67b04c79 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -3506,15 +3506,11 @@ skills["FistOfWarSupportPlayerThree"] = { mod("FistOfWarCooldown", "BASE", nil), div = 1000, }, - ["double_ancestral_boost_effect"] = { - -- Accounted for in base mod - }, }, baseFlags = { }, baseMods = { flag("Condition:AncestrallyBoosted"), - flag("Condition:AncestrallyBoostedDouble"), }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 1d4562db63..77788729fa 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -786,12 +786,8 @@ statMap = { mod("FistOfWarCooldown", "BASE", nil), div = 1000, }, - ["double_ancestral_boost_effect"] = { - -- Accounted for in base mod - }, }, #baseMod flag("Condition:AncestrallyBoosted") -#baseMod flag("Condition:AncestrallyBoostedDouble") #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index bba1969529..ea6e91bc86 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3381,11 +3381,11 @@ function calcs.offence(env, actor, activeSkill) local ruthlessBlowStunEffect = (ruthlessBlowChance / 100) * ruthlessBlowStunMultiplier skillModList:NewMod("EnemyHeavyStunBuildup", "MORE", ruthlessBlowStunEffect * 100, "Ruthless Blows") - -- passive nodes local ancestrallyBoostedIncDamageMulti = modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 - local ancestrallyBoostedIncArea = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") - -- Condition:AncestrallyBoosted or Condition:AncestrallyBoostedDouble - local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 + -- because the tree nodes and the generic slam AOE are INC, it's a little tricky to know what to scale here unless we want to use different mod names + local ancestrallyBoostedIncArea = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + 25 * (skillModList:More(cfg, "AncestralBoostEffect") - 1) + -- Condition:AncestrallyBoosted * AncestralBoostEffect (e.g. Fist of War III) + local ancestrallyBoostedMoreDamageMulti = (skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") * skillModList:More(cfg, "AncestralBoostEffect")) / 100 -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense -- for special case/skillPart-specific Ancestrally Boosted skills that have 100% uptime diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 10aaf14249..e0e674d254 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -417,28 +417,28 @@ return { --}, { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, + { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentCombinedDamageEffect}" }, }, { label = "Anc. Empowerment", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentDamageEffect}", { breakdown = "AvgAncestralEmpowermentDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" } }, + { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, { format = "{0:output:AncestralEmpowermentUptimeRatio}%", { breakdown = "AncestralEmpowermentUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentDamageEffect}" }, }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, - { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" } }, + { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, { format = "{0:output:FistOfWarUptimeRatio}%", { breakdown = "FistOfWarUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxFistOfWarDamageEffect}" }, }, { label = "Ancestral Call", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralCallUptimeRatio", { format = "{2:output:AvgAncestralCallDamageEffect}", { breakdown = "AvgAncestralCallDamageEffect"}, }, - { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, }, + { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, { format = "{0:output:AncestralCallUptimeRatio}%", { breakdown = "AncestralCallUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralCallDamageEffect}" }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 8b4c5ebf03..982a8ae5f8 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -668,10 +668,8 @@ function calcs.initEnv(build, mode, override, specEnv) modDB:NewMod("Evasion", "INC", 10, "Base", { type = "Multiplier", var = "Tailwind", limit = 10 }) modDB:NewMod("SkillSlots", "BASE", 9, "Base") modDB:NewMod("MaxLineageCount", "BASE", 1, "Base") - modDB:NewMod("AncestralBoostMoreDamage", "BASE", 30, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }, { type = "Condition", var = "AncestrallyBoostedDouble", neg = true }) - modDB:NewMod("AncestralBoostMoreDamage", "BASE", 60, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) - modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }, { type = "Condition", var = "AncestrallyBoostedDouble", neg = true }) - modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 50, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoostedDouble" }) + modDB:NewMod("AncestralBoostMoreDamage", "BASE", 30, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) modDB:NewMod("AdditionalStrikeTarget", "BASE", 2, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam, neg = true }, { type = "Condition", var = "AncestrallyBoosted" }) modDB:NewMod("Condition:Empowered", "FLAG", 1, "Base", { type = "Condition", var = "AncestrallyBoosted" }) From 65b7214281ef80280078b1bedbbe9f2d7b5fbbe7 Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Wed, 27 May 2026 08:27:52 -0500 Subject: [PATCH 16/19] multiplier instead --- src/Data/SkillStatMap.lua | 4 ++-- src/Modules/CalcOffence.lua | 5 ++--- src/Modules/CalcSections.lua | 8 ++++---- src/Modules/CalcSetup.lua | 7 ++++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 8c102b4792..bad08e403e 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -2600,8 +2600,8 @@ return { flag("Condition:FinalStrike"), }, ["double_ancestral_boost_effect"] = { - mod("AncestralBoostEffect", "MORE", nil), - value = 100, + mod("Multiplier:AncestralBoostEffect", "BASE", nil), + value = 1, }, -- Curse ["curse_effect_+%"] = { diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index ea6e91bc86..14d661913b 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3382,10 +3382,9 @@ function calcs.offence(env, actor, activeSkill) skillModList:NewMod("EnemyHeavyStunBuildup", "MORE", ruthlessBlowStunEffect * 100, "Ruthless Blows") local ancestrallyBoostedIncDamageMulti = modDB:Sum("INC", cfg, "AncestralBoostDamage") / 100 - -- because the tree nodes and the generic slam AOE are INC, it's a little tricky to know what to scale here unless we want to use different mod names - local ancestrallyBoostedIncArea = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + 25 * (skillModList:More(cfg, "AncestralBoostEffect") - 1) + local ancestrallyBoostedIncArea = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") -- Condition:AncestrallyBoosted * AncestralBoostEffect (e.g. Fist of War III) - local ancestrallyBoostedMoreDamageMulti = (skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") * skillModList:More(cfg, "AncestralBoostEffect")) / 100 + local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense -- for special case/skillPart-specific Ancestrally Boosted skills that have 100% uptime diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index e0e674d254..41f6a3e848 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -417,28 +417,28 @@ return { --}, { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, + { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentCombinedDamageEffect}" }, }, { label = "Anc. Empowerment", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentDamageEffect}", { breakdown = "AvgAncestralEmpowermentDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, + { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:AncestralEmpowermentUptimeRatio}%", { breakdown = "AncestralEmpowermentUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentDamageEffect}" }, }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, - { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, + { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:FistOfWarUptimeRatio}%", { breakdown = "FistOfWarUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxFistOfWarDamageEffect}" }, }, { label = "Ancestral Call", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralCallUptimeRatio", { format = "{2:output:AvgAncestralCallDamageEffect}", { breakdown = "AvgAncestralCallDamageEffect"}, }, - { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostEffect", cfg = "skill" } }, + { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }}, { format = "{0:output:AncestralCallUptimeRatio}%", { breakdown = "AncestralCallUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralCallDamageEffect}" }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 982a8ae5f8..084357fe67 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -668,9 +668,10 @@ function calcs.initEnv(build, mode, override, specEnv) modDB:NewMod("Evasion", "INC", 10, "Base", { type = "Multiplier", var = "Tailwind", limit = 10 }) modDB:NewMod("SkillSlots", "BASE", 9, "Base") modDB:NewMod("MaxLineageCount", "BASE", 1, "Base") - modDB:NewMod("AncestralBoostMoreDamage", "BASE", 30, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) - modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) - modDB:NewMod("AdditionalStrikeTarget", "BASE", 2, "Base", 0, 0, { type = "SkillType", skillType = SkillType.Slam, neg = true }, { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("Multiplier:AncestralBoostEffect", "BASE", 1, "Base", { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("AncestralBoostMoreDamage", "BASE", 30, "Base", 0, 0, { type = "Multiplier", var = "AncestralBoostEffect" }, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("AncestralBoostAreaOfEffect", "INC", 25, "Base", 0, 0, { type = "Multiplier", var = "AncestralBoostEffect" }, { type = "SkillType", skillType = SkillType.Slam }, { type = "Condition", var = "AncestrallyBoosted" }) + modDB:NewMod("AdditionalStrikeTarget", "BASE", 2, "Base", 0, 0, { type = "Multiplier", var = "AncestralBoostEffect" }, { type = "SkillType", skillType = SkillType.Slam, neg = true }, { type = "Condition", var = "AncestrallyBoosted" }) modDB:NewMod("Condition:Empowered", "FLAG", 1, "Base", { type = "Condition", var = "AncestrallyBoosted" }) From 28004fa5a4eccbcc221a85387c9fade6fcb04b9f Mon Sep 17 00:00:00 2001 From: Peechey <92683202+Peechey@users.noreply.github.com> Date: Wed, 27 May 2026 15:04:48 -0500 Subject: [PATCH 17/19] pr comments also refactored Crescendo III to use the new logic instead of an extra isolated block of logic by introducing a way to conditionally max uptime for Boosted or Empowered attacks --- src/Data/ModCache.lua | 32 ++++--- src/Data/SkillStatMap.lua | 17 +++- src/Data/Skills/sup_str.lua | 45 --------- src/Export/Skills/sup_str.txt | 35 ------- src/Modules/CalcOffence.lua | 168 ++++++++++++++++++---------------- src/Modules/CalcSections.lua | 29 +++--- src/Modules/ModParser.lua | 7 +- 7 files changed, 144 insertions(+), 189 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 95ba6feef0..287148233c 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -1242,7 +1242,7 @@ c["100% increased Parried Debuff Duration"]={{[1]={flags=0,keywordFlags=0,name=" c["100% increased Parry Damage"]={{[1]={[1]={includeTransfigured=true,skillName="Parry",type="SkillName"},flags=0,keywordFlags=0,name="Damage",type="INC",value=100}},nil} c["100% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=100}},nil} c["100% increased Spell Damage"]={{[1]={flags=2,keywordFlags=0,name="Damage",type="INC",value=100}},nil} -c["100% increased Stun Threshold during Empowered Attacks"]={{[1]={[1]={type="Condition",var="Empowered"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=100}},nil} +c["100% increased Stun Threshold during Empowered Attacks"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=100}}," during Empowered Attacks "} c["100% increased Stun Threshold for each time you've been Stunned Recently"]={{[1]={[1]={type="Multiplier",var="StunnedRecently"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=100}},nil} c["100% increased Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="INC",value=100}},nil} c["100% increased amount of Life Leeched"]={{[1]={flags=0,keywordFlags=0,name="MaxLifeLeechRate",type="INC",value=100}},nil} @@ -1764,8 +1764,8 @@ c["20% chance for Energy Shield Recharge to start when you Kill an Enemy"]={{[1] c["20% chance for Flasks you use to not consume Charges"]={{[1]={flags=0,keywordFlags=0,name="FlaskChanceNotConsumeCharges",type="BASE",value=20}},nil} c["20% chance for Lightning Skills to Chain an additional time"]={{[1]={flags=0,keywordFlags=128,name="ChainChance",type="BASE",value=20}},nil} c["20% chance to Aggravate Bleeding on targets you Critically Hit with Attacks"]={{}," to Aggravate Bleeding on targets you Critically Hit "} -c["20% chance to Aggravate Bleeding on targets you Hit with Empowered Attacks"]={{}," to Aggravate Bleeding on targets you Hit "} -c["20% chance to Aggravate Bleeding on targets you Hit with Empowered Attacks Empowered Attacks deal 30% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=0,keywordFlags=0,name="Damage",type="BASE",value=20}}," to Aggravate Bleeding on targets you Hit Empowered Attacks deal 30% increased "} +c["20% chance to Aggravate Bleeding on targets you Hit with Empowered Attacks"]={{}," to Aggravate Bleeding on targets you Hit with Empowered Attacks "} +c["20% chance to Aggravate Bleeding on targets you Hit with Empowered Attacks Empowered Attacks deal 30% increased Damage"]={{[1]={flags=0,keywordFlags=0,name="Damage",type="BASE",value=20}}," to Aggravate Bleeding on targets you Hit with Empowered Attacks Empowered Attacks deal 30% increased "} c["20% chance to Avoid Chaos Damage from Hits"]={{[1]={flags=0,keywordFlags=0,name="AvoidChaosDamageChance",type="BASE",value=20}},nil} c["20% chance to Avoid Cold Damage from Hits"]={{[1]={flags=0,keywordFlags=0,name="AvoidColdDamageChance",type="BASE",value=20}},nil} c["20% chance to Avoid Elemental Ailments"]={{[1]={flags=0,keywordFlags=0,name="AvoidElementalAilments",type="BASE",value=20}},nil} @@ -1872,7 +1872,7 @@ c["20% increased Flammability Magnitude"]={{[1]={flags=0,keywordFlags=0,name="En c["20% increased Flask Effect Duration"]={{[1]={flags=0,keywordFlags=0,name="FlaskDuration",type="INC",value=20}},nil} c["20% increased Flask and Charm Charges gained"]={{[1]={flags=0,keywordFlags=0,name="CharmChargesGained",type="INC",value=20},[2]={flags=0,keywordFlags=0,name="FlaskChargesGained",type="INC",value=20}},nil} c["20% increased Freeze Buildup"]={{[1]={flags=0,keywordFlags=0,name="EnemyFreezeBuildup",type="INC",value=20}},nil} -c["20% increased Freeze Buildup with Empowered Attacks"]={{[1]={[1]={type="Condition",var="Empowered"},flags=0,keywordFlags=0,name="EnemyFreezeBuildup",type="INC",value=20}},nil} +c["20% increased Freeze Buildup with Empowered Attacks"]={{[1]={flags=0,keywordFlags=0,name="EnemyFreezeBuildup",type="INC",value=20}}," with Empowered Attacks "} c["20% increased Freeze Buildup with Quarterstaves"]={{[1]={flags=2097156,keywordFlags=0,name="EnemyFreezeBuildup",type="INC",value=20}},nil} c["20% increased Freeze Duration on Enemies"]={{[1]={flags=0,keywordFlags=0,name="EnemyFreezeDuration",type="INC",value=20}},nil} c["20% increased Frenzy Charge Duration"]={{[1]={flags=0,keywordFlags=0,name="FrenzyChargesDuration",type="INC",value=20}},nil} @@ -4800,16 +4800,18 @@ c["Elemental Archon does not expire while on High Infernal Flame"]={nil,"Element c["Elemental Archon does not expire while on High Infernal Flame Lose Elemental Archon on reaching maximum Infernal Flame"]={nil,"Elemental Archon does not expire while on High Infernal Flame Lose Elemental Archon on reaching maximum Infernal Flame "} c["Elemental Damage also Contributes to Bleeding Magnitude"]={{[1]={flags=0,keywordFlags=0,name="FireCanBleed",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ColdCanBleed",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="LightningCanBleed",type="FLAG",value=true}},nil} c["Elemental Equilibrium"]={{[1]={flags=0,keywordFlags=0,name="Keystone",type="LIST",value="Elemental Equilibrium"}},nil} -c["Empowered Attacks Gain 15% of Physical Damage as Extra Fire damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="PhysicalDamageGainAsFire",type="BASE",value=15}},nil} -c["Empowered Attacks Gain 16% of Damage as Extra Cold Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="DamageGainAsCold",type="BASE",value=16}},nil} -c["Empowered Attacks deal 10% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=10}},nil} -c["Empowered Attacks deal 16% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=16}},nil} -c["Empowered Attacks deal 2% increased damage per 10 Tribute"]={{[1]={[1]={type="Condition",var="Empowered"},[2]={actor="parent",div=10,stat="Tribute",type="PerStat"},flags=1,keywordFlags=0,name="Damage",type="INC",value=2}},nil} -c["Empowered Attacks deal 20% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=20}},nil} -c["Empowered Attacks deal 30% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=30}},nil} -c["Empowered Attacks deal 50% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=50}},nil} -c["Empowered Attacks deal 8% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="Damage",type="INC",value=8}},nil} -c["Empowered Attacks have 50% increased Stun Buildup"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EnemyHeavyStunBuildup",type="INC",value=50}},nil} +c["Empowered Attacks Gain 15% of Physical Damage as Extra Fire damage"]={nil,"Empowered Attacks Gain 15% of Physical Damage as Extra Fire damage "} +c["Empowered Attacks Gain 16% of Damage as Extra Cold Damage"]={nil,"Empowered Attacks Gain 16% of Damage as Extra Cold Damage "} +c["Empowered Attacks deal 10% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=10}},nil} +c["Empowered Attacks deal 16% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=16}},nil} +c["Empowered Attacks deal 2% increased damage per 10 Tribute"]={nil,"Empowered Attacks deal 2% increased damage per 10 Tribute "} +c["Empowered Attacks deal 2% increased damage per 10 Tribute 4% increased Warcry Speed per 25 Tribute"]={nil,"Empowered Attacks deal 2% increased damage per 10 Tribute 4% increased Warcry Speed per 25 Tribute "} +c["Empowered Attacks deal 20% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=20}},nil} +c["Empowered Attacks deal 30% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=30}},nil} +c["Empowered Attacks deal 50% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=50}},nil} +c["Empowered Attacks deal 8% increased Damage"]={{[1]={[1]={type="Condition",var="Empowered"},flags=1,keywordFlags=0,name="EmpoweredIncrease",type="INC",value=8}},nil} +c["Empowered Attacks have 50% increased Stun Buildup"]={nil,"Empowered Attacks have 50% increased Stun Buildup "} +c["Empowered Attacks have 50% increased Stun Buildup 100% increased Stun Threshold during Empowered Attacks"]={nil,"Empowered Attacks have 50% increased Stun Buildup 100% increased Stun Threshold during Empowered Attacks "} c["Enemies Blinded by you have 15% reduced Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-15}}}},nil} c["Enemies Blinded by you have 50% reduced Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="EnemyModifier",type="LIST",value={mod={[1]={type="Condition",var="Blinded"},flags=0,keywordFlags=0,name="CritChance",type="INC",value=-50}}}},nil} c["Enemies Chilled by your Hits can be Shattered as though Frozen"]={nil,"your Hits can be Shattered as though Frozen "} @@ -4921,7 +4923,7 @@ c["Every Rage also grants 2% increased Stun Threshold"]={{[1]={[1]={type="Multip c["Every Rage also grants you 1% increased Minion Attack Speed"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=1,keywordFlags=0,name="Speed",type="INC",value=1}}}},nil} c["Every Rage also grants you 1% increased Minion Damage"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={[1]={actor="player",type="Multiplier",var="RageEffect"},flags=0,keywordFlags=0,name="Damage",type="INC",value=1}}}},nil} c["Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area"]={nil,"Every Third Slam skill that doesn't create Fissures which you use yourself causes 3 additional Aftershocks ahead and to each side of the initial area "} -c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={{[1]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowerment",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="Condition:AncestrallyBoosted",type="FLAG",value=true}},nil} +c["Every second Slam Skill you use yourself is Ancestrally Boosted"]={{[1]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="AncestralEmpowerment",type="FLAG",value=true},[2]={[1]={skillType=93,type="SkillType"},flags=0,keywordFlags=0,name="Condition:AncestrallyBoosted",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 1 second"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 15 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} c["Every second, inflicts Critical Weakness on enemies in your Presence for 18 seconds"]={{[1]={flags=0,keywordFlags=0,name="ApplyCriticalWeakness",type="FLAG",value=true}},nil} diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index bad08e403e..8374b2361e 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -2594,11 +2594,26 @@ return { }, -- Final Strike ["final_strike_is_ancestrally_boosted"] = { - flag("FinalStrikeAncestrallyBoosted"), + flag("Condition:AncestrallyBoosted", { type = "Condition", var = "FinalStrike" }), + flag("MaxBoostedUptimeRatio", { type = "Condition", var = "FinalStrike"}), }, ["is_final_strike"] = { flag("Condition:FinalStrike"), }, +["ancestral_slam_interval_duration"] = { + { + mod("FistOfWarCooldown", "BASE", nil), + div = 1000, + }, + flag("Condition:AncestrallyBoosted"), +}, +["ancestral_call_spirit_strike_interval_ms"] = { + { + mod("AncestralCallCooldown", "BASE", nil), + div = 1000, + }, + flag("Condition:AncestrallyBoosted"), +}, ["double_ancestral_boost_effect"] = { mod("Multiplier:AncestralBoostEffect", "BASE", nil), value = 1, diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 0f67b04c79..daff4789c3 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -149,17 +149,8 @@ skills["SupportAncestralCallPlayer"] = { label = "Ancestral Call I", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", - statMap = { - ["ancestral_call_spirit_strike_interval_ms"] = { - mod("AncestralCallCooldown", "BASE", nil), - div = 1000, - }, - }, baseFlags = { }, - baseMods = { - flag("Condition:AncestrallyBoosted"), - }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 5000 }, }, @@ -190,17 +181,8 @@ skills["SupportAncestralCallPlayerTwo"] = { label = "Ancestral Call II", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", - statMap = { - ["ancestral_call_spirit_strike_interval_ms"] = { - mod("AncestralCallCooldown", "BASE", nil), - div = 1000, - }, - }, baseFlags = { }, - baseMods = { - flag("Condition:AncestrallyBoosted"), - }, constantStats = { { "ancestral_call_spirit_strike_interval_ms", 3000 }, }, @@ -3421,17 +3403,8 @@ skills["FistOfWarSupportPlayer"] = { label = "Fist of War I", incrementalEffectiveness = 0.092720001935959, statDescriptionScope = "gem_stat_descriptions", - statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, - }, baseFlags = { }, - baseMods = { - flag("Condition:AncestrallyBoosted"), - }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, { "ancestral_slam_interval_duration", 6000 }, @@ -3461,17 +3434,8 @@ skills["FistOfWarSupportPlayerTwo"] = { label = "Fist of War II", incrementalEffectiveness = 0.092720001935959, statDescriptionScope = "gem_stat_descriptions", - statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, - }, baseFlags = { }, - baseMods = { - flag("Condition:AncestrallyBoosted"), - }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, { "ancestral_slam_interval_duration", 4000 }, @@ -3501,17 +3465,8 @@ skills["FistOfWarSupportPlayerThree"] = { label = "Fist of War III", incrementalEffectiveness = 0.092720001935959, statDescriptionScope = "gem_stat_descriptions", - statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, - }, baseFlags = { }, - baseMods = { - flag("Condition:AncestrallyBoosted"), - }, constantStats = { { "support_ancestral_slam_big_hit_max_count", 1 }, { "ancestral_slam_interval_duration", 14000 }, diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 77788729fa..3094573d5b 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -26,25 +26,11 @@ local skills, mod, flag, skill = ... #skill SupportAncestralCallPlayer #set SupportAncestralCallPlayer -statMap = { - ["ancestral_call_spirit_strike_interval_ms"] = { - mod("AncestralCallCooldown", "BASE", nil), - div = 1000, - }, -}, -#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd #skill SupportAncestralCallPlayerTwo #set SupportAncestralCallPlayerTwo -statMap = { - ["ancestral_call_spirit_strike_interval_ms"] = { - mod("AncestralCallCooldown", "BASE", nil), - div = 1000, - }, -}, -#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd @@ -757,37 +743,16 @@ statMap = { #skill FistOfWarSupportPlayer #set FistOfWarSupportPlayer -statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, -}, -#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd #skill FistOfWarSupportPlayerTwo #set FistOfWarSupportPlayerTwo -statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, -}, -#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd #skill FistOfWarSupportPlayerThree #set FistOfWarSupportPlayerThree -statMap = { - ["ancestral_slam_interval_duration"] = { - mod("FistOfWarCooldown", "BASE", nil), - div = 1000, - }, -}, -#baseMod flag("Condition:AncestrallyBoosted") #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 14d661913b..e7c784822a 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3306,56 +3306,6 @@ function calcs.offence(env, actor, activeSkill) else globalOutput.AilmentWarcryEffect = globalOutput.OffensiveWarcryEffect end - - -- Calculate Exerted Attack Uptime - -- There are various strategies a player could use to maximize either warcry effect stacking or staggering - -- 1) they don't pay attention and therefore we calculated exerted attack uptime as just the maximum uptime of any enabled warcries that exert attacks - local warcryList = {"AncestralUpTimeRatio", "InfernalCryUptimeRatio", "IntimidatingUpTimeRatio", "RallyingUpTimeRatio", "SeismicUpTimeRatio", "BattlemageUpTimeRatio"} - for _, cryTimeRatio in ipairs(warcryList) do - globalOutput.ExertedAttackUptimeRatio = m_max(globalOutput.ExertedAttackUptimeRatio or 0, globalOutput[cryTimeRatio] or 0) - end - if globalBreakdown then - globalBreakdown.ExertedAttackUptimeRatio = { } - t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("Maximum of:")) - for _, cryTimeRatio in ipairs(warcryList) do - if globalOutput[cryTimeRatio] then - t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("%d%% ^8(%s Cry Uptime)", globalOutput[cryTimeRatio] or 0, cryTimeRatio:match("(.+)Up.*"))) - end - end - t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("= %d%%", globalOutput.ExertedAttackUptimeRatio)) - end - if globalOutput.ExertedAttackUptimeRatio > 0 and not globalOutput.ExertedAttackUptimeRatioCalculated then - local incExertedAttacks = skillModList:Sum("INC", cfg, "ExertIncrease") - local moreExertedAttacks = skillModList:Sum("MORE", cfg, "ExertIncrease") - local moreExertedAttackDamage = skillModList:Sum("MORE", cfg, "ExertAttackIncrease") - local overexertionExertedDamage = skillModList:Sum("MORE", cfg, "OverexertionExertAverageIncrease") - local echoesOfCreationExertedDamage = skillModList:Sum("MORE", cfg, "EchoesExertAverageIncrease") - if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - skillModList:NewMod("Damage", "INC", incExertedAttacks, "Exerted Attacks") - skillModList:NewMod("Damage", "MORE", moreExertedAttacks, "Exerted Attacks") - skillModList:NewMod("Damage", "MORE", moreExertedAttackDamage, "Exerted Attack Damage", ModFlag.Attack) - skillModList:NewMod("Damage", "MORE", overexertionExertedDamage * exertingWarcryCount, "Max Autoexertion Support") - skillModList:NewMod("Damage", "MORE", echoesOfCreationExertedDamage * exertingWarcryCount, "Max Echoes of Creation") - else - skillModList:NewMod("Damage", "INC", incExertedAttacks * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Exerted Attacks") - skillModList:NewMod("Damage", "MORE", moreExertedAttacks * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Exerted Attacks") - skillModList:NewMod("Damage", "MORE", moreExertedAttackDamage * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Exerted Attack Damage", ModFlag.Attack) - skillModList:NewMod("Damage", "MORE", overexertionExertedDamage * globalOutput.GlobalWarcryUptimeRatio / 100, "Uptime Scaled Autoexertion Support") - skillModList:NewMod("Damage", "MORE", echoesOfCreationExertedDamage * globalOutput.GlobalWarcryUptimeRatio / 100, "Uptime Scaled Echoes of Creation") - end - globalOutput.ExertedAttackAvgDmg = calcLib.mod(skillModList, skillCfg, "ExertIncrease") - globalOutput.ExertedAttackAvgDmg = globalOutput.ExertedAttackAvgDmg * calcLib.mod(skillModList, skillCfg, "ExertAttackIncrease", "OverexertionExertAverageIncrease", "EchoesExertAverageIncrease") - globalOutput.ExertedAttackHitEffect = globalOutput.ExertedAttackAvgDmg * globalOutput.ExertedAttackUptimeRatio / 100 - globalOutput.ExertedAttackMaxHitEffect = globalOutput.ExertedAttackAvgDmg - if globalBreakdown then - globalBreakdown.ExertedAttackHitEffect = { - s_format("(%.2f ^8(average exerted damage)", globalOutput.ExertedAttackAvgDmg), - s_format("x %.2f) ^8(uptime %%)", globalOutput.ExertedAttackUptimeRatio / 100), - s_format("= %.2f", globalOutput.ExertedAttackHitEffect), - } - end - globalOutput.ExertedAttackUptimeRatioCalculated = true - end end end @@ -3386,16 +3336,6 @@ function calcs.offence(env, actor, activeSkill) -- Condition:AncestrallyBoosted * AncestralBoostEffect (e.g. Fist of War III) local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 - -- Final Strike calcs could be done in many other places, but clumping the Ancestral Boost things together made sense - -- for special case/skillPart-specific Ancestrally Boosted skills that have 100% uptime - if skillModList:Flag(cfg, "FinalStrikeAncestrallyBoosted") then - local modSource = skillModList:Tabulate("FLAG", cfg, "FinalStrikeAncestrallyBoosted")[1].mod.source -- e.g. Skill:SupportCrescendoPlayerThree - local sourceName = "Ancestral Boost - "..data.gemNameForModSource[modSource] - skillModList:NewMod("Damage", "INC", modDB:Sum("INC", cfg, "AncestralBoostDamage"), sourceName, { type = "Condition", var = "FinalStrike" }) - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, sourceName, { type = "Condition", var = "FinalStrike" }) - calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) - end - -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code -- uptimeOverride: Ancestral Empowerment -- combinedCalcs: ignore INC AoE as we will run that in calcCombinedAncestralBoost @@ -3404,11 +3344,7 @@ function calcs.offence(env, actor, activeSkill) local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() - if moreDmg then - globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg * (1 + ancestrallyBoostedIncDamageMulti) - else - globalOutput[skillNameVar.."DamageMultiplier"] = ancestrallyBoostedIncDamageMulti - end + globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg or 1 globalOutput[skillNameVar.."UptimeRatio"] = uptimeOverride or m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 if globalBreakdown then globalBreakdown[skillNameVar.."UptimeRatio"] = { @@ -3429,12 +3365,8 @@ function calcs.offence(env, actor, activeSkill) globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] - if not combinedCalcs then - skillModList:NewMod("AreaOfEffect", "INC", m_floor(ancestrallyBoostedIncArea * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Boosted AoE") - end end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3447,11 +3379,7 @@ function calcs.offence(env, actor, activeSkill) local skillNameVar = skillName:gsub(" ", "") -- Fist Of War -> FistOfWar local skillNameLabel = skillName:lower() - if moreDmg then - globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg * (1 + ancestrallyBoostedIncDamageMulti) - else - globalOutput[skillNameVar.."DamageMultiplier"] = ancestrallyBoostedIncDamageMulti - end + globalOutput[skillNameVar.."DamageMultiplier"] = moreDmg or 1 -- for CalcSections, set the AncestralEmpowerment damage for mod breakdown globalOutput[skillNameVar.."CombinedDamageMultiplier"] = globalOutput[skillNameVar.."DamageMultiplier"] skillNameVar = skillNameVar.."Combined" @@ -3481,14 +3409,11 @@ function calcs.offence(env, actor, activeSkill) s_format("= %.2f", globalOutput["Avg"..skillNameVar.."DamageEffect"]), } end - globalOutput["Avg"..skillNameVar.."Damage"] = globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput[additionalSkillNameVar.."DamageMultiplier"] - globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] + globalOutput[additionalSkillNameVar.."DamageMultiplier"] + globalOutput["Max"..skillNameVar.."DamageEffect"] = 1 + globalOutput[skillNameVar.."DamageMultiplier"] if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then output[skillNameVar.."DamageEffect"] = globalOutput["Max"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", ancestrallyBoostedIncArea, "Max "..skillName.." Combined Boosted AoE") else output[skillNameVar.."DamageEffect"] = globalOutput["Avg"..skillNameVar.."DamageEffect"] - skillModList:NewMod("AreaOfEffect", "INC", m_floor((ancestrallyBoostedIncArea) * globalOutput[skillNameVar.."UptimeRatio"] / 100), "Avg "..skillName.." Combined Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) globalOutput.TheoreticalOffensiveWarcryEffect = globalOutput.TheoreticalOffensiveWarcryEffect * globalOutput["Avg"..skillNameVar.."DamageEffect"] @@ -3524,6 +3449,93 @@ function calcs.offence(env, actor, activeSkill) end end + -- Calculate Empowered Attack Uptime + -- Ancestrally Boosted attacks are also Empowered, so we need to check for the highest uptime among both lists + -- we can use these ratio flags to max the uptime for attacks/skills that guarantee Ancestrally Boosted or Empowered in specific cases like Crescendo III + local maxEmpoweredUptimeRatio = (skillModList:Flag(cfg, "MaxBoostedUptimeRatio") or skillModList:Flag(cfg, "MaxEmpoweredUptimeRatio")) and 100 + local warcryList = { "InfernalCryUptimeRatio" } + local ancestralBoostList = { "AncestralEmpowermentCombinedUptimeRatio", "AncestralEmpowermentUptimeRatio", "FistOfWarUptimeRatio", "AncestralCallUptimeRatio" } + local combinedList = {} + for _, ratio in ipairs(warcryList) do + t_insert(combinedList, ratio) + end + for _, ratio in ipairs(ancestralBoostList) do + t_insert(combinedList, ratio) + end + + for _, cryTimeRatio in ipairs(combinedList) do + globalOutput.ExertedAttackUptimeRatio = maxEmpoweredUptimeRatio or m_max(globalOutput.ExertedAttackUptimeRatio or 0, globalOutput[cryTimeRatio] or 0) + end + if globalBreakdown then + globalBreakdown.ExertedAttackUptimeRatio = { } + t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("Maximum of:")) + for _, cryTimeRatio in ipairs(combinedList) do + if globalOutput[cryTimeRatio] then + t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("%d%% ^8(%s Uptime)", maxEmpoweredUptimeRatio or globalOutput[cryTimeRatio] or 0, maxEmpoweredUptimeRatio and "Override" or cryTimeRatio:match("(.+)Up.*") or "Override")) + end + end + t_insert(globalBreakdown.ExertedAttackUptimeRatio, s_format("= %d%%", globalOutput.ExertedAttackUptimeRatio)) + end + if globalOutput.ExertedAttackUptimeRatio > 0 and not globalOutput.ExertedAttackUptimeRatioCalculated then + local incExertedAttacks = skillModList:Sum("INC", cfg, "EmpoweredIncrease") + if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then + skillModList:NewMod("Damage", "INC", incExertedAttacks, "Empowered Attacks") + else + skillModList:NewMod("Damage", "INC", incExertedAttacks * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Empowered Attacks") + end + globalOutput.ExertedAttackAvgDmg = calcLib.mod(skillModList, skillCfg, "EmpoweredIncrease") + globalOutput.ExertedAttackHitEffect = globalOutput.ExertedAttackAvgDmg * globalOutput.ExertedAttackUptimeRatio / 100 + globalOutput.ExertedAttackMaxHitEffect = globalOutput.ExertedAttackAvgDmg + if globalBreakdown then + globalBreakdown.ExertedAttackHitEffect = { + s_format("(%.2f ^8(average exerted damage)", globalOutput.ExertedAttackAvgDmg), + s_format("x %.2f) ^8(uptime %%)", globalOutput.ExertedAttackUptimeRatio / 100), + s_format("= %.2f", globalOutput.ExertedAttackHitEffect), + } + end + globalOutput.ExertedAttackUptimeRatioCalculated = true + end + + local maxBoostedUptimeRatio = skillModList:Flag(cfg, "MaxBoostedUptimeRatio") and 100 + -- Calculate Ancestrally Boosted Attack Uptime + for _, boostUptimeRatio in ipairs(ancestralBoostList) do + globalOutput.BoostedAttackUptimeRatio = maxBoostedUptimeRatio or m_max(globalOutput.BoostedAttackUptimeRatio or 0, globalOutput[boostUptimeRatio] or 0) + end + if globalBreakdown then + globalBreakdown.BoostedAttackUptimeRatio = { } + t_insert(globalBreakdown.BoostedAttackUptimeRatio, s_format("Maximum of:")) + for _, boostUptimeRatio in ipairs(ancestralBoostList) do + if globalOutput[boostUptimeRatio] then + t_insert(globalBreakdown.BoostedAttackUptimeRatio, s_format("%d%% ^8(%s Uptime)", maxBoostedUptimeRatio or globalOutput[boostUptimeRatio] or 0, maxBoostedUptimeRatio and "Override" or boostUptimeRatio:match("(.+)Up.*"))) + end + end + t_insert(globalBreakdown.BoostedAttackUptimeRatio, s_format("= %d%%", globalOutput.BoostedAttackUptimeRatio)) + end + if globalOutput.BoostedAttackUptimeRatio > 0 and not globalOutput.BoostedAttackUptimeRatioCalculated then + local incBoostedAttacks = skillModList:Sum("INC", cfg, "AncestralBoostDamage") + local incAoEBoostedAttacks = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") + if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then + skillModList:NewMod("Damage", "INC", incBoostedAttacks, "Ancestrally Boosted Attacks") + skillModList:NewMod("AreaOfEffect", "INC", incAoEBoostedAttacks, "Ancestrally Boosted Attacks") + else + skillModList:NewMod("Damage", "INC", incBoostedAttacks * globalOutput.BoostedAttackUptimeRatio / 100, "Uptime Scaled Ancestrally Boosted Attacks") + skillModList:NewMod("AreaOfEffect", "INC", incAoEBoostedAttacks * globalOutput.BoostedAttackUptimeRatio / 100, "Uptime Scaled Ancestrally Boosted AoE") + end + calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) + + globalOutput.BoostedAttackAvgDmg = calcLib.mod(skillModList, skillCfg, "AncestralBoostDamage") + globalOutput.BoostedAttackHitEffect = globalOutput.BoostedAttackAvgDmg * globalOutput.BoostedAttackUptimeRatio / 100 + globalOutput.BoostedAttackMaxHitEffect = globalOutput.BoostedAttackAvgDmg + if globalBreakdown then + globalBreakdown.BoostedAttackHitEffect = { + s_format("(%.2f ^8(average Boosted damage)", globalOutput.BoostedAttackAvgDmg), + s_format("x %.2f) ^8(uptime %%)", globalOutput.BoostedAttackUptimeRatio / 100), + s_format("= %.2f", globalOutput.BoostedAttackHitEffect), + } + end + globalOutput.BoostedAttackUptimeRatioCalculated = true + end + -- Calculate maximum sustainable fuses and explosion rate for Explosive Arrow -- Does not take into account mines or traps if activeSkill.activeEffect.grantedEffect.name == "Explosive Arrow" then diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index 41f6a3e848..a0bcaeb18c 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -408,37 +408,44 @@ return { { format = "{0:output:AncestralExertsCount}" }, { format = "" }, }, - --{ label = "Exerted Attacks", bgCol = colorCodes.MAINHANDBG, haveOutput = "ExertedAttackUptimeRatio", - -- { format = "{2:output:ExertedAttackHitEffect}", { breakdown = "ExertedAttackHitEffect"}, }, - -- { format = "{2:output:ExertedAttackAvgDmg}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, - -- { format = "{0:output:ExertedAttackUptimeRatio}%", { breakdown = "ExertedAttackUptimeRatio" }, }, - -- { format = "" }, - -- { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, - --}, + { label = "Empowered Attacks", haveOutput = "ExertedAttackUptimeRatio", + { format = "{2:output:ExertedAttackHitEffect}", { breakdown = "ExertedAttackHitEffect" }, }, + { format = "{2:output:ExertedAttackAvgDmg}", { modName = "EmpoweredIncrease", cfg = "skill" }, }, + { format = "{0:output:ExertedAttackUptimeRatio}%", { breakdown = "ExertedAttackUptimeRatio" }, }, + { format = "" }, + { format = "{2:output:ExertedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, + }, + { label = "Boosted Attacks", bgCol = colorCodes.MAINHANDBG, haveOutput = "BoostedAttackUptimeRatio", + { format = "{2:output:BoostedAttackHitEffect}", { breakdown = "BoostedAttackHitEffect"}, }, + { format = "{2:output:BoostedAttackAvgDmg}", { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "EmpoweredIncrease", cfg = "skill" } }, + { format = "{0:output:BoostedAttackUptimeRatio}%", { breakdown = "BoostedAttackUptimeRatio" }, }, + { format = "" }, + { format = "{2:output:BoostedAttackMaxHitEffect}", { modName = "ExertIncrease", cfg = "skill" }, { modName = "ExertAttackIncrease", cfg = "skill" }, }, + }, { label = "AncestralEmpower+", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentCombinedUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentCombinedDamageEffect}", { breakdown = "AvgAncestralEmpowermentCombinedDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, + { format = "{2:output:AvgAncestralEmpowermentCombinedDamage}", { modName = { "AncestralEmpowermentDamageMultiplier", "FistOfWarDamageMultiplier" }, cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:AncestralEmpowermentCombinedUptimeRatio}%", { breakdown = "AncestralEmpowermentCombinedUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentCombinedDamageEffect}" }, }, { label = "Anc. Empowerment", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralEmpowermentUptimeRatio", { format = "{2:output:AvgAncestralEmpowermentDamageEffect}", { breakdown = "AvgAncestralEmpowermentDamageEffect"}, }, - { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, + { format = "{2:output:AvgAncestralEmpowermentDamage}", { modName = "AncestralEmpowermentDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:AncestralEmpowermentUptimeRatio}%", { breakdown = "AncestralEmpowermentUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralEmpowermentDamageEffect}" }, }, { label = "Fist of War", bgCol = colorCodes.MAINHANDBG, haveOutput = "FistOfWarUptimeRatio", { format = "{2:output:AvgFistOfWarDamageEffect}", { breakdown = "AvgFistOfWarDamageEffect"}, }, - { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, + { format = "{2:output:AvgFistOfWarDamage}", { modName = "FistOfWarDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostMoreDamage", cfg = "skill" }}, { format = "{0:output:FistOfWarUptimeRatio}%", { breakdown = "FistOfWarUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxFistOfWarDamageEffect}" }, }, { label = "Ancestral Call", bgCol = colorCodes.MAINHANDBG, haveOutput = "AncestralCallUptimeRatio", { format = "{2:output:AvgAncestralCallDamageEffect}", { breakdown = "AvgAncestralCallDamageEffect"}, }, - { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}, { modName = "AncestralBoostDamage", cfg = "skill" }}, + { format = "{2:output:AvgAncestralCallDamage}", { modName = "AncestralCallDamageMultiplier", cfg = "skill"}}, { format = "{0:output:AncestralCallUptimeRatio}%", { breakdown = "AncestralCallUptimeRatio" }, }, { format = "" }, { format = "{2:output:MaxAncestralCallDamageEffect}" }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 5d7d5e330f..40511b1050 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -1400,7 +1400,6 @@ local preFlagList = { ["^for each nearby corpse, "] = { tag = { type = "Multiplier", var = "NearbyCorpse" } }, ["^enemies in your link beams have "] = { tag = { type = "Condition", var = "BetweenYouAndLinkedTarget" }, applyToEnemy = true }, ["^consecrated ground you create also grants "] = { tag = { type = "Condition", var = "OnConsecratedGround" } }, - ["^empowered attacks [hgd][ae][via][enl] "] = { flags = ModFlag.Attack, tag = { type = "Condition", var = "Empowered" } }, -- While in the presence of... ["^while a unique enemy is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" } }, ["^while a pinnacle atlas boss is in your presence, "] = { tag = { type = "ActorCondition", actor = "enemy", var = "PinnacleBoss" } }, @@ -1422,8 +1421,6 @@ local modTagList = { ["with critical hits"] = { tag = { type = "Condition", var = "CriticalStrike" } }, ["while affected by auras you cast"] = { tag = { type = "Condition", var = "AffectedByAura" } }, ["for you and nearby allies"] = { newAura = true }, - ["with empowered attacks"] = { tag = { type = "Condition", var = "Empowered" } }, - ["during empowered attacks"] = { tag = { type = "Condition", var = "Empowered" } }, -- Multipliers ["per power charge"] = { tag = { type = "Multiplier", var = "PowerCharge" } }, ["if you've consumed an? (%D+) charge recently"] = function(charge) return { tag = { type = "Multiplier", var = "Removable" .. firstToUpper(charge) .. "Charge", limit = 1 }} end, @@ -2626,12 +2623,14 @@ local specialModList = { -- Exerted Attacks ["exerted attacks deal (%d+)%% increased damage"] = function(num) return { mod("ExertIncrease", "INC", num, nil, ModFlag.Attack, 0) } end, ["exerted attacks have (%d+)%% chance to deal double damage"] = function(num) return { mod("ExertDoubleDamageChance", "BASE", num, nil, ModFlag.Attack, 0) } end, + -- Empowered Attacks + ["empowered attacks deal (%d+)%% increased damage"] = function(num) return { mod("EmpoweredIncrease", "INC", num, nil, ModFlag.Attack, 0, { type = "Condition", var = "Empowered"}) } end, -- Ancestrally Boosted ["ancestrally boosted attacks deal (%d+)%% increased damage"] = function(num) return { mod("AncestralBoostDamage", "INC", num, nil, ModFlag.Attack, 0) } end, ["(%d+)%% increased area of effect of ancestrally boosted attacks"] = function(num) return { mod("AncestralBoostAreaOfEffect", "INC", num, nil, ModFlag.Attack, 0) } end, ["every second slam skill you use yourself is ancestrally boosted"] = { flag("AncestralEmpowerment", { type = "SkillType", skillType = SkillType.Slam }), - flag("Condition:AncestrallyBoosted"), + flag("Condition:AncestrallyBoosted", { type = "SkillType", skillType = SkillType.Slam }), }, -- Leech Related ["life leech is instant"] = { mod("InstantLifeLeech", "BASE", 100), }, From 14769d65339e4338ad2819baec891aae5e0c22bd Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Fri, 29 May 2026 00:22:00 +1000 Subject: [PATCH 18/19] Fix issues Move the Infernal Cry buff to calc offence so it doesn't rely on stale calc output Fix Ancestral Empowerment uptime calculation Move gain table so Infernal Cry still works --- spec/System/TestSkills_spec.lua | 2 + src/Data/Skills/act_str.lua | 2 +- src/Export/Skills/act_str.txt | 2 +- src/Modules/CalcOffence.lua | 113 ++++++++++++++++++-------------- src/Modules/CalcPerform.lua | 30 ++++----- 5 files changed, 80 insertions(+), 69 deletions(-) diff --git a/spec/System/TestSkills_spec.lua b/spec/System/TestSkills_spec.lua index 509d8df2a2..5d00cf219d 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -898,5 +898,7 @@ describe("TestSkills", function() -- test doubled effects of Fist of War III with Ancestral Empowerment assert.True(fistOfWarOneMaxDmgEffect < build.calcsTab.calcsOutput.MaxAncestralEmpowermentCombinedDamageEffect) + local expectedAverageEffect = 1 + (build.calcsTab.calcsOutput.MaxAncestralEmpowermentCombinedDamageEffect - 1) * build.calcsTab.calcsOutput.AncestralEmpowermentCombinedUptimeRatio / 100 + assert.are.equals(round(expectedAverageEffect, 4), round(build.calcsTab.calcsOutput.AvgAncestralEmpowermentCombinedDamageEffect, 4)) end) end) \ No newline at end of file diff --git a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua index 4d61401a01..9f6c4764ea 100644 --- a/src/Data/Skills/act_str.lua +++ b/src/Data/Skills/act_str.lua @@ -7511,7 +7511,7 @@ skills["InfernalCryPlayer"] = { statDescriptionScope = "infernal_cry", statMap = { ["infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%"] = { - mod("DamageGainAsFire", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Warcry" }, { type = "Condition", var = "Empowered" }), + mod("InfernalExtraFireDamageMultiplier", "BASE", nil), }, }, baseFlags = { diff --git a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt index d7155420ba..67a9b02814 100644 --- a/src/Export/Skills/act_str.txt +++ b/src/Export/Skills/act_str.txt @@ -488,7 +488,7 @@ statMap = { #flags warcry area duration statMap = { ["infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%"] = { - mod("DamageGainAsFire", "BASE", nil, ModFlag.Melee, 0, { type = "GlobalEffect", effectType = "Warcry" }, { type = "Condition", var = "Empowered" }), + mod("InfernalExtraFireDamageMultiplier", "BASE", nil), }, }, #mods diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index e7c784822a..076b8b5f8e 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -2211,6 +2211,33 @@ function calcs.offence(env, actor, activeSkill) return totalConv, total end + local function buildGainTable() + for _, damageType in ipairs(dmgTypeList) do + activeSkill.gainTable[damageType] = {} + for _, toType in ipairs(dmgTypeList) do + local globalGain = m_max(skillModList:Sum("BASE", skillCfg, + "DamageAs"..toType, + "DamageGainAs"..toType, + damageType.."DamageAs"..toType, + damageType.."DamageGainAs"..toType, + isElemental[damageType] and "ElementalDamageAs"..toType or nil, + isElemental[damageType] and "ElementalDamageGainAs"..toType or nil, + damageType ~= "Chaos" and "NonChaosDamageAs"..toType or nil, + damageType ~= "Chaos" and "NonChaosDamageGainAs"..toType or nil), 0) + local skillGain = m_max(skillModList:Sum("BASE", skillCfg, + "SkillDamageGainAs"..toType, + "Skill"..damageType.."DamageGainAs"..toType, + isElemental[damageType] and "SkillElementalDamageGainAs"..toType or nil, + damageType ~= "Chaos" and "SkillNonChaosDamageGainAs"..toType or nil), 0) + if skillModList:Flag(skillCfg, "DamageGainIsOnlyCold") and toType ~= "Cold" then + activeSkill.gainTable[damageType]["Cold"] = (activeSkill.gainTable[damageType]["Cold"] or 0) + (globalGain + skillGain) / 100 + else + activeSkill.gainTable[damageType][toType] = (activeSkill.gainTable[damageType][toType] or 0) + (globalGain + skillGain) / 100 + end + end + end + end + -- First step: Process skill conversion for _, damageType in ipairs(dmgTypeList) do local skillConv, skillTotal = processDamageConversion(damageType, true) @@ -2268,29 +2295,6 @@ function calcs.offence(env, actor, activeSkill) end end - -- Handle gains - activeSkill.gainTable[damageType] = {} - for _, toType in ipairs(dmgTypeList) do - local globalGain = m_max(skillModList:Sum("BASE", skillCfg, - "DamageAs"..toType, - "DamageGainAs"..toType, - damageType.."DamageAs"..toType, - damageType.."DamageGainAs"..toType, - isElemental[damageType] and "ElementalDamageAs"..toType or nil, - isElemental[damageType] and "ElementalDamageGainAs"..toType or nil, - damageType ~= "Chaos" and "NonChaosDamageAs"..toType or nil, - damageType ~= "Chaos" and "NonChaosDamageGainAs"..toType or nil), 0) - local skillGain = m_max(skillModList:Sum("BASE", skillCfg, - "SkillDamageGainAs"..toType, - "Skill"..damageType.."DamageGainAs"..toType, - isElemental[damageType] and "SkillElementalDamageGainAs"..toType or nil, - damageType ~= "Chaos" and "SkillNonChaosDamageGainAs"..toType or nil), 0) - if skillModList:Flag(skillCfg, "DamageGainIsOnlyCold") and toType ~= "Cold" then - activeSkill.gainTable[damageType]["Cold"] = (activeSkill.gainTable[damageType]["Cold"] or 0) + (globalGain + skillGain) / 100 - else - activeSkill.gainTable[damageType][toType] = (activeSkill.gainTable[damageType][toType] or 0) + (globalGain + skillGain) / 100 - end - end end -- Configure damage passes @@ -3090,7 +3094,8 @@ function calcs.offence(env, actor, activeSkill) -- Exerted Attack members local exertedDoubleDamage = env.modDB:Sum("BASE", cfg, "ExertDoubleDamageChance") - local exertingWarcryCount = env.modDB:Sum("BASE", nil, "Multiplier:ExertingWarcryCount") + local exertingWarcryCount = env.modDB:Sum("BASE", nil, "Multiplier:EmpoweringWarcryCount") + local warcryPower = modDB:Override(nil, "WarcryPower") or m_max((modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (modDB:Sum("INC", nil, "WarcryPower") or 0) / 100), (modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) globalOutput.OffensiveWarcryEffect = 1 globalOutput.MaxOffensiveWarcryEffect = 1 globalOutput.TheoreticalOffensiveWarcryEffect = 1 @@ -3125,29 +3130,34 @@ function calcs.offence(env, actor, activeSkill) t_insert(globalBreakdown.AncestralUpTimeRatio, s_format("= %d%%", globalOutput.AncestralUpTimeRatio)) end globalOutput.AncestralCryCalculated = true - elseif value.activeEffect.grantedEffect.name == "Infernal Cry" and not globalOutput.InfernalCryCalculated then + elseif value.activeEffect.grantedEffect.name == "Infernal Cry" and activeSkill.skillTypes[SkillType.Melee] and not globalOutput.InfernalCryCalculated then globalOutput.CreateWarcryOffensiveCalcSection = true globalOutput.InfernalCryDuration = calcSkillDuration(value.skillModList, value.skillCfg, value.skillData, env, enemyDB) globalOutput.InfernalCryCooldown = calcSkillCooldown(value.skillModList, value.skillCfg, value.skillData) globalOutput.InfernalCryCastTime = calcWarcryCastTime(value.skillModList, value.skillCfg, value.skillData, actor) - if activeSkill.skillTypes[SkillType.Melee] then - globalOutput.InfernalEmpoweredCount = (modDB:Override(nil, "WarcryPower") or value.skillModList:Sum("BASE", nil, "WarcryPowerCap")) / value.skillModList:Sum("BASE", nil, "WarcryPowerPer") - local baseUptimeRatio = m_min((globalOutput.InfernalEmpoweredCount / globalOutput.Speed) / (globalOutput.InfernalCryCooldown + globalOutput.InfernalCryCastTime), 1) * 100 - local storedUses = value.skillData.storedUses or 0 + value.skillModList:Sum("BASE", value.skillCfg, "AdditionalCooldownUses") - globalOutput.InfernalCryUptimeRatio = m_min(100, baseUptimeRatio * storedUses) - globalOutput.GlobalWarcryUptimeRatio = globalOutput.GlobalWarcryUptimeRatio + globalOutput.InfernalCryUptimeRatio - if globalBreakdown then - globalBreakdown.InfernalCryUptimeRatio = { } - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("(%.2f ^8(number of empowered)", globalOutput.InfernalEmpoweredCount)) - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f) ^8(attacks per second)", globalOutput.Speed)) - if globalOutput.InfernalCryCastTime > 0 then - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ (%.2f ^8(warcry cooldown)", globalOutput.InfernalCryCooldown)) - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("+ %.2f) ^8(warcry cast time)", globalOutput.InfernalCryCastTime)) - else - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f ^8(average warcry cooldown)", globalOutput.InfernalCryCooldown)) - end - t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("= %d%%", globalOutput.InfernalCryUptimeRatio)) + local powerCap = value.skillModList:Sum("BASE", nil, "WarcryPowerCap") + local powerPer = value.skillModList:Sum("BASE", nil, "WarcryPowerPer") + globalOutput.InfernalEmpoweredCount = powerPer > 0 and m_floor(m_min(warcryPower, powerCap) / powerPer) or 0 + local baseUptimeRatio = m_min((globalOutput.InfernalEmpoweredCount / globalOutput.Speed) / (globalOutput.InfernalCryCooldown + globalOutput.InfernalCryCastTime), 1) * 100 + local storedUses = value.skillData.storedUses or 0 + value.skillModList:Sum("BASE", value.skillCfg, "AdditionalCooldownUses") + globalOutput.InfernalCryUptimeRatio = m_min(100, baseUptimeRatio * storedUses) + globalOutput.GlobalWarcryUptimeRatio = globalOutput.GlobalWarcryUptimeRatio + globalOutput.InfernalCryUptimeRatio + if globalBreakdown then + globalBreakdown.InfernalCryUptimeRatio = { } + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("(%.2f ^8(number of empowered)", globalOutput.InfernalEmpoweredCount)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f) ^8(attacks per second)", globalOutput.Speed)) + if globalOutput.InfernalCryCastTime > 0 then + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ (%.2f ^8(warcry cooldown)", globalOutput.InfernalCryCooldown)) + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("+ %.2f) ^8(warcry cast time)", globalOutput.InfernalCryCastTime)) + else + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("/ %.2f ^8(average warcry cooldown)", globalOutput.InfernalCryCooldown)) end + t_insert(globalBreakdown.InfernalCryUptimeRatio, s_format("= %d%%", globalOutput.InfernalCryUptimeRatio)) + end + local infernalGainAsFire = modDB:Sum("BASE", nil, "InfernalExtraFireDamage") + if infernalGainAsFire > 0 then + local infernalUptime = activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") and 100 or globalOutput.InfernalCryUptimeRatio + skillModList:NewMod("DamageGainAsFire", "BASE", infernalGainAsFire * infernalUptime / 100, "Uptime Scaled Infernal Cry", ModFlag.Melee) end globalOutput.InfernalCryCalculated = true elseif value.activeEffect.grantedEffect.name == "Intimidating Cry" and activeSkill.skillTypes[SkillType.Melee] and not globalOutput.IntimidatingCryCalculated then @@ -3388,7 +3398,7 @@ function calcs.offence(env, actor, activeSkill) -- a lot of these are doubled up because it would be very long lines otherwise and hopefully this helps legibility globalOutput[skillNameVar.."UptimeRatio"] = uptimeOverride or m_min( (1 / globalOutput.Speed) / globalOutput[skillNameVar.."Cooldown"], 1) * 100 - globalOutput[skillNameVar.."UptimeRatio"] = globalOutput[skillNameVar.."UptimeRatio"] + (globalOutput[additionalSkillNameVar.."UptimeRatio"] or 0) / 2 + globalOutput[skillNameVar.."UptimeRatio"] = m_min(globalOutput[skillNameVar.."UptimeRatio"] + (globalOutput[additionalSkillNameVar.."UptimeRatio"] or 0), 100) if globalBreakdown then globalBreakdown[skillNameVar.."UptimeRatio"] = { s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), @@ -3396,16 +3406,15 @@ function calcs.offence(env, actor, activeSkill) "+", s_format("min( (1 / %.2f) ^8(second per attack)", globalOutput.Speed), s_format("/ %.2f, 1) ^8("..additionalSkillNameLabel.." cooldown)", globalOutput[additionalSkillNameVar.."Cooldown"]), + "capped at 100%", s_format("= %d%%", globalOutput[skillNameVar.."UptimeRatio"]), } end globalOutput["Avg"..skillNameVar.."Damage"] = globalOutput[skillNameVar.."DamageMultiplier"] - globalOutput["Avg"..skillNameVar.."DamageEffect"] = 1 + globalOutput["Avg"..skillNameVar.."Damage"] * (uptimeOverride and uptimeOverride / 100 or (globalOutput[skillNameVar.."UptimeRatio"] / 100)) - globalOutput["Avg"..skillNameVar.."DamageEffect"] = (globalOutput["Avg"..skillNameVar.."DamageEffect"] * (1 + globalOutput["Avg"..additionalSkillNameVar.."Damage"] * globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2)) + globalOutput["Avg"..skillNameVar.."DamageEffect"] = 1 + globalOutput["Avg"..skillNameVar.."Damage"] * (globalOutput[skillNameVar.."UptimeRatio"] / 100) if globalBreakdown then globalBreakdown["Avg"..skillNameVar.."DamageEffect"] = { - s_format("1 + (%.2f x %.2f) ^8("..skillNameLabel.." damage multiplier x ^8"..skillNameLabel.." uptime ratio)", globalOutput[skillNameVar.."DamageMultiplier"], uptimeOverride / 100), - s_format(" + (%.2f x %.2f) ^8("..additionalSkillNameLabel.." damage multiplier x ^8"..additionalSkillNameLabel.." uptime ratio)", globalOutput[additionalSkillNameVar.."DamageMultiplier"], globalOutput[additionalSkillNameVar.."UptimeRatio"] / 100 / 2), + s_format("1 + (%.2f x %.2f) ^8(combined ancestral boost damage multiplier x uptime ratio)", globalOutput[skillNameVar.."DamageMultiplier"], globalOutput[skillNameVar.."UptimeRatio"] / 100), s_format("= %.2f", globalOutput["Avg"..skillNameVar.."DamageEffect"]), } end @@ -3479,9 +3488,9 @@ function calcs.offence(env, actor, activeSkill) if globalOutput.ExertedAttackUptimeRatio > 0 and not globalOutput.ExertedAttackUptimeRatioCalculated then local incExertedAttacks = skillModList:Sum("INC", cfg, "EmpoweredIncrease") if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - skillModList:NewMod("Damage", "INC", incExertedAttacks, "Empowered Attacks") + skillModList:NewMod("Damage", "INC", incExertedAttacks, "Empowered Attacks", ModFlag.Attack) else - skillModList:NewMod("Damage", "INC", incExertedAttacks * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Empowered Attacks") + skillModList:NewMod("Damage", "INC", incExertedAttacks * globalOutput.ExertedAttackUptimeRatio / 100, "Uptime Scaled Empowered Attacks", ModFlag.Attack) end globalOutput.ExertedAttackAvgDmg = calcLib.mod(skillModList, skillCfg, "EmpoweredIncrease") globalOutput.ExertedAttackHitEffect = globalOutput.ExertedAttackAvgDmg * globalOutput.ExertedAttackUptimeRatio / 100 @@ -3515,10 +3524,10 @@ function calcs.offence(env, actor, activeSkill) local incBoostedAttacks = skillModList:Sum("INC", cfg, "AncestralBoostDamage") local incAoEBoostedAttacks = skillModList:Sum("INC", cfg, "AncestralBoostAreaOfEffect") if activeSkill.skillModList:Flag(nil, "Condition:WarcryMaxHit") then - skillModList:NewMod("Damage", "INC", incBoostedAttacks, "Ancestrally Boosted Attacks") + skillModList:NewMod("Damage", "INC", incBoostedAttacks, "Ancestrally Boosted Attacks", ModFlag.Attack) skillModList:NewMod("AreaOfEffect", "INC", incAoEBoostedAttacks, "Ancestrally Boosted Attacks") else - skillModList:NewMod("Damage", "INC", incBoostedAttacks * globalOutput.BoostedAttackUptimeRatio / 100, "Uptime Scaled Ancestrally Boosted Attacks") + skillModList:NewMod("Damage", "INC", incBoostedAttacks * globalOutput.BoostedAttackUptimeRatio / 100, "Uptime Scaled Ancestrally Boosted Attacks", ModFlag.Attack) skillModList:NewMod("AreaOfEffect", "INC", incAoEBoostedAttacks * globalOutput.BoostedAttackUptimeRatio / 100, "Uptime Scaled Ancestrally Boosted AoE") end calcAreaOfEffect(skillModList, skillCfg, skillData, skillFlags, globalOutput, globalBreakdown) @@ -3769,6 +3778,8 @@ function calcs.offence(env, actor, activeSkill) --Calculate reservation DPS globalOutput.ReservationDpsMultiplier = 100 / (100 - enemyDB:Sum("BASE", nil, "LifeReservationPercent")) + buildGainTable() + -- Calculate base hit damage for _, damageType in ipairs(dmgTypeList) do local damageTypeMin = damageType.."Min" diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 38ae5b7228..4d4769fb34 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1231,12 +1231,9 @@ function calcs.perform(env, skipEHP) modDB:NewMod("Condition:HaveCompanion", "FLAG", true, activeSkill.activeEffect.grantedEffect.name) end if env.mode_buffs and skillFlags.warcry then - if activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and not activeSkill.skillModList:Flag(nil, "CannotShareWarcryBuffs") and not modDB:Flag(nil, "RallyingActive") then - env.player.modDB:NewMod("RallyingExertMoreDamagePerAlly", "BASE", activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "RallyingCryExertDamageBonus")) - modDB:NewMod("RallyingActive", "FLAG", true) -- Prevents effect from applying multiple times - elseif activeSkill.activeEffect.grantedEffect.name == "Seismic Cry" and not modDB:Flag(nil, "SeismicActive") then - env.player.modDB:NewMod("SeismicMoreAoE", "BASE", activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "SeismicAoEMoreMultiplier")) - modDB:NewMod("SeismicActive", "FLAG", true) -- Prevents effect from applying multiple times + if activeSkill.activeEffect.grantedEffect.name == "Infernal Cry" and not modDB:Flag(nil, "InfernalActive") then + env.player.modDB:NewMod("InfernalExtraFireDamage", "BASE", activeSkill.skillModList:Sum("BASE", env.player.mainSkill.skillCfg, "InfernalExtraFireDamageMultiplier")) + modDB:NewMod("InfernalActive", "FLAG", true) -- Prevents effect from applying multiple times end end if activeSkill.skillData.triggeredOnDeath and not skillFlags.minion then @@ -1970,19 +1967,22 @@ function calcs.perform(env, skipEHP) if env.mode_buffs then local skillCfg = skillCfg local modStore = skillModList or modDB + local warcryPower = modDB:Override(nil, "WarcryPower") or m_max((modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (modDB:Sum("INC", nil, "WarcryPower") or 0)/100), (modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) + local powerCap = skillModList:Sum("BASE", nil, "WarcryPowerCap") + local powerPer = skillModList:Sum("BASE", nil, "WarcryPowerPer") + local baseEmpowers = m_floor(m_min(warcryPower, powerCap) / powerPer) local warcryName = buff.name:gsub(" Cry", ""):gsub("'s",""):gsub(" ","") - local baseExerts = modStore:Sum("BASE", env.player.mainSkill.skillCfg, warcryName.."ExertedAttacks") - if baseExerts > 0 then - local extraExertions = modStore:Sum("BASE", nil, "ExtraExertedAttacks") or 0 - local exertMultiplier = modStore:More(nil, "ExtraExertedAttacks") - env.player.modDB:NewMod("Num"..warcryName.."Exerts", "BASE", m_floor((baseExerts + extraExertions) * exertMultiplier)) + local baseEmpowers = modStore:Sum("BASE", env.player.mainSkill.skillCfg, warcryName.."EmpoweredAttacks") + baseEmpowers + if baseEmpowers > 0 then + local extraEmpowerions = modStore:Sum("BASE", nil, "ExtraEmpoweredAttacks") or 0 + local EmpowerMultiplier = modStore:More(nil, "ExtraEmpoweredAttacks") + env.player.modDB:NewMod("Num"..warcryName.."Empowers", "BASE", m_floor((baseEmpowers + extraEmpowerions) * EmpowerMultiplier)) if not warcryList[buff.name] then - env.player.modDB:NewMod("Multiplier:ExertingWarcryCount", "BASE", 1, buff.name) + env.player.modDB:NewMod("Multiplier:EmpoweringWarcryCount", "BASE", 1, buff.name) warcryList[buff.name] = true end end if not activeSkill.skillModList:Flag(nil, "CannotShareWarcryBuffs") then - local warcryPower = modDB:Override(nil, "WarcryPower") or m_max((modDB:Sum("BASE", nil, "WarcryPower") or 0) * (1 + (modDB:Sum("INC", nil, "WarcryPower") or 0)/100), (modDB:Sum("BASE", nil, "MinimumWarcryPower") or 0)) for _, warcryBuff in ipairs(buff.modList) do if warcryBuff[1] and warcryBuff[1].effectType == "Warcry" and warcryBuff[1].div then warcryBuff[1].warcryPowerBonus = m_floor((warcryBuff[1].limit and m_min(warcryPower, warcryBuff[1].limit) or warcryPower) / warcryBuff[1].div) @@ -1990,9 +1990,7 @@ function calcs.perform(env, skipEHP) end local full_duration = calcSkillDuration(modStore, skillCfg, activeSkill.skillData, env, enemyDB) local actual_cooldown = calcSkillCooldown(modStore, skillCfg, activeSkill.skillData) - -- need to scale warcry buffs by their actual uptime - local warcryOutputUptime = env.build.calcsTab.mainOutput and ((env.build.calcsTab.mainOutput[warcryName.."CryUptimeRatio"] or 0) / 100) or nil - local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or warcryOutputUptime or m_min(full_duration / actual_cooldown, 1) + local uptime = modDB:Flag(nil, "Condition:WarcryMaxHit") and 1 or m_min(full_duration / actual_cooldown, 1) local extraWarcryModList = activeSkill.activeEffect.grantedEffect.name == "Rallying Cry" and new("ModList") or {} if not modDB:Flag(nil, "CannotGainWarcryBuffs") then if not buff.applyNotPlayer then From f47b3f7ab2b01e5392dc4501c064d5c7b43c6bbf Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Fri, 29 May 2026 00:31:41 +1000 Subject: [PATCH 19/19] Fix spelling --- src/Data/ModCache.lua | 2 +- src/Modules/CalcOffence.lua | 2 +- src/Modules/CalcPerform.lua | 4 ++-- src/Modules/ModParser.lua | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index c9a46e82de..9b06027582 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -4604,7 +4604,7 @@ c["Chance is doubled against Undead and Demons"]={{},"Chance against Undead and c["Chance to Block Damage is Lucky"]={{[1]={flags=0,keywordFlags=0,name="BlockChanceIsLucky",type="FLAG",value=true}},nil} c["Chance to Deflect is Lucky"]={{[1]={flags=0,keywordFlags=0,name="DeflectIsLucky",type="FLAG",value=true}},nil} c["Chance to Evade is Unlucky"]={{[1]={flags=0,keywordFlags=0,name="UnluckyEvade",type="FLAG",value=true}},nil} -c["Chance to Hit with Attacks can exceed 100%"]={{[1]={[1]={skillType=1,type="Skilltype"},flags=0,keywordFlags=0,name="Condition:HitChanceCanExceed100",type="FLAG",value=true}},nil} +c["Chance to Hit with Attacks can exceed 100%"]={{[1]={[1]={skillType=1,type="SkillType"},flags=0,keywordFlags=0,name="Condition:HitChanceCanExceed100",type="FLAG",value=true}},nil} c["Channelling Skills deal 12% increased Damage"]={{[1]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=12}},nil} c["Channelling Skills deal 20% increased Damage"]={{[1]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=20}},nil} c["Channelling Skills deal 25% increased Damage"]={{[1]={[1]={skillType=48,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=25}},nil} diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 6d404a0bb6..ce73d8328b 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3409,7 +3409,7 @@ function calcs.offence(env, actor, activeSkill) -- Condition:AncestrallyBoosted * AncestralBoostEffect (e.g. Fist of War III) local ancestrallyBoostedMoreDamageMulti = skillModList:Sum("BASE", cfg, "AncestralBoostMoreDamage") / 100 - -- dynamic way of calcing the Ancestral Boost from a single source without duplicating the code + -- dynamic way of calculating the Ancestral Boost from a single source without duplicating the code -- uptimeOverride: Ancestral Empowerment -- combinedCalcs: ignore INC AoE as we will run that in calcCombinedAncestralBoost local function calcAncestralBoost(skillName, moreDmg, uptimeOverride, combinedCalcs) diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index 738d6a2116..f17d22d132 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -1989,9 +1989,9 @@ function calcs.perform(env, skipEHP) local warcryName = buff.name:gsub(" Cry", ""):gsub("'s",""):gsub(" ","") local baseEmpowers = modStore:Sum("BASE", env.player.mainSkill.skillCfg, warcryName.."EmpoweredAttacks") + baseEmpowers if baseEmpowers > 0 then - local extraEmpowerions = modStore:Sum("BASE", nil, "ExtraEmpoweredAttacks") or 0 + local extraEmpowers = modStore:Sum("BASE", nil, "ExtraEmpoweredAttacks") or 0 local EmpowerMultiplier = modStore:More(nil, "ExtraEmpoweredAttacks") - env.player.modDB:NewMod("Num"..warcryName.."Empowers", "BASE", m_floor((baseEmpowers + extraEmpowerions) * EmpowerMultiplier)) + env.player.modDB:NewMod("Num"..warcryName.."Empowers", "BASE", m_floor((baseEmpowers + extraEmpowers) * EmpowerMultiplier)) if not warcryList[buff.name] then env.player.modDB:NewMod("Multiplier:EmpoweringWarcryCount", "BASE", 1, buff.name) warcryList[buff.name] = true diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index e85776a981..1178e86a14 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2694,7 +2694,7 @@ local specialModList = { } end, -- Amazon - ["chance to hit with attacks can exceed 100%%"] = {flag("Condition:HitChanceCanExceed100", { type = "Skilltype", skillType = SkillType.Attack})}, + ["chance to hit with attacks can exceed 100%%"] = {flag("Condition:HitChanceCanExceed100", { type = "SkillType", skillType = SkillType.Attack})}, ["gain additional critical hit chance equal to (%d+)%% of excess chance to hit with attacks"] = function(num) return { mod("CritChance", "BASE", 0.01 * num, { type = "Multiplier", var = "ExcessHitChance" }, { type = "SkillType", skillType = SkillType.Attack})} end, ["attacks using your weapons have added (%a+) damage equal to (%d+)%% of the accuracy rating on the weapon"] = function(_, dmgType, num) return { mod(firstToUpper(dmgType) .. "Min", "BASE", 1, nil, ModFlag.Attack, { type = "PercentStat", stat = "AccuracyOnWeapon 1", percent = num }, { type = "SkillType", skillType = SkillType.NonWeaponAttack, neg = true } , { type = "Condition", var = "MainHandAttack" }),