From 268296b57c322b41e38972ed87a5e6e8afe94500 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 1/8] 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 bab988d5c..d4f674cad 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -2328,7 +2328,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} @@ -2566,8 +2566,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} @@ -4343,10 +4342,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 1e2c80fc6..debf76f1b 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -2512,6 +2512,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 612992061..488c28a3f 100644 --- a/src/Data/Skills/sup_int.lua +++ b/src/Data/Skills/sup_int.lua @@ -2584,6 +2584,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 4e04c7162..cc9d89a36 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 0b1786e04..f35d9e4e0 100644 --- a/src/Export/Skills/sup_int.txt +++ b/src/Export/Skills/sup_int.txt @@ -436,6 +436,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 9af608efa..054e6ed8b 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 3e87cc8ac..ddf2dc7bf 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3296,6 +3296,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") @@ -3314,6 +3315,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 @@ -3326,8 +3337,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), @@ -3335,13 +3346,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 @@ -3349,6 +3362,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 @@ -3687,6 +3742,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 @@ -3695,9 +3753,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 ab1596c29..e2bd3f47b 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 a13144ac8..35fb80bab 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2617,6 +2617,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 2673009c18e51f05ba7f4566f7a6e0417c95e16e 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 2/8] 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 ddf2dc7bf..ce58ea2b7 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3316,7 +3316,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 @@ -3380,17 +3380,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 8dd845d1f09ff1387b18468111333a9b4f33741d 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 3/8] 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 ce58ea2b7..19d10c731 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3325,40 +3325,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 @@ -3368,39 +3380,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 06ba100c265ec624749a5b4bbc0b889b4436c701 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 4/8] 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 f0c02d4f3..3bbbfdd2b 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -84,4 +84,21 @@ describe("TestSkills", function() local finalCost = build.calcsTab.mainOutput.ManaCost assert.are.equals(16, round(finalCost)) 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) \ No newline at end of file diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 19d10c731..e659da8be 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3327,6 +3327,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 e2bd3f47b..5e28589ba 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 057b46796adcc4ee79df4cebd2b998b7d928e53d 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 5/8] 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 e659da8be..fce2f6db4 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3321,7 +3321,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 a92579ce6..8a9e98700 100644 --- a/src/Modules/Data.lua +++ b/src/Modules/Data.lua @@ -889,6 +889,7 @@ data.gems = LoadModule("Data/Gems") data.gemForSkill = { } data.gemForBaseName = { } data.gemsByGameId = { } +data.gemNameForModSource = { } -- Lookup table - [Gem.grantedEffectId] = VaalGemId data.gemGrantedEffectIdForVaalGemId = { } data.gemVaalGemIdForBaseGemId = { } @@ -898,6 +899,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 e455da4b0998780ff574d4529ef8295c1f3978d4 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 6/8] 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 721a75876..009e6aa4f 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -189,7 +189,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 4cc27c3e0f2f82ecd32041602abcae1e9aeadbad 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 7/8] 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 3bbbfdd2b..b4e0cabc8 100644 --- a/spec/System/TestSkills_spec.lua +++ b/spec/System/TestSkills_spec.lua @@ -101,4 +101,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) \ No newline at end of file diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index d4f674cad..f7557c521 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -4879,7 +4879,7 @@ c["Every Rage also grants you 1% increased Minion Attack Speed"]={nil,"you 1% in c["Every Rage also grants you 1% increased Minion Attack Speed Every Rage also grants you 1% increased Minion Damage"]={nil,"you 1% increased Minion Attack Speed Every Rage also grants you 1% increased Minion Damage "} c["Every Rage also grants you 1% increased Minion Damage"]={nil,"you 1% increased Minion Damage "} 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 cc9d89a36..30c3c0f27 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 054e6ed8b..63577a7eb 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 fce2f6db4..787bf2431 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3297,6 +3297,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") @@ -3325,8 +3327,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() @@ -3336,11 +3339,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 @@ -3356,12 +3359,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"] @@ -3369,9 +3424,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 @@ -3727,6 +3794,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 @@ -3735,9 +3808,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 5e28589ba..a55c31202 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 35fb80bab..f5d03c4a0 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2620,6 +2620,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 7c68390625b6dc060a15c80a161ae47f0e32bb31 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 8/8] 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 787bf2431..20c6699d2 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -3369,7 +3369,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