Skip to content
Closed
1 change: 1 addition & 0 deletions src/Data/Global.lua
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ ModFlag.Spell = 0x0000000000000002
ModFlag.Hit = 0x0000000000000004
ModFlag.Dot = 0x0000000000000008
ModFlag.Cast = 0x0000000000000010
ModFlag.Thorns = 0x0000000000000020
-- Damage sources
ModFlag.Melee = 0x0000000000000100
ModFlag.Area = 0x0000000000000200
Expand Down
83 changes: 42 additions & 41 deletions src/Data/ModCache.lua

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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" }),
Expand Down
27 changes: 27 additions & 0 deletions src/Data/Skills/other.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9300,3 +9300,30 @@ skills["VoidIllusionSpawnPlayer"] = {
},
}
}
skills["ThornsPlayer"] = {
name = "Thorns",
hidden = true,
fromItem = true,
skillTypes = { [SkillType.Damage] = true },
qualityStats = {},
levels = {
[1] = { levelRequirement = 0 },
},
statSets = {
[1] = {
label = "Thorns",
incrementalEffectiveness = 0,
statDescriptionScope = "skill_stat_descriptions",
baseFlags = {
thorns = true,
},
baseMods = {
},
constantStats = {},
stats = {},
levels = {
[1] = {},
},
},
}
}
6 changes: 6 additions & 0 deletions src/Data/Skills/sup_int.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2354,6 +2354,12 @@ skills["SupportCracklingBarrierPlayer"] = {
label = "Crackling Barrier",
incrementalEffectiveness = 0.054999999701977,
statDescriptionScope = "gem_stat_descriptions",
statMap = {
["return_%_of_maximum_mana_as_lightning_damage_to_attacker_while_channelling"] = {
mod("LightningMin", "BASE", nil, ModFlag.Thorns, 0, { type = "PercentStat", stat = "Mana", percent = 1 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Crackling Barrier" }, { type = "Condition", var = "Channelling" }),
mod("LightningMax", "BASE", nil, ModFlag.Thorns, 0, { type = "PercentStat", stat = "Mana", percent = 1 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Crackling Barrier" }, { type = "Condition", var = "Channelling" }),
},
},
baseFlags = {
},
constantStats = {
Expand Down
26 changes: 24 additions & 2 deletions src/Data/Skills/sup_str.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -5230,6 +5251,7 @@ skills["TriggeredQuillburstPlayer"] = {
incrementalEffectiveness = 0.054999999701977,
statDescriptionScope = "triggered_spiked_gauntlets",
baseFlags = {
thorns = true,
},
constantStats = {
{ "triggered_by_spiked_gauntlets_support_%", 100 },
Expand Down Expand Up @@ -6993,7 +7015,7 @@ skills["SupportThornskinPlayer"] = {
statDescriptionScope = "gem_stat_descriptions",
statMap = {
["support_thorns_spirit_cost_thorns_damage_+%"] = {
mod("ThornsDamage", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
mod("Damage", "INC", nil, ModFlag.Thorns, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
},
},
baseFlags = {
Expand Down Expand Up @@ -7029,7 +7051,7 @@ skills["SupportThornskinPlayerTwo"] = {
statDescriptionScope = "gem_stat_descriptions",
statMap = {
["support_thorns_spirit_cost_thorns_damage_+%"] = {
mod("ThornsDamage", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
mod("Damage", "INC", nil, ModFlag.Thorns, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
},
},
baseFlags = {
Expand Down
27 changes: 27 additions & 0 deletions src/Export/Skills/other.txt
Original file line number Diff line number Diff line change
Expand Up @@ -774,3 +774,30 @@ skills["EnemyExplode"] = {
},
}
}
skills["ThornsPlayer"] = {
name = "Thorns",
hidden = true,
fromItem = true,
skillTypes = { [SkillType.Damage] = true },
qualityStats = {},
levels = {
[1] = { levelRequirement = 0 },
},
statSets = {
[1] = {
label = "Thorns",
incrementalEffectiveness = 0,
statDescriptionScope = "skill_stat_descriptions",
baseFlags = {
thorns = true,
},
baseMods = {
},
constantStats = {},
stats = {},
levels = {
[1] = {},
},
},
}
}
6 changes: 6 additions & 0 deletions src/Export/Skills/sup_int.txt
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ statMap = {

#skill SupportCracklingBarrierPlayer
#set SupportCracklingBarrierPlayer
statMap = {
["return_%_of_maximum_mana_as_lightning_damage_to_attacker_while_channelling"] = {
mod("LightningMin", "BASE", nil, ModFlag.Thorns, 0, { type = "PercentStat", stat = "Mana", percent = 1 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Crackling Barrier" }, { type = "Condition", var = "Channelling" }),
mod("LightningMax", "BASE", nil, ModFlag.Thorns, 0, { type = "PercentStat", stat = "Mana", percent = 1 }, { type = "GlobalEffect", effectType = "Buff", effectName = "Crackling Barrier" }, { type = "Condition", var = "Channelling" }),
},
},
#mods
#skillEnd

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

Expand Down Expand Up @@ -1211,11 +1227,17 @@ statMap = {

#skill SupportQuillburstPlayer
#set SupportQuillburstPlayer
statMap = {
["trigger_spiked_gauntlets_for_X_hits_after_thorns_trigger"] = {
flag("EnableTriggeredQuillburst"),
},
},
#mods
#skillEnd

#skill TriggeredQuillburstPlayer
#set TriggeredQuillburstPlayer
#flags thorns
#mods thorns area
#skillEnd

Expand Down Expand Up @@ -1590,7 +1612,7 @@ statMap = {
#set SupportThornskinPlayer
statMap = {
["support_thorns_spirit_cost_thorns_damage_+%"] = {
mod("ThornsDamage", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
mod("Damage", "INC", nil, ModFlag.Thorns, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
},
},
#mods
Expand All @@ -1600,7 +1622,7 @@ statMap = {
#set SupportThornskinPlayerTwo
statMap = {
["support_thorns_spirit_cost_thorns_damage_+%"] = {
mod("ThornsDamage", "INC", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
mod("Damage", "INC", nil, ModFlag.Thorns, 0, { type = "GlobalEffect", effectType = "Buff", effectName = "Thornskin" }),
},
},
#mods
Expand Down
2 changes: 2 additions & 0 deletions src/Modules/CalcActiveSkill.lua
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ function calcs.buildActiveSkillModList(env, activeSkill)
end
if skillFlags.attack or skillFlags.nonWeaponAttack then
skillModFlags = bor(skillModFlags, ModFlag.Attack)
elseif skillFlags.thorns then
skillModFlags = bor(skillModFlags, ModFlag.Thorns)
else
skillModFlags = bor(skillModFlags, ModFlag.Cast)
if skillFlags.spell then
Expand Down
58 changes: 54 additions & 4 deletions src/Modules/CalcOffence.lua
Original file line number Diff line number Diff line change
Expand Up @@ -725,13 +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", { flags = ModFlag.Thorns }, "Damage")) do
local mod = value.mod
skillModList:NewMod("Damage", "INC", mod.value, mod.source, ModFlag.Hit, mod.keywordFlags, unpack(mod))
end

-- Thorns crit chance
for _, value in ipairs(skillModList:Tabulate("BASE", { flags = ModFlag.Thorns }, "CritChance")) 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", { flags = ModFlag.Thorns }, "CritChance")) do
local mod = value.mod
skillModList:NewMod("CritChance", "INC", mod.value, mod.source, mod.flags, mod.keywordFlags, unpack(mod))
end

-- Thorns crit multiplier
for _, value in ipairs(skillModList:Tabulate("INC", { flags = ModFlag.Thorns }, "CritMultiplier")) 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", { flags = ModFlag.Thorns }, "ChanceToIgnoreEnemyArmour")) do
local mod = value.mod
skillModList:NewMod("ChanceToIgnoreEnemyArmour", "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)
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
Expand Down Expand Up @@ -3740,6 +3789,7 @@ function calcs.offence(env, actor, activeSkill)
enemyDB:ReplaceMod("Armour", "OVERRIDE", -enemyDB:Sum("BASE", { source = "Config" }, "Armour"), "ArmourBreak", { type = "Condition", var = "ArmourBrokenBelowZeroMax" }, { type = "GlobalEffect", effectType= "Debuff", effectName = "ArmourBreak" }) -- if Config is set to Max, add mod with max value (use replace to avoid doubling)
end
local enemyArmour = enemyDB:Override(nil, "Armour") or m_max(calcLib.val(enemyDB, "Armour"), enemyArmourMin)
local chanceIgnoreEnemyArmour = m_min(skillModList:Sum("BASE", cfg, "ChanceToIgnoreEnemyArmour") / 100, 1)
local ignoreEnemyArmour = skillModList:Flag(cfg, "IgnoreEnemyArmour") and enemyArmour or calcLib.val(enemyDB, "IgnoreArmour") -- check for mods that ignore Armour
if ignoreEnemyArmour and (enemyArmour > 0) then enemyArmour = m_max(enemyArmour - ignoreEnemyArmour, 0) end -- subtract ignored value up to zero, if Armour is still positive (to allow future support of negative Armour)
local armourReduction = calcs.armourReductionF(enemyArmour, damageTypeHitAvg * skillModList:More(cfg, "CalcArmourAsThoughDealing"))
Expand All @@ -3754,7 +3804,7 @@ function calcs.offence(env, actor, activeSkill)
if skillModList:Flag(cfg, "IgnoreEnemyPhysicalDamageReduction") or ChanceToIgnoreEnemyPhysicalDamageReduction >= 100 then
resist = 0
else
resist = m_min(m_max(-data.misc.NegArmourDmgBonusCap, enemyDB:Sum("BASE", nil, "PhysicalDamageReduction") + skillModList:Sum("BASE", cfg, "EnemyPhysicalDamageReduction") + armourReduction), data.misc.EnemyPhysicalDamageReductionCap)
resist = m_min(m_max(-data.misc.NegArmourDmgBonusCap, enemyDB:Sum("BASE", nil, "PhysicalDamageReduction") + skillModList:Sum("BASE", cfg, "EnemyPhysicalDamageReduction") + armourReduction * (1 - chanceIgnoreEnemyArmour)), data.misc.EnemyPhysicalDamageReductionCap)
resist = resist > 0 and resist * (1 - (skillModList:Sum("BASE", nil, "PartialIgnoreEnemyPhysicalDamageReduction") / 100 + ChanceToIgnoreEnemyPhysicalDamageReduction / 100)) or resist
end
else
Expand Down
5 changes: 5 additions & 0 deletions src/Modules/CalcPerform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/Modules/CalcSections.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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" }, }, },
Expand Down Expand Up @@ -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" } },
}, },
Expand Down
Loading