From e53fb9c5efe53087835acca1786394c8ee8f0b77 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Sun, 15 Mar 2026 22:40:44 +1100 Subject: [PATCH] Add support for Black Scythe Training Keystone Adds support for the mod the following mods Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour Correctly apply damage reduction calcs just for physical damage and have it override mods like Transcendence that stops armour from applying to pdr --- src/Data/ModCache.lua | 5 ++--- src/Modules/CalcDefence.lua | 37 ++++++++++++++++++++++++++++--------- src/Modules/ModParser.lua | 8 ++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index ca18a636f8..a35a33c286 100755 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -8093,8 +8093,7 @@ c["Chance to Block Spell Damage is Unlucky"]={{[1]={flags=0,keywordFlags=0,name= c["Chance to Block Spell Damage is doubled"]={{[1]={flags=0,keywordFlags=0,name="SpellBlockChance",type="MORE",value=100}},nil} c["Chance to Block is Lucky"]={{[1]={flags=0,keywordFlags=0,name="BlockChanceIsLucky",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ProjectileBlockChanceIsLucky",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="SpellBlockChanceIsLucky",type="FLAG",value=true},[4]={flags=0,keywordFlags=0,name="SpellProjectileBlockChanceIsLucky",type="FLAG",value=true}},nil} c["Chance to Block is Unlucky"]={{[1]={flags=0,keywordFlags=0,name="BlockChanceIsUnlucky",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ProjectileBlockChanceIsUnlucky",type="FLAG",value=true},[3]={flags=0,keywordFlags=0,name="SpellBlockChanceIsUnlucky",type="FLAG",value=true},[4]={flags=0,keywordFlags=0,name="SpellProjectileBlockChanceIsUnlucky",type="FLAG",value=true}},nil} -c["Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating"]={nil,"Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating "} -c["Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour"]={nil,"Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour "} +c["Chance to Evade Hits is based off of 200% of your Ward instead of your Evasion Rating"]={{[1]={flags=0,keywordFlags=0,name="EvadeChanceBasedOnWard",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="EvadeChanceBasedOnWardPercent",source="Black Scythe Training",type="OVERRIDE",value=200}},nil} c["Chance to Suppress Spell Damage is Lucky"]={{[1]={flags=0,keywordFlags=0,name="SpellSuppressionChanceIsLucky",type="FLAG",value=true}},nil} c["Channelling Skills deal 12% increased Damage"]={{[1]={[1]={skillType=57,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=12}},nil} c["Channelling Skills deal 20% increased Damage"]={{[1]={[1]={skillType=57,type="SkillType"},flags=0,keywordFlags=0,name="Damage",type="INC",value=20}},nil} @@ -10439,7 +10438,7 @@ c["Permanently Intimidate Enemies on Block"]={{[1]={[1]={type="Condition",var="B c["Petrified during Effect"]={nil,"Petrified during Effect "} c["Petrified during Effect +50% Chance to Block Attack Damage during Effect"]={nil,"Petrified during Effect +50% Chance to Block Attack Damage during Effect "} c["Phasing"]={{[1]={flags=0,keywordFlags=0,name="Condition:Phasing",type="FLAG",value=true}},nil} -c["Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour"]={nil,"Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour "} +c["Physical Damage Reduction from Hits is based off of 200% of your Ward instead of your Armour"]={{[1]={flags=0,keywordFlags=0,name="PhysicalReductionBasedOnWard",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalReductionBasedOnWardPercent",source="Black Scythe Training",type="OVERRIDE",value=200}},nil} c["Physical Damage of Enemies Hitting you is Unlucky"]={nil,"Physical Damage of Enemies Hitting you is Unlucky "} c["Physical Damage taken bypasses Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="PhysicalEnergyShieldBypass",type="BASE",value=100}},nil} c["Plague Bearer has 20% increased Maximum Plague Value"]={{}," Maximum Plague Value "} diff --git a/src/Modules/CalcDefence.lua b/src/Modules/CalcDefence.lua index 6def57a06e..74b9583b07 100644 --- a/src/Modules/CalcDefence.lua +++ b/src/Modules/CalcDefence.lua @@ -84,8 +84,13 @@ function calcs.applyDmgTakenConversion(activeSkill, output, breakdown, sourceTyp local reductMult = 1 local percentOfArmourApplies = m_min((not activeSkill.skillModList:Flag(nil, "ArmourDoesNotApplyTo"..damageType.."DamageTaken") and activeSkill.skillModList:Sum("BASE", nil, "ArmourAppliesTo"..damageType.."DamageTaken") or 0), 100) - if percentOfArmourApplies > 0 then + local physicalReductionBasedOnWard = damageType == "Physical" and activeSkill.skillModList:Flag(nil, "PhysicalReductionBasedOnWard") + if percentOfArmourApplies > 0 or physicalReductionBasedOnWard then local effArmour = (output.Armour * percentOfArmourApplies / 100) * (1 + output.ArmourDefense) + if physicalReductionBasedOnWard then + local multiplier = activeSkill.skillModList:Override(nil, "PhysicalReductionBasedOnWardPercent") / 100 + effArmour = output.Ward * multiplier + end local effDamage = damage * resMult armourReduct = round(effArmour ~= 0 and damage * resMult ~= 0 and (effArmour / (effArmour + effDamage * 5) * 100) or 0) armourReduct = m_min(output.DamageReductionMax, armourReduct) @@ -1068,9 +1073,18 @@ function calcs.defence(env, actor) local enemyAccuracy = round(calcLib.val(enemyDB, "Accuracy")) local evadeChance = modDB:Sum("BASE", nil, "EvadeChance") local hitChance = calcLib.mod(enemyDB, nil, "HitChance") - output.EvadeChance = 100 - (calcs.hitChance(output.Evasion, enemyAccuracy) - evadeChance) * hitChance - output.MeleeEvadeChance = m_max(0, m_min(data.misc.EvadeChanceCap, (100 - (calcs.hitChance(output.MeleeEvasion, enemyAccuracy) - evadeChance) * hitChance) * calcLib.mod(modDB, nil, "EvadeChance", "MeleeEvadeChance"))) - output.ProjectileEvadeChance = m_max(0, m_min(data.misc.EvadeChanceCap, (100 - (calcs.hitChance(output.ProjectileEvasion, enemyAccuracy) - evadeChance) * hitChance) * calcLib.mod(modDB, nil, "EvadeChance", "ProjectileEvadeChance"))) + local evadeStat = output.Evasion + local meleeEvadeStat= output.MeleeEvasion + local projectileEvadeStat= output.ProjectileEvasion + if modDB:Flag(nil, "EvadeChanceBasedOnWard") then + local multiplier = modDB:Override(nil, "EvadeChanceBasedOnWardPercent") / 100 + evadeStat = output.Ward * multiplier + meleeEvadeStat = evadeStat + projectileEvadeStat = evadeStat + end + output.EvadeChance = 100 - (calcs.hitChance(evadeStat, enemyAccuracy) - evadeChance) * hitChance + output.MeleeEvadeChance = m_max(0, m_min(data.misc.EvadeChanceCap, (100 - (calcs.hitChance(meleeEvadeStat, enemyAccuracy) - evadeChance) * hitChance) * calcLib.mod(modDB, nil, "EvadeChance", "MeleeEvadeChance"))) + output.ProjectileEvadeChance = m_max(0, m_min(data.misc.EvadeChanceCap, (100 - (calcs.hitChance(projectileEvadeStat, enemyAccuracy) - evadeChance) * hitChance) * calcLib.mod(modDB, nil, "EvadeChance", "ProjectileEvadeChance"))) -- Condition for displaying evade chance only if melee or projectile evade chance have the same values if output.MeleeEvadeChance ~= output.ProjectileEvadeChance then output.splitEvade = true @@ -1087,13 +1101,13 @@ function calcs.defence(env, actor) breakdown.MeleeEvadeChance = { s_format("Enemy level: %d ^8(%s the Configuration tab)", env.enemyLevel, env.configInput.enemyLevel and "overridden from" or "can be overridden in"), s_format("Average enemy accuracy: %d", enemyAccuracy), - s_format("Effective Evasion: %d", output.MeleeEvasion), + s_format("Effective Evasion: %d", meleeEvadeStat), s_format("Approximate melee evade chance: %d%%", output.MeleeEvadeChance), } breakdown.ProjectileEvadeChance = { s_format("Enemy level: %d ^8(%s the Configuration tab)", env.enemyLevel, env.configInput.enemyLevel and "overridden from" or "can be overridden in"), s_format("Average enemy accuracy: %d", enemyAccuracy), - s_format("Effective Evasion: %d", output.ProjectileEvasion), + s_format("Effective Evasion: %d", projectileEvadeStat), s_format("Approximate projectile evade chance: %d%%", output.ProjectileEvadeChance), } end @@ -1942,6 +1956,11 @@ function calcs.buildDefenceEstimations(env, actor) local impaleArmourReduct = 0 local percentOfArmourApplies = m_min((not modDB:Flag(nil, "ArmourDoesNotApplyTo"..damageType.."DamageTaken") and modDB:Sum("BASE", nil, "ArmourAppliesTo"..damageType.."DamageTaken") or 0), 100) local effectiveAppliedArmour = (output.Armour * percentOfArmourApplies / 100) * (1 + output.ArmourDefense) + local physicalReductionBasedOnWard = damageType == "Physical" and modDB:Flag(nil, "PhysicalReductionBasedOnWard") + if physicalReductionBasedOnWard then + local multiplier = modDB:Override(nil, "PhysicalReductionBasedOnWardPercent") / 100 + effectiveAppliedArmour = output.Ward * multiplier + end local resMult = 1 - (resist - enemyPen) / 100 local reductMult = 1 local takenFlat = modDB:Sum("BASE", nil, "DamageTaken", damageType.."DamageTaken", "DamageTakenWhenHit", damageType.."DamageTakenWhenHit") @@ -1953,7 +1972,7 @@ function calcs.buildDefenceEstimations(env, actor) takenFlat = takenFlat + modDB:Sum("BASE", nil, "DamageTakenFromAttacks", damageType.."DamageTakenFromAttacks") / 2 + modDB:Sum("BASE", nil, damageType.."DamageTakenFromProjectileAttacks") / 4 + modDB:Sum("BASE", nil, "DamageTakenFromSpells", damageType.."DamageTakenFromSpells") / 2 + modDB:Sum("BASE", nil, "DamageTakenFromSpellProjectiles", damageType.."DamageTakenFromSpellProjectiles") / 4 end output[damageType.."takenFlat"] = takenFlat - if percentOfArmourApplies > 0 then + if percentOfArmourApplies > 0 or physicalReductionBasedOnWard then armourReduct = calcs.armourReduction(effectiveAppliedArmour, damage * resMult) armourReduct = m_min(output.DamageReductionMax, armourReduct) if impaleDamage > 0 then @@ -1975,7 +1994,7 @@ function calcs.buildDefenceEstimations(env, actor) else t_insert(breakdown[damageType.."DamageReduction"], s_format("Enemy Hit Damage: %d ^8(total incoming damage)", damage)) end - if percentOfArmourApplies ~= 100 then + if percentOfArmourApplies ~= 100 and not physicalReductionBasedOnWard then t_insert(breakdown[damageType.."DamageReduction"], s_format("%d%% percent of armour applies", percentOfArmourApplies)) end t_insert(breakdown[damageType.."DamageReduction"], s_format("Reduction from Armour: %d%%", armourReduct)) @@ -2035,7 +2054,7 @@ function calcs.buildDefenceEstimations(env, actor) else t_insert(breakdown[damageType.."TakenHitMult"], s_format("Enemy Hit Damage: %d ^8(total incoming damage)", damage)) end - if percentOfArmourApplies ~= 100 then + if percentOfArmourApplies ~= 100 and not physicalReductionBasedOnWard then t_insert(breakdown[damageType.."TakenHitMult"], s_format("%d%% percent of armour applies", percentOfArmourApplies)) end t_insert(breakdown[damageType.."TakenHitMult"], s_format("Reduction from Armour: %.2f", 1 - armourReduct / 100)) diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 3377b979eb..01e7a590bc 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -2109,6 +2109,14 @@ local specialModList = { flag("ConvertSpellSuppressionToSpellDodge"), mod("SpellSuppressionChance", "OVERRIDE", 0, "Acrobatics"), }, + ["chance to evade hits is based off of (%d+)%% of your ward instead of your evasion rating"] = function(num) return { + flag("EvadeChanceBasedOnWard"), + mod("EvadeChanceBasedOnWardPercent", "OVERRIDE", num, "Black Scythe Training"), + } end, + ["physical damage reduction from hits is based off of (%d+)%% of your ward instead of your armour"] = function(num) return { + flag("PhysicalReductionBasedOnWard"), + mod("PhysicalReductionBasedOnWardPercent", "OVERRIDE", num, "Black Scythe Training"), + } end, ["maximum chance to dodge spell hits is (%d+)%%"] = function(num) return { mod("SpellDodgeChanceMax", "OVERRIDE", num, "Acrobatics") } end, ["dexterity provides no bonus to evasion rating"] = { flag("NoDexBonusToEvasion") }, ["dexterity provides no inherent bonus to evasion rating"] = { flag("NoDexBonusToEvasion") },