From 4b3ae4e6d669f1c53b326b0a2b3dcb82180c51eb Mon Sep 17 00:00:00 2001 From: DS_Koala Date: Thu, 5 Mar 2026 23:36:50 -0500 Subject: [PATCH 1/2] Add support for thorns crit and ignore armour passives --- src/Data/ModCache.lua | 14 ++++++-------- src/Modules/CalcOffence.lua | 17 ++++++++++++++++- src/Modules/ModParser.lua | 14 ++++++++++++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 2bd89bc8a..34eae29bd 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -361,8 +361,7 @@ c["+25% to Critical Damage Bonus against Stunned Enemies"]={{[1]={[1]={actor="en c["+25% to Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="FireResist",type="BASE",value=25}},nil} c["+25% to Fire Resistance while on Low Life"]={{[1]={[1]={type="Condition",var="LowLife"},flags=0,keywordFlags=0,name="FireResist",type="BASE",value=25}},nil} c["+25% to Lightning Resistance"]={{[1]={flags=0,keywordFlags=0,name="LightningResist",type="BASE",value=25}},nil} -c["+25% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=25}}," Thorns "} -c["+25% to Thorns Critical Hit Chance 15 to 25 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=25}}," Thorns 15 to 25 Physical Thorns damage "} +c["+25% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="ThornsCritChance",type="BASE",value=25}},nil} c["+250 to Accuracy Rating"]={{[1]={flags=0,keywordFlags=0,name="Accuracy",type="BASE",value=250}},nil} c["+250 to Accuracy against Bleeding Enemies"]={{[1]={[1]={actor="enemy",type="ActorCondition",var="Bleeding"},flags=0,keywordFlags=0,name="AccuracyVsEnemy",type="BASE",value=250}},nil} c["+250 to Ailment Threshold"]={{[1]={flags=0,keywordFlags=0,name="AilmentThreshold",type="BASE",value=250}},nil} @@ -695,8 +694,7 @@ c["+4% to Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance", c["+4% to Maximum Cold Resistance"]={{[1]={flags=0,keywordFlags=0,name="ColdResistMax",type="BASE",value=4}},nil} c["+4% to Maximum Fire Resistance"]={{[1]={flags=0,keywordFlags=0,name="FireResistMax",type="BASE",value=4}},nil} c["+4% to Maximum Lightning Resistance"]={{[1]={flags=0,keywordFlags=0,name="LightningResistMax",type="BASE",value=4}},nil} -c["+4% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=4}}," Thorns "} -c["+4% to Thorns Critical Hit Chance Gain Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=4}}," Thorns Gain Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour "} +c["+4% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="ThornsCritChance",type="BASE",value=4}},nil} c["+4% to all Elemental Resistances per socketed Grand Spectrum"]={{[1]={[1]={type="Multiplier",var="GrandSpectrum"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=4}},nil} c["+4% to maximum Block chance"]={{[1]={flags=0,keywordFlags=0,name="BlockChanceMax",type="BASE",value=4}},nil} c["+40 to Accuracy Rating"]={{[1]={flags=0,keywordFlags=0,name="Accuracy",type="BASE",value=40}},nil} @@ -784,7 +782,7 @@ c["+6 to Level of all Projectile Skills"]={{[1]={flags=0,keywordFlags=0,name="Ge c["+6 to all Attributes"]={{[1]={flags=0,keywordFlags=0,name="Str",type="BASE",value=6},[2]={flags=0,keywordFlags=0,name="Dex",type="BASE",value=6},[3]={flags=0,keywordFlags=0,name="Int",type="BASE",value=6},[4]={flags=0,keywordFlags=0,name="All",type="BASE",value=6}},nil} c["+6 to all Attributes per Socket filled"]={{[1]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="Str",type="BASE",value=6},[2]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="Dex",type="BASE",value=6},[3]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="Int",type="BASE",value=6},[4]={[1]={type="Multiplier",var="RunesSocketedIn{SlotName}"},flags=0,keywordFlags=0,name="All",type="BASE",value=6}},nil} c["+6% to Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=6}},nil} -c["+6% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=6}}," Thorns "} +c["+6% to Thorns Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="ThornsCritChance",type="BASE",value=6}},nil} c["+6% to all Elemental Resistances per socketed Grand Spectrum"]={{[1]={[1]={type="Multiplier",var="GrandSpectrum"},flags=0,keywordFlags=0,name="ElementalResist",type="BASE",value=6}},nil} c["+6.5% to Critical Hit Chance"]={{[1]={flags=0,keywordFlags=0,name="CritChance",type="BASE",value=6.5}},nil} c["+60 to Accuracy Rating"]={{[1]={flags=0,keywordFlags=0,name="Accuracy",type="BASE",value=60}},nil} @@ -2445,7 +2443,7 @@ c["30% increased Stun Recovery"]={{[1]={flags=0,keywordFlags=0,name="StunRecover c["30% increased Stun Threshold"]={{[1]={flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=30}},nil} c["30% increased Stun Threshold if you haven't been Stunned Recently"]={{[1]={[1]={neg=true,type="Condition",var="StunnedRecently"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=30}},nil} c["30% increased Stun Threshold while on Full Life"]={{[1]={[1]={type="Condition",var="FullLife"},flags=0,keywordFlags=0,name="StunThreshold",type="INC",value=30}},nil} -c["30% increased Thorns Critical Damage Bonus"]={{[1]={flags=0,keywordFlags=0,name="CritMultiplier",type="INC",value=30}}," Thorns "} +c["30% increased Thorns Critical Damage Bonus"]={{[1]={flags=0,keywordFlags=0,name="ThornsCritMultiplier",type="INC",value=30}},nil} c["30% increased Totem Duration"]={{[1]={flags=0,keywordFlags=0,name="TotemDuration",type="INC",value=30}},nil} c["30% increased Totem Life"]={{[1]={flags=0,keywordFlags=0,name="TotemLife",type="INC",value=30}},nil} c["30% increased Totem Placement speed"]={{[1]={flags=0,keywordFlags=0,name="TotemPlacementSpeed",type="INC",value=30}},nil} @@ -6046,8 +6044,8 @@ c["This item gains bonuses from Socketed Items as though it was a Helmet"]={nil, c["This item gains bonuses from Socketed Items as though it was a Helmet This item gains bonuses from Socketed Items as though it was a Shield"]={nil,"This item gains bonuses from Socketed Items as though it was a Helmet This item gains bonuses from Socketed Items as though it was a Shield "} c["This item gains bonuses from Socketed Items as though it was a Shield"]={nil,"This item gains bonuses from Socketed Items as though it was a Shield "} c["This item gains bonuses from Socketed Items as though it was a Shield 100% increased effect of Socketed Items"]={nil,"This item gains bonuses from Socketed Items as though it was a Shield 100% increased effect of Socketed Items "} -c["Thorns Damage has 25% chance to ignore Enemy Armour"]={nil,"Thorns Damage has 25% chance to ignore Enemy Armour "} -c["Thorns Damage has 50% chance to ignore Enemy Armour"]={nil,"Thorns Damage has 50% chance to ignore Enemy Armour "} +c["Thorns Damage has 25% chance to ignore Enemy Armour"]={{[1]={flags=0,keywordFlags=0,name="ThornsChanceToIgnoreEnemyArmour",type="BASE",value=25}},nil} +c["Thorns Damage has 50% chance to ignore Enemy Armour"]={{[1]={flags=0,keywordFlags=0,name="ThornsChanceToIgnoreEnemyArmour",type="BASE",value=50}},nil} c["Thorns can Retaliate against all Hits"]={nil,"Thorns can Retaliate against all Hits "} c["Totems Regenerate 3% of maximum Life per second"]={nil,"Totems Regenerate 3% of maximum Life per second "} c["Totems die 6 seconds after their Life is reduced to 0"]={nil,"Totems die 6 seconds after their Life is reduced to 0 "} diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index 7f237aa2f..f6753d220 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -727,10 +727,25 @@ function calcs.offence(env, actor, activeSkill) end if skillModList:Flag(nil, "ThornsDamageAppliesToHits") then -- Caltrops mod - for i, value in ipairs(skillModList:Tabulate("INC", { }, "ThornsDamage")) do + for i, value in ipairs(skillModList:Tabulate("INC", { }, "ThornsDamage")) do local mod = value.mod skillModList:NewMod("Damage", "INC", mod.value, mod.source, ModFlag.Hit, mod.keywordFlags, unpack(mod)) end + -- Increased Thorns critical damage bonus + for i, value in ipairs(skillModList:Tabulate("INC", { }, "ThornsCritMultiplier")) do + local mod = value.mod + skillModList:NewMod("CritMultiplier", "INC", mod.value, mod.source, 0, 0) + end + -- +#% to Thorns critical hit chance + for _, value in ipairs(skillModList:Tabulate("BASE", {}, "ThornsCritChance")) do + local mod = value.mod + skillModList:NewMod("CritChance", "BASE", mod.value, mod.source, 0, 0) + end + -- Thorns damage has +#% chance to ignore enemy armour + for _, value in ipairs(skillModList:Tabulate("BASE", {}, "ThornsChanceToIgnoreEnemyArmour")) do + local mod = value.mod + skillModList:NewMod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", mod.value, mod.source, 0, 0) + end end if skillModList:Flag(nil, "CastSpeedAppliesToAttacks") then -- Get all increases for this; assumption is that multiple sources would not stack, so find the max diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index 3feb3402a..fe0f78a2a 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3433,10 +3433,20 @@ local specialModList = { }end, ["take (%d+) (.+) damage when herald of thunder hits an enemy"] = function(dmg, _, dmgType) return { mod("StormSecretSelfDamage", "LIST", {baseDamage = dmg, damageType = dmgType}) - }end, + } end, ["your skills deal you (%d+)%% of mana cost as (.+) damage"] = function(dmgMult, _, dmgType) return { mod("ScoldsBridleSelfDamage", "LIST", {dmgMult = dmgMult, damageType = dmgType}) - }end, + } end, + -- Thorns + ["(%d+)%% increased thorns critical damage bonus"] = function(num) return { + mod("ThornsCritMultiplier", "INC", num) + } end, + ["%+(%d+)%% to thorns critical hit chance"] = function(num) return { + mod("ThornsCritChance", "BASE", num) + } end, + ["thorns damage has (%d+)%% chance to ignore enemy armour"] = function(num) return { + mod("ThornsChanceToIgnoreEnemyArmour", "BASE", num) + } end, -- Extra skill/support ["grants skill: (%D+)"] = function(_, skill) return grantedExtraSkill(skill, 1) end, ["grants skill: level (%d+) (.+)"] = function(num, _, skill) return grantedExtraSkill(skill, num) end, From 65f53913b1a13d73dae6c3921fee37d2d0c1d0b9 Mon Sep 17 00:00:00 2001 From: DS_Koala Date: Fri, 6 Mar 2026 12:51:35 -0500 Subject: [PATCH 2/2] Add thorns damage support and thorns-based support interactions --- src/Data/ModCache.lua | 32 ++++++++------ src/Data/SkillStatMap.lua | 2 +- src/Data/Skills/other.lua | 80 +++++++++++++++++++++++++++++++++++ src/Data/Skills/sup_str.lua | 69 ++++++++++++++++++++++++++++++ src/Export/Skills/sup_str.txt | 21 +++++++++ src/Modules/CalcOffence.lua | 56 +++++++++++++++++++----- src/Modules/CalcPerform.lua | 5 +++ src/Modules/CalcSections.lua | 4 +- src/Modules/CalcSetup.lua | 37 ++++++++++++++++ src/Modules/ConfigOptions.lua | 5 +++ src/Modules/ModParser.lua | 56 +++++++++++++++++++++++- 11 files changed, 338 insertions(+), 29 deletions(-) diff --git a/src/Data/ModCache.lua b/src/Data/ModCache.lua index 34eae29bd..ec05672a5 100644 --- a/src/Data/ModCache.lua +++ b/src/Data/ModCache.lua @@ -1369,6 +1369,7 @@ c["125% increased Charges per use"]={{[1]={flags=0,keywordFlags=0,name="FlaskCha c["125% increased Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=125}},nil} c["125% increased Evasion Rating"]={{[1]={flags=0,keywordFlags=0,name="Evasion",type="INC",value=125}},nil} c["125% increased Evasion and Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="EvasionAndEnergyShield",type="INC",value=125}},nil} +c["13 to 23 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=13},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=23}},nil} c["13% increased Attack Speed"]={{[1]={flags=1,keywordFlags=0,name="Speed",type="INC",value=13}},nil} c["13% increased Block chance"]={{[1]={flags=0,keywordFlags=0,name="BlockChance",type="INC",value=13}},nil} c["13% increased Cast Speed"]={{[1]={flags=16,keywordFlags=0,name="Speed",type="INC",value=13}},nil} @@ -1404,8 +1405,7 @@ c["140% increased Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="EnergyShie c["140% increased Evasion Rating"]={{[1]={flags=0,keywordFlags=0,name="Evasion",type="INC",value=140}},nil} c["140% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=140}},nil} c["15 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=15}},nil} -c["15 to 25 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=15}}," to 25 Physical "} -c["15 to 25 Physical Thorns damage Thorns can Retaliate against all Hits"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=15}}," to 25 Physical Thorns can Retaliate against all Hits "} +c["15 to 25 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=15},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=25}},nil} c["15% additional Physical Damage Reduction"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamageReduction",type="BASE",value=15}},nil} c["15% chance for Remnants you create to grant their effects twice"]={{[1]={flags=0,keywordFlags=0,name="LocalEffect",type="BASE",value=15}}," for Remnants you create to grant their s twice "} c["15% chance for Shapeshift Slam Skills you use yourself to cause an additional Aftershock"]={{}," for Shapeshift Slam Skills you use yourself to cause an additional Aftershock "} @@ -1670,6 +1670,7 @@ c["175% increased Armour, Evasion and Energy Shield"]={{[1]={flags=0,keywordFlag c["175% increased Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=175}},nil} c["175% increased Evasion and Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="EvasionAndEnergyShield",type="INC",value=175}},nil} c["175% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=175}},nil} +c["18 to 28 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=18},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=28}},nil} c["18% increased Area of Effect for Attacks"]={{[1]={flags=1,keywordFlags=0,name="AreaOfEffect",type="INC",value=18}},nil} c["18% increased Armour"]={{[1]={flags=0,keywordFlags=0,name="Armour",type="INC",value=18}},nil} c["18% increased Attack Speed"]={{[1]={flags=1,keywordFlags=0,name="Speed",type="INC",value=18}},nil} @@ -1732,7 +1733,7 @@ c["2% reduced Light Radius per 10 Tribute"]={{[1]={[1]={actor="parent",div=10,st c["2% reduced Movement Speed Penalty from using Skills while moving"]={{[1]={flags=0,keywordFlags=0,name="MovementSpeedPenalty",type="INC",value=-2}},nil} c["2% reduced Presence Area of Effect per 10 Tribute"]={{[1]={[1]={actor="parent",div=10,stat="Tribute",type="PerStat"},flags=0,keywordFlags=0,name="PresenceArea",type="INC",value=-2}},nil} c["20 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=20}},nil} -c["20 to 30 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=20}}," to 30 Physical "} +c["20 to 30 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=20},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=30}},nil} c["20% Chance to build an additional Combo on Hit"]={{}," to build an additional Combo "} c["20% chance for Attack Hits to apply Incision"]={{[1]={flags=0,keywordFlags=0,name="Condition:CanInflictIncision",type="FLAG",value=true}},nil} c["20% chance for Bleeding to be Aggravated when Inflicted against Enemies on Jagged Ground"]={{}," to be Aggravated when Inflicted against Enemies on Jagged Ground "} @@ -2036,8 +2037,8 @@ c["24% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keyw c["24% reduced Slowing Potency of Debuffs on You"]={{}," Slowing Potency of Debuffs on You "} c["240% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=240}},nil} c["25 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=25}},nil} -c["25 to 35 Cold Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=25}}," to 35 Cold "} -c["25 to 35 Fire Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=25}}," to 35 Fire "} +c["25 to 35 Cold Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="ColdThornsMin",type="BASE",value=25},[3]={flags=0,keywordFlags=0,name="ColdThornsMax",type="BASE",value=35}},nil} +c["25 to 35 Fire Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="FireThornsMin",type="BASE",value=25},[3]={flags=0,keywordFlags=0,name="FireThornsMax",type="BASE",value=35}},nil} c["25% Chance to gain a Charge when you kill an enemy"]={nil,"a Charge "} c["25% Chance to gain a Charge when you kill an enemy Creates Ignited Ground for 4 seconds when used, Igniting enemies as though dealing Fire damage equal to 500% of your maximum Life"]={nil,"a Charge Creates Ignited Ground when used, Igniting enemies as though dealing Fire damage equal to 500% of your maximum Life "} c["25% Chance to gain a Charge when you kill an enemy Energy Shield Recharge starts on use"]={nil,"a Charge Energy Shield Recharge starts on use "} @@ -2242,8 +2243,10 @@ c["250% increased bonuses gained from Equipped Quiver"]={{[1]={flags=0,keywordFl c["250% of Melee Physical Damage taken reflected to Attacker"]={{[1]={flags=256,keywordFlags=0,name="PhysicalDamage",type="BASE",value=250}}," taken reflected to Attacker "} c["250% of Melee Physical Damage taken reflected to Attacker Regenerate 5% of maximum Life per second while Surrounded"]={{[1]={[1]={type="Condition",var="Surrounded"},flags=256,keywordFlags=0,name="PhysicalDamage",type="BASE",value=250}}," taken reflected to Attacker Regenerate 5% of maximum Life per second "} c["253% increased Spell Damage"]={{[1]={flags=2,keywordFlags=0,name="Damage",type="INC",value=253}},nil} +c["26 to 40 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=26},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=40}},nil} c["26% reduced Charges per use"]={{[1]={flags=0,keywordFlags=0,name="FlaskChargesUsed",type="INC",value=-26}},nil} c["275% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=275}},nil} +c["28 to 38 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=28},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=38}},nil} c["28% increased maximum Energy Shield"]={{[1]={[1]={type="Global"},flags=0,keywordFlags=0,name="EnergyShield",type="INC",value=28}},nil} c["29% increased Chaos Damage"]={{[1]={flags=0,keywordFlags=0,name="ChaosDamage",type="INC",value=29}},nil} c["3 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=3}},nil} @@ -2303,7 +2306,8 @@ c["3% reduced Movement Speed Penalty from using Skills while moving"]={{[1]={fla c["3% reduced Skill Speed"]={{[1]={flags=0,keywordFlags=0,name="Speed",type="INC",value=-3},[2]={flags=0,keywordFlags=0,name="WarcrySpeed",type="INC",value=-3},[3]={flags=0,keywordFlags=0,name="TotemPlacementSpeed",type="INC",value=-3}},nil} c["3% reduced maximum Life"]={{[1]={flags=0,keywordFlags=0,name="Life",type="INC",value=-3}},nil} c["30 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=30}},nil} -c["30 to 40 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=30}}," to 40 Physical "} +c["30 to 40 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=30},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=40}},nil} +c["30 to 44 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=30},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=44}},nil} c["30% chance for Lightning Damage with Hits to be Lucky"]={{[1]={flags=0,keywordFlags=0,name="LightningLuckyHitsChance",type="BASE",value=30}},nil} c["30% chance to Avoid Chaos Damage from Hits"]={{[1]={flags=0,keywordFlags=0,name="AvoidChaosDamageChance",type="BASE",value=30}},nil} c["30% chance to Avoid Cold Damage from Hits"]={{[1]={flags=0,keywordFlags=0,name="AvoidColdDamageChance",type="BASE",value=30}},nil} @@ -2504,7 +2508,7 @@ c["300% increased Armour and Evasion"]={{[1]={flags=0,keywordFlags=0,name="Armou c["300% increased Armour, Evasion and Energy Shield"]={{[1]={flags=0,keywordFlags=0,name="Defences",type="INC",value=300}},nil} c["300% increased Evasion Rating"]={{[1]={flags=0,keywordFlags=0,name="Evasion",type="INC",value=300}},nil} c["300% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=300}},nil} -c["31 to 49 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=31}}," to 49 Physical "} +c["31 to 49 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=31},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=49}},nil} c["32% increased Spell Damage while wielding a Melee Weapon"]={{[1]={[1]={type="Condition",var="UsingMeleeWeapon"},flags=2,keywordFlags=0,name="Damage",type="INC",value=32}},nil} c["325% increased Physical Damage"]={{[1]={flags=0,keywordFlags=0,name="PhysicalDamage",type="INC",value=325}},nil} c["33% increased Damage with Hits against Enemies affected by Ailments"]={{[1]={[1]={actor="enemy",type="ActorCondition",varList={[1]="Frozen",[2]="Chilled",[3]="Shocked",[4]="Ignited",[5]="Scorched",[6]="Brittle",[7]="Sapped",[8]="Poisoned",[9]="Bleeding"}},flags=0,keywordFlags=262144,name="Damage",type="INC",value=33}},nil} @@ -2515,7 +2519,7 @@ c["33% of Elemental Damage Converted to Fire Damage"]={{[1]={flags=0,keywordFlag c["33% of Elemental Damage Converted to Lightning Damage"]={{[1]={flags=0,keywordFlags=0,name="ElementalDamageConvertToLightning",type="BASE",value=33}},nil} c["333% increased effect of Socketed Soul Cores"]={{[1]={flags=0,keywordFlags=0,name="SocketedSoulCoreEffect",type="INC",value=333}},nil} c["35 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=35}},nil} -c["35 to 53 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=35}}," to 53 Physical "} +c["35 to 53 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=35},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=53}},nil} c["35% increased Attack Damage while you have an Ally in your Presence"]={{[1]={[1]={threshold=1,type="MultiplierThreshold",var="NearbyAlly"},flags=1,keywordFlags=0,name="Damage",type="INC",value=35}},nil} c["35% increased Attack Speed"]={{[1]={flags=1,keywordFlags=0,name="Speed",type="INC",value=35}},nil} c["35% increased Charges"]={{[1]={flags=0,keywordFlags=0,name="FlaskCharges",type="INC",value=35}},nil} @@ -2559,6 +2563,7 @@ c["375% increased Armour and Evasion"]={{[1]={flags=0,keywordFlags=0,name="Armou c["38% increased Armour"]={{[1]={flags=0,keywordFlags=0,name="Armour",type="INC",value=38}},nil} c["38% increased Duration"]={{[1]={flags=0,keywordFlags=0,name="Duration",type="INC",value=38}},nil} c["4 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=4}},nil} +c["4 to 8 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=4},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=8}},nil} c["4% chance for Spell Skills to fire 2 additional Projectiles"]={{[1]={flags=2,keywordFlags=0,name="TwoAdditionalProjectilesChance",type="BASE",value=4}},nil} c["4% chance that if you would gain Rage on Hit, you instead gain up to your maximum Rage"]={{[1]={flags=4,keywordFlags=0,name="MaximumRage",type="BASE",value=4}}," that if you would gain Rage , you instead gain up to your "} c["4% increased Area of Effect"]={{[1]={flags=0,keywordFlags=0,name="AreaOfEffect",type="INC",value=4}},nil} @@ -2762,8 +2767,8 @@ c["450% increased Armour and Evasion"]={{[1]={flags=0,keywordFlags=0,name="Armou c["48% increased Spirit"]={{[1]={flags=0,keywordFlags=0,name="Spirit",type="INC",value=48}},nil} c["5 Life Regeneration per second"]={{[1]={flags=0,keywordFlags=0,name="LifeRegen",type="BASE",value=5}},nil} c["5 Mana gained when you Block"]={{[1]={flags=0,keywordFlags=0,name="ManaOnBlock",type="BASE",value=5}},nil} -c["5 to 10 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=5}}," to 10 Physical "} -c["5 to 10 Physical Thorns damage Pain Attunement"]={{[1]={flags=0,keywordFlags=0,name="ThornsDamage",type="BASE",value=5}}," to 10 Physical Pain Attunement "} +c["5 to 10 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=5},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=10}},nil} +c["5 to 9 Physical Thorns damage"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=5},[3]={flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=9}},nil} c["5% Chance to build an additional Combo on Hit"]={{}," to build an additional Combo "} c["5% additional Physical Damage Reduction while you have at least 150 Devotion"]={{[1]={[1]={stat="Devotion",threshold=150,type="StatThreshold"},flags=0,keywordFlags=0,name="PhysicalDamageReduction",type="BASE",value=5}},nil} c["5% chance for Slam Skills you use yourself to cause an additional Aftershock"]={{}," for Slam Skills you use yourself to cause an additional Aftershock "} @@ -5079,10 +5084,9 @@ c["Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Lif c["Gain Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds"]={nil,"Infernal Flame instead of spending Mana for Skill costs Take maximum Life and Energy Shield as Fire Damage when Infernal Flame reaches maximum Lose all Infernal Flame on reaching maximum Infernal Flame 25% of Infernal Flame lost per second if none was gained in the past 2 seconds "} c["Gain Onslaught for 4 seconds when a Minion Dies"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Condition:Onslaught",type="FLAG",value=true}}}}," when a Dies "} c["Gain Onslaught for 4 seconds when a Minion Dies 18% increased Area of Effect for Attacks"]={{[1]={flags=0,keywordFlags=0,name="MinionModifier",type="LIST",value={mod={flags=0,keywordFlags=0,name="Condition:Onslaught",type="FLAG",value=true}}}}," when a Dies 18% increased for Attacks "} -c["Gain Physical Thorns damage equal to 10% of Item Armour on Equipped Body Armour"]={nil,"Physical Thorns damage equal to 10% of Item Armour on Equipped Body Armour "} -c["Gain Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour"]={nil,"Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour "} -c["Gain Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour 12% chance for Trigger skills to refund half of Energy Spent"]={nil,"Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour 12% chance for Trigger skills to refund half of Energy Spent "} -c["Gain Physical Thorns damage equal to 8% of maximum Life while Shapeshifted"]={nil,"Physical Thorns damage equal to 8% of maximum Life while Shapeshifted "} +c["Gain Physical Thorns damage equal to 10% of Item Armour on Equipped Body Armour"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={[1]={div=10,stat="ArmourOnBody Armour",type="PerStat"},flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=1},[3]={[1]={div=10,stat="ArmourOnBody Armour",type="PerStat"},flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=1}},nil} +c["Gain Physical Thorns damage equal to 6% of Item Armour on Equipped Body Armour"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={[1]={div=16.666666666667,stat="ArmourOnBody Armour",type="PerStat"},flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=1},[3]={[1]={div=16.666666666667,stat="ArmourOnBody Armour",type="PerStat"},flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=1}},nil} +c["Gain Physical Thorns damage equal to 8% of maximum Life while Shapeshifted"]={{[1]={flags=0,keywordFlags=0,name="GrantsThorns",type="FLAG",value=true},[2]={[1]={percent=8,stat="Life",type="PercentStat"},[2]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="PhysicalThornsMin",type="BASE",value=1},[3]={[1]={percent=8,stat="Life",type="PercentStat"},[2]={type="Condition",var="Shapeshifted"},flags=0,keywordFlags=0,name="PhysicalThornsMax",type="BASE",value=1}},nil} c["Gain Power Charges instead of Frenzy Charges"]={nil,"Power Charges instead of Frenzy Charges "} c["Gain Power Charges instead of Frenzy Charges Gain Frenzy Charges instead of Endurance Charges"]={nil,"Power Charges instead of Frenzy Charges Gain Frenzy Charges instead of Endurance Charges "} c["Gain Power Charges instead of Frenzy Charges Gain Frenzy Charges instead of Endurance Charges Gain Endurance Charges instead of Power Charges"]={nil,"Power Charges instead of Frenzy Charges Gain Frenzy Charges instead of Endurance Charges Gain Endurance Charges instead of Power Charges "} diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index 99a3e994c..ee8448980 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -996,7 +996,7 @@ return { mod("ImprovedSpellDamageAppliesToAttacks", "MAX", nil), }, ["additive_thorns_damage_modifiers_apply_to_attack_damage"] = { - flag("ThornsDamageAppliesToHits"), + flag("ThornsModifiersApplyToHits"), }, ["active_skill_main_hand_weapon_damage_+%_final"] = { mod("Damage", "MORE", nil, 0, 0, { type = "Condition", var = "MainHandAttack" }), diff --git a/src/Data/Skills/other.lua b/src/Data/Skills/other.lua index 138b5395e..dc197aa12 100644 --- a/src/Data/Skills/other.lua +++ b/src/Data/Skills/other.lua @@ -228,6 +228,86 @@ skills["AcidicConcoctionPlayer"] = { }, } } +skills["ThornsPlayer"] = { + name = "Thorns", + hidden = true, + fromItem = true, + skillTypes = { [SkillType.Damage] = true }, + qualityStats = {}, + levels = { + [1] = { levelRequirement = 0 }, + }, + preDamageFunc = function(activeSkill, output, breakdown) + local skillModList = activeSkill.skillModList + local cfg = activeSkill.skillCfg + + if activeSkill.actor and activeSkill.actor.modDB and activeSkill.actor.modDB:Flag(nil, "Condition:Shapeshifted") then + skillModList:NewMod("Condition:Shapeshifted", "FLAG", true, "Thorns") + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsDamage")) do + local mod = value.mod + skillModList:NewMod("Damage", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + local function remapThornsBase(fromStat, toStat) + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, fromStat)) do + local mod = value.mod + skillModList:NewMod(toStat, "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + end + + remapThornsBase("PhysicalThornsMin", "PhysicalMin") + remapThornsBase("PhysicalThornsMax", "PhysicalMax") + remapThornsBase("FireThornsMin", "FireMin") + remapThornsBase("FireThornsMax", "FireMax") + remapThornsBase("ColdThornsMin", "ColdMin") + remapThornsBase("ColdThornsMax", "ColdMax") + remapThornsBase("LightningThornsMin", "LightningMin") + remapThornsBase("LightningThornsMax", "LightningMax") + remapThornsBase("ChaosThornsMin", "ChaosMin") + remapThornsBase("ChaosThornsMax", "ChaosMax") + + -- Crit calculations + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, "ThornsCritChance")) do + local mod = value.mod + skillModList:NewMod("CritChance", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsCritChance")) do + local mod = value.mod + skillModList:NewMod("CritChance", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsCritMultiplier")) do + local mod = value.mod + skillModList:NewMod("CritMultiplier", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, "ThornsChanceToIgnoreEnemyArmour")) do + local mod = value.mod + skillModList:NewMod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + end, + statSets = { + [1] = { + label = "Thorns", + incrementalEffectiveness = 0, + statDescriptionScope = "skill_stat_descriptions", + baseFlags = { + thorns = true, + }, + baseMods = { + flag("CannotBleed"), + flag("CannotPoison"), + }, + constantStats = {}, + stats = {}, + levels = { + [1] = {}, + }, + }, + } +} skills["AlignFatePlayer"] = { name = "Align Fate", baseTypeName = "Align Fate", diff --git a/src/Data/Skills/sup_str.lua b/src/Data/Skills/sup_str.lua index 4e04c7162..be100f27d 100644 --- a/src/Data/Skills/sup_str.lua +++ b/src/Data/Skills/sup_str.lua @@ -540,6 +540,11 @@ skills["SupportBarbsPlayer"] = { label = "Barbs I", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["deal_thorns_damage_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + }, + }, baseFlags = { }, constantStats = { @@ -571,6 +576,11 @@ skills["SupportBarbsPlayerTwo"] = { label = "Barbs II", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["deal_thorns_damage_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + }, + }, baseFlags = { }, constantStats = { @@ -602,6 +612,12 @@ skills["SupportBarbsPlayerThree"] = { label = "Barbs III", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["deal_thorns_damage_twice_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + flag("BarbsThornsTwiceOnHit"), + }, + }, baseFlags = { }, constantStats = { @@ -5200,6 +5216,11 @@ skills["SupportQuillburstPlayer"] = { label = "Quill Burst", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["trigger_spiked_gauntlets_for_X_hits_after_thorns_trigger"] = { + flag("EnableTriggeredQuillburst"), + }, + }, baseFlags = { }, constantStats = { @@ -5221,6 +5242,53 @@ skills["TriggeredQuillburstPlayer"] = { castTime = 1, qualityStats = { }, + preDamageFunc = function(activeSkill, output, breakdown) + local skillModList = activeSkill.skillModList + local cfg = activeSkill.skillCfg + + local function remapThornsBase(fromStat, toStat) + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, fromStat)) do + local mod = value.mod + skillModList:NewMod(toStat, "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsDamage")) do + local mod = value.mod + skillModList:NewMod("Damage", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + remapThornsBase("PhysicalThornsMin", "PhysicalMin") + remapThornsBase("PhysicalThornsMax", "PhysicalMax") + remapThornsBase("FireThornsMin", "FireMin") + remapThornsBase("FireThornsMax", "FireMax") + remapThornsBase("ColdThornsMin", "ColdMin") + remapThornsBase("ColdThornsMax", "ColdMax") + remapThornsBase("LightningThornsMin", "LightningMin") + remapThornsBase("LightningThornsMax", "LightningMax") + remapThornsBase("ChaosThornsMin", "ChaosMin") + remapThornsBase("ChaosThornsMax", "ChaosMax") + + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, "ThornsCritChance")) do + local mod = value.mod + skillModList:NewMod("CritChance", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsCritChance")) do + local mod = value.mod + skillModList:NewMod("CritChance", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("INC", cfg, "ThornsCritMultiplier")) do + local mod = value.mod + skillModList:NewMod("CritMultiplier", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + for _, value in ipairs(skillModList:Tabulate("BASE", cfg, "ThornsChanceToIgnoreEnemyArmour")) do + local mod = value.mod + skillModList:NewMod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + end, levels = { [1] = { cooldown = 0.15, levelRequirement = 0, storedUses = 1, }, }, @@ -5230,6 +5298,7 @@ skills["TriggeredQuillburstPlayer"] = { incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "triggered_spiked_gauntlets", baseFlags = { + thorns = true, }, constantStats = { { "triggered_by_spiked_gauntlets_support_%", 100 }, diff --git a/src/Export/Skills/sup_str.txt b/src/Export/Skills/sup_str.txt index 9af608efa..436209a26 100644 --- a/src/Export/Skills/sup_str.txt +++ b/src/Export/Skills/sup_str.txt @@ -107,16 +107,32 @@ statMap = { #skill SupportBarbsPlayer #set SupportBarbsPlayer +statMap = { + ["deal_thorns_damage_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + }, +} #mods #skillEnd #skill SupportBarbsPlayerTwo #set SupportBarbsPlayerTwo +statMap = { + ["deal_thorns_damage_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + }, +} #mods #skillEnd #skill SupportBarbsPlayerThree #set SupportBarbsPlayerThree +statMap = { + ["deal_thorns_damage_twice_on_hit_for_X_hits_after_thorns_trigger"] = { + flag("ThornsDamageAppliesToHits"), + flag("BarbsThornsTwiceOnHit"), + }, +} #mods #skillEnd @@ -1211,6 +1227,11 @@ statMap = { #skill SupportQuillburstPlayer #set SupportQuillburstPlayer +statMap = { + ["trigger_spiked_gauntlets_for_X_hits_after_thorns_trigger"] = { + flag("EnableTriggeredQuillburst"), + }, +} #mods #skillEnd diff --git a/src/Modules/CalcOffence.lua b/src/Modules/CalcOffence.lua index f6753d220..6dba5c744 100644 --- a/src/Modules/CalcOffence.lua +++ b/src/Modules/CalcOffence.lua @@ -725,28 +725,62 @@ function calcs.offence(env, actor, activeSkill) end end end - if skillModList:Flag(nil, "ThornsDamageAppliesToHits") then - -- Caltrops mod - for i, value in ipairs(skillModList:Tabulate("INC", { }, "ThornsDamage")) do + + -- Apply thorns-derived modifiers to hits + if skillModList:Flag(nil, "ThornsModifiersApplyToHits") or skillModList:Flag(nil, "ThornsDamageAppliesToHits") then + -- % increased Thorns damage + for _, value in ipairs(skillModList:Tabulate("INC", {}, "ThornsDamage")) do local mod = value.mod skillModList:NewMod("Damage", "INC", mod.value, mod.source, ModFlag.Hit, mod.keywordFlags, unpack(mod)) end - -- Increased Thorns critical damage bonus - for i, value in ipairs(skillModList:Tabulate("INC", { }, "ThornsCritMultiplier")) do + + -- Thorns crit chance + for _, value in ipairs(skillModList:Tabulate("BASE", {}, "ThornsCritChance")) do local mod = value.mod - skillModList:NewMod("CritMultiplier", "INC", mod.value, mod.source, 0, 0) + skillModList:NewMod("CritChance", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) end - -- +#% to Thorns critical hit chance - for _, value in ipairs(skillModList:Tabulate("BASE", {}, "ThornsCritChance")) do + for _, value in ipairs(skillModList:Tabulate("INC", {}, "ThornsCritChance")) do local mod = value.mod - skillModList:NewMod("CritChance", "BASE", mod.value, mod.source, 0, 0) + skillModList:NewMod("CritChance", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) end - -- Thorns damage has +#% chance to ignore enemy armour + + -- Thorns crit multiplier + for _, value in ipairs(skillModList:Tabulate("INC", {}, "ThornsCritMultiplier")) do + local mod = value.mod + skillModList:NewMod("CritMultiplier", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + end + + -- Thorns chance to ignore enemy armour for _, value in ipairs(skillModList:Tabulate("BASE", {}, "ThornsChanceToIgnoreEnemyArmour")) do local mod = value.mod - skillModList:NewMod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", mod.value, mod.source, 0, 0) + skillModList:NewMod("ChanceToIgnoreEnemyPhysicalDamageReduction", "BASE", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) end end + + -- Apply full thorns damage payload to hits + if skillModList:Flag(nil, "ThornsDamageAppliesToHits") then + local multiplier = skillModList:Flag(nil, "BarbsThornsTwiceOnHit") and 2 or 1 + + local function remapThornsBase(fromStat, toStat) + for _, value in ipairs(skillModList:Tabulate("BASE", {}, fromStat)) do + local mod = value.mod + skillModList:NewMod(toStat, "BASE", mod.value * multiplier, mod.source, ModFlag.Hit, mod.keywordFlags, unpack(mod)) + end + end + + -- Base thorns damage to hits + remapThornsBase("PhysicalThornsMin", "PhysicalMin") + remapThornsBase("PhysicalThornsMax", "PhysicalMax") + remapThornsBase("FireThornsMin", "FireMin") + remapThornsBase("FireThornsMax", "FireMax") + remapThornsBase("ColdThornsMin", "ColdMin") + remapThornsBase("ColdThornsMax", "ColdMax") + remapThornsBase("LightningThornsMin", "LightningMin") + remapThornsBase("LightningThornsMax", "LightningMax") + remapThornsBase("ChaosThornsMin", "ChaosMin") + remapThornsBase("ChaosThornsMax", "ChaosMax") + end + if skillModList:Flag(nil, "CastSpeedAppliesToAttacks") then -- Get all increases for this; assumption is that multiple sources would not stack, so find the max local multiplier = (skillModList:Max(skillCfg, "ImprovedCastSpeedAppliesToAttacks") or 100) / 100 diff --git a/src/Modules/CalcPerform.lua b/src/Modules/CalcPerform.lua index cd5a2bc12..f0817355d 100644 --- a/src/Modules/CalcPerform.lua +++ b/src/Modules/CalcPerform.lua @@ -265,6 +265,11 @@ local function doActorAttribsConditions(env, actor) condList["Channelling"] = true end end + + if env.configInput.conditionShapeshifted then + condList["Shapeshifted"] = true + end + if actor.mainSkill.skillTypes[SkillType.Bear] then condList["Shapeshifted"] = true condList["BearForm"] = true diff --git a/src/Modules/CalcSections.lua b/src/Modules/CalcSections.lua index ab1596c29..e037a3a12 100644 --- a/src/Modules/CalcSections.lua +++ b/src/Modules/CalcSections.lua @@ -623,7 +623,7 @@ return { } } } }, { 1, "SkillTypeStats", 1, colorCodes.OFFENCE, {{ defaultCollapsed = false, label = "Skill type-specific Stats", data = { - { label = "Gem Level", haveOutput = "GemHasLevel", { format = "{0:output:GemLevel}", { breakdown = "GemLevel" }, { modName = { "GemLevel" }, cfg = "skill" },{ modName = { "GemSupportLevel" }, cfg = "skill" }, { modName = { "GemItemLevel" }, cfg = "skill" }, }, }, + { label = "Gem Level", notFlag = "thorns", haveOutput = "GemHasLevel", { format = "{0:output:GemLevel}", { breakdown = "GemLevel" }, { modName = { "GemLevel" }, cfg = "skill" }, { modName = { "GemSupportLevel" }, cfg = "skill" }, { modName = { "GemItemLevel" }, cfg = "skill" }, }, }, { label = "Spirit Cost", color = colorCodes.SPIRIT, haveOutput = "SpiritHasCost", { format = "{0:output:SpiritCost}", { breakdown = "SpiritCost" }, { modName = { "SpiritCost", "Cost", "SpiritCostNoMult" }, cfg = "skill" }, }, }, { label = "Spirit % Cost", color = colorCodes.SPIRIT, haveOutput = "SpiritPercentHasCost", { format = "{0:output:SpiritPercentCost}", { breakdown = "SpiritPercentCost" }, { modName = { "SpiritCost", "Cost", "SpiritCostNoMult" }, cfg = "skill" }, }, }, { label = "Mana Cost", color = colorCodes.MANA, haveOutput = "ManaHasCost", { format = "{0:output:ManaCost}", { breakdown = "ManaCost" }, { modName = { "ManaCost", "Cost", "ManaCostNoMult" }, cfg = "skill" }, }, }, @@ -721,7 +721,7 @@ return { { modName = { "CurseDelay" }, cfg = "skill" }, { modName = { "CurseActivation" }, cfg = "skill" }, } }, - { label = "Curse Limit", haveOutput = "EnemyCurseLimit", { format = "{0:output:EnemyCurseLimit}", + { label = "Curse Limit", notFlag = "thorns", haveOutput = "EnemyCurseLimit", { format = "{0:output:EnemyCurseLimit}", { breakdown = "EnemyCurseLimit" }, { modName = { "CurseLimitIsMaximumPowerCharges", "EnemyCurseLimit" } }, }, }, diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 58f354d66..2bd246e00 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -196,6 +196,10 @@ function calcs.buildModListForNode(env, node, incSmallPassiveSkill, includeKeyst if modList:Flag(nil, "CanExplode") then t_insert(env.explodeSources, node) end + + if modList:Flag(nil, "GrantsThorns") then + t_insert(env.thornsSources, node) + end for i, mod in ipairs(modList) do local added = false @@ -548,6 +552,7 @@ function calcs.initEnv(build, mode, override, specEnv) env.grantedSkillsNodes = { } env.grantedSkillsItems = { } env.explodeSources = { } + env.thornsSources = { } env.itemWarnings = { } env.flasks = { } env.charms = { } @@ -832,6 +837,9 @@ function calcs.initEnv(build, mode, override, specEnv) if item and item.baseModList and item.baseModList:Flag(nil, "CanExplode") then t_insert(env.explodeSources, item) end + if item and item.baseModList and item.baseModList:Flag(nil, "GrantsThorns") then + t_insert(env.thornsSources, item) + end if slot.weaponSet and slot.weaponSet ~= (build.itemsTab.activeItemSet.useSecondWeaponSet and 2 or 1) then goto continue end @@ -1462,6 +1470,35 @@ function calcs.initEnv(build, mode, override, specEnv) build.skillsTab:ProcessSocketGroup(group) end + if #env.thornsSources ~= 0 then + local group + for _, socketGroup in pairs(build.skillsTab.socketGroupList) do + if socketGroup.source == "Thorns" then + group = socketGroup + break + end + end + if not group then + group = { label = "Thorns", enabled = true, gemList = { }, source = "Thorns", noSupports = true } + t_insert(build.skillsTab.socketGroupList, group) + end + + group.thornsSources = env.thornsSources + wipeTable(group.gemList) + + local activeGemInstance = { + skillId = "ThornsPlayer", + quality = 0, + enabled = true, + level = 1, + triggered = true, + } + t_insert(group.gemList, activeGemInstance) + markList[group] = true + build.skillsTab:ProcessSocketGroup(group) + end + + -- Remove any socket groups that no longer have a matching item local i = 1 while build.skillsTab.socketGroupList[i] do diff --git a/src/Modules/ConfigOptions.lua b/src/Modules/ConfigOptions.lua index 721a75876..48b346a3d 100644 --- a/src/Modules/ConfigOptions.lua +++ b/src/Modules/ConfigOptions.lua @@ -1203,6 +1203,11 @@ Huge sets the radius to 11. { var = "multiplierStunnedRecently", type = "count", label = "# of times Stunned Recently:", ifOption = "conditionStunnedRecently", defaultPlaceholderState = 1, apply = function(val, modList, enemyModList) modList:NewMod("Multiplier:StunnedRecently", "BASE", m_min(val, 100), "Config", { type = "Condition", var = "Combat" }, { type = "Condition", var = "StunnedRecently" } ) end }, + { var = "conditionShapeshifted", type = "check", label = "Currently Shapeshifted?", apply = function(val, modList, enemyModList) + if val then + modList:NewMod("Condition:Shapeshifted", "FLAG", true, "Config") + end + end }, { var = "conditionShapeshiftToAnimal", type = "check", label = "Shapeshifted to animal recently?", ifSkillType = { SkillType.Bear, SkillType.Wolf, SkillType.Wyvern }, apply = function(val, modList, enemyModList) modList:NewMod("Condition:ShapeshiftToAnimal", "FLAG", true, "Config", { type = "Condition", var = "Combat" }) end }, diff --git a/src/Modules/ModParser.lua b/src/Modules/ModParser.lua index fe0f78a2a..f12df65f7 100644 --- a/src/Modules/ModParser.lua +++ b/src/Modules/ModParser.lua @@ -3437,16 +3437,70 @@ local specialModList = { ["your skills deal you (%d+)%% of mana cost as (.+) damage"] = function(dmgMult, _, dmgType) return { mod("ScoldsBridleSelfDamage", "LIST", {dmgMult = dmgMult, damageType = dmgType}) } end, - -- Thorns + + -- Thorns base damage + ["(%d+) to (%d+) physical thorns damage"] = function(_, minStr, maxStr) + return { + flag("GrantsThorns"), + mod("PhysicalThornsMin", "BASE", tonumber(minStr)), + mod("PhysicalThornsMax", "BASE", tonumber(maxStr)), + } + end, + ["(%d+) to (%d+) fire thorns damage"] = function(_, minStr, maxStr) + return { + flag("GrantsThorns"), + mod("FireThornsMin", "BASE", tonumber(minStr)), + mod("FireThornsMax", "BASE", tonumber(maxStr)), + } + end, + ["(%d+) to (%d+) cold thorns damage"] = function(_, minStr, maxStr) + return { + flag("GrantsThorns"), + mod("ColdThornsMin", "BASE", tonumber(minStr)), + mod("ColdThornsMax", "BASE", tonumber(maxStr)), + } + end, + ["(%d+) to (%d+) lightning thorns damage"] = function(_, minStr, maxStr) + return { + flag("GrantsThorns"), + mod("LightningThornsMin", "BASE", tonumber(minStr)), + mod("LightningThornsMax", "BASE", tonumber(maxStr)), + } + end, + ["(%d+) to (%d+) chaos thorns damage"] = function(_, minStr, maxStr) + return { + flag("GrantsThorns"), + mod("ChaosThornsMin", "BASE", tonumber(minStr)), + mod("ChaosThornsMax", "BASE", tonumber(maxStr)), + } + end, + + -- Thorns critical modifiers ["(%d+)%% increased thorns critical damage bonus"] = function(num) return { mod("ThornsCritMultiplier", "INC", num) } end, + ["(%d+)%% increased thorns critical hit chance"] = function(num) return { + mod("ThornsCritChance", "INC", num) + } end, ["%+(%d+)%% to thorns critical hit chance"] = function(num) return { mod("ThornsCritChance", "BASE", num) } end, + + -- Thorns (other damage modifiers) ["thorns damage has (%d+)%% chance to ignore enemy armour"] = function(num) return { mod("ThornsChanceToIgnoreEnemyArmour", "BASE", num) } end, + ["gain physical thorns damage equal to (%d+)%% of item armour on equipped body armour"] = function(num) return { + flag("GrantsThorns"), + mod("PhysicalThornsMin", "BASE", 1, { type = "PerStat", stat = "ArmourOnBody Armour", div = 100 / tonumber(num) }), + mod("PhysicalThornsMax", "BASE", 1, { type = "PerStat", stat = "ArmourOnBody Armour", div = 100 / tonumber(num) }), + } end, + ["gain physical thorns damage equal to (%d+)%% of maximum life while shapeshifted"] = function(num) return { + flag("GrantsThorns"), + mod("PhysicalThornsMin", "BASE", 1, { type = "PercentStat", stat = "Life", percent = tonumber(num) }, { type = "Condition", var = "Shapeshifted" }), + mod("PhysicalThornsMax", "BASE", 1, { type = "PercentStat", stat = "Life", percent = tonumber(num) }, { type = "Condition", var = "Shapeshifted" }), + } end, + -- Extra skill/support ["grants skill: (%D+)"] = function(_, skill) return grantedExtraSkill(skill, 1) end, ["grants skill: level (%d+) (.+)"] = function(num, _, skill) return grantedExtraSkill(skill, num) end,