Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
12 changes: 5 additions & 7 deletions src/Data/ModCache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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 "}
Expand Down
7 changes: 7 additions & 0 deletions src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
5 changes: 5 additions & 0 deletions src/Data/Skills/sup_int.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
18 changes: 18 additions & 0 deletions src/Data/Skills/sup_str.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
},
Expand Down Expand Up @@ -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 },
},
Expand Down
5 changes: 5 additions & 0 deletions src/Export/Skills/sup_int.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 14 additions & 0 deletions src/Export/Skills/sup_str.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
86 changes: 63 additions & 23 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -3314,41 +3315,77 @@ function calcs.offence(env, actor, activeSkill)
local ruthlessBlowStunEffect = (ruthlessBlowChance / 100) * ruthlessBlowStunMultiplier
skillModList:NewMod("EnemyHeavyStunBuildup", "MORE", ruthlessBlowStunEffect * 100, "Ruthless Blows")

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
-- passive nodes
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
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" })
end

-- 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()

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
globalOutput.AvgFistOfWarDamageEffect = 1 + globalOutput.FistOfWarDamageMultiplier * (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
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")
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") / 100 * globalOutput.FistOfWarUptimeRatio), "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

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
end
end

-- Calculate maximum sustainable fuses and explosion rate for Explosive Arrow
Expand Down Expand Up @@ -3687,6 +3724,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
Expand All @@ -3695,9 +3735,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
Expand Down
Loading
Loading