From ce619e0456c9670bb028940f45e389bb7cba9f72 Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 18 Aug 2025 12:20:14 +0200 Subject: [PATCH 1/8] Add 'totem' flag to Vile Effusion (Dark Effigy) The 'totem' flag was missing for the damaging part of the skill --- src/Data/Skills/act_int.lua | 1 + src/Export/Skills/act_int.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Skills/act_int.lua b/src/Data/Skills/act_int.lua index 65a78e71b1..9433c3abbe 100644 --- a/src/Data/Skills/act_int.lua +++ b/src/Data/Skills/act_int.lua @@ -4532,6 +4532,7 @@ skills["DarkEffigyProjectilePlayer"] = { spell = true, area = true, projectile = true, + totem = true, }, constantStats = { { "skill_disabled_unless_cloned", 2 }, diff --git a/src/Export/Skills/act_int.txt b/src/Export/Skills/act_int.txt index eb207d7f81..104c6fe888 100644 --- a/src/Export/Skills/act_int.txt +++ b/src/Export/Skills/act_int.txt @@ -305,7 +305,7 @@ statMap = { #skill DarkEffigyProjectilePlayer #set DarkEffigyProjectilePlayer -#flags spell area projectile +#flags spell area projectile totem #mods #skillEnd From 2894493848931210b773c37dd257fec0dc93a06a Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 18 Aug 2025 12:46:50 +0200 Subject: [PATCH 2/8] Fix `addFlags` parsing `addFlags` functionality was accidentally broken in #62 because `mainSkillFlags` and `calcSkillFlags` variables were introduced but seemingly later made redundant to use the original `skillFlags`. However the `addFlags` section still checked the old variables which were now `nil`. This wasn't a problem until now, because the PoE2 skills had not used `addFlags` yet. --- src/Modules/CalcActiveSkill.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index af6c3301d1..313752648a 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -165,8 +165,7 @@ function calcs.createActiveSkill(activeEffect, supportList, env, actor, socketGr if supportEffect.grantedEffect.addFlags and not summonSkill then -- Support skill adds flags to supported skills (eg. Remote Mine adds 'mine') for k in pairs(supportEffect.grantedEffect.addFlags) do - mainSkillFlags[k] = true - calcsSkillFlags[k] = true + skillFlags[k] = true end end end From 6d491140ba78d127497cb975420c52e5d3597bc4 Mon Sep 17 00:00:00 2001 From: majochem Date: Tue, 19 Aug 2025 16:05:39 +0200 Subject: [PATCH 3/8] Remove "Base" mod for "ActiveTotemLimit" `CalcSetup` previous added +1 to "ActiveTotemLimit" as a base, but totem skills in PoE2 always come with "base_number_of_totems_allowed" values, which led to the values always being 1 too high --- src/Modules/CalcSetup.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcSetup.lua b/src/Modules/CalcSetup.lua index 6616314dc2..70f2a28dce 100644 --- a/src/Modules/CalcSetup.lua +++ b/src/Modules/CalcSetup.lua @@ -55,7 +55,6 @@ function calcs.initModDB(env, modDB) modDB:NewMod("WarcryCastTime", "BASE", 0.8, "Base") modDB:NewMod("TotemPlacementTime", "BASE", 0.6, "Base") modDB:NewMod("BallistaPlacementTime", "BASE", 0.35, "Base") - modDB:NewMod("ActiveTotemLimit", "BASE", 1, "Base") modDB:NewMod("ShockStacksMax", "BASE", 1, "Base") modDB:NewMod("ChillStacksMax", "BASE", 1, "Base") modDB:NewMod("ScorchStacksMax", "BASE", 1, "Base") @@ -1759,6 +1758,7 @@ function calcs.initEnv(build, mode, override, specEnv) end end + -- Merge Requirements Tables env.requirementsTable = tableConcat(env.requirementsTableItems, env.requirementsTableGems) From 52d2b9a51940b34ad76162fbf5830eee704ab969 Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 25 Aug 2025 16:52:31 +0200 Subject: [PATCH 4/8] Let "Ancestral Warrior Totem" add the `totem` flag --- src/Data/Skills/act_str.lua | 3 +++ src/Export/Skills/act_str.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua index d9400662be..e36383006e 100644 --- a/src/Data/Skills/act_str.lua +++ b/src/Data/Skills/act_str.lua @@ -145,6 +145,9 @@ skills["SupportAncestralWarriorTotemPlayer"] = { name = "SupportAncestralWarriorTotemPlayer", hidden = true, support = true, + addFlags = { + totem = true, + }, requireSkillTypes = { SkillType.Attack, }, addSkillTypes = { SkillType.UsedByTotem, }, excludeSkillTypes = { SkillType.Meta, SkillType.Triggered, SkillType.Cooldown, SkillType.Channel, SkillType.Persistent, }, diff --git a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt index 8d6b70aa79..797fb1b7b6 100644 --- a/src/Export/Skills/act_str.txt +++ b/src/Export/Skills/act_str.txt @@ -12,6 +12,9 @@ local skills, mod, flag, skill = ... #skillEnd #skill SupportAncestralWarriorTotemPlayer + addFlags = { + totem = true, + }, #set SupportAncestralWarriorTotemPlayer #flags #mods From 14e9d24c7fe11b8d74c29d79f598ff70ff1f0606 Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 25 Aug 2025 17:16:55 +0200 Subject: [PATCH 5/8] Get totem stats from "base" totem skill This fixes previous problems that were caused by totem skills consisting of multiple parts, such as inability to get correct skillTotemId and level requirement for the "active" portion of a totem skill. The skill (or support) that provides the baseTotem data is now identified within `CalcActiveSkill` Examples: - "Shockwave Totem" -> "Wave" would not show correct totem stats - "Sunder" attached to "Ancestral Warrior Totem" would not show any totem stats at all --- src/Modules/CalcActiveSkill.lua | 61 ++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index 313752648a..b3cf05b900 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -231,6 +231,47 @@ local function getWeaponFlags(env, weaponData, weaponTypes) return flags, info end +-- Get stats from totem base skill in case of separate active skills or "totemification" via supports +---@param activeSkill table @activeSkill with totem tag +local function getTotemBaseStats(activeSkill) + local totemBase = {} + + if activeSkill.skillTypes[SkillType.SummonsTotem] then -- Skill that summons totems already has stats on activeEffect + totemBase.grantedEffect = activeSkill.activeEffect.grantedEffect + totemBase.gemData = activeSkill.activeEffect.gemData + totemBase.skillLevel = activeSkill.activeEffect.level + elseif activeSkill.skillTypes[SkillType.UsedByTotem] then + if activeSkill.activeEffect.grantedEffect.skillTypes[SkillType.UsedByTotem] then -- is totem skill by default + totemBase.grantedEffect = activeSkill.activeEffect.gemData.grantedEffect + totemBase.gemData = activeSkill.activeEffect.gemData + totemBase.totemified = true + totemBase.skillLevel = activeSkill.activeEffect.level + elseif activeSkill.supportList then -- skill is "totemified" via support + for _, support in ipairs(activeSkill.supportList) do + if support.grantedEffect.addSkillTypes and (not support.superseded) and support.isSupporting[activeSkill.activeEffect.srcInstance] then + for _, skillType in ipairs(support.grantedEffect.addSkillTypes) do + if skillType == SkillType.UsedByTotem then + totemBase.grantedEffect = support.gemData.grantedEffect + totemBase.gemData = support.gemData + break + end + end + end + if totemBase.gemData or totemBase.grantedEffect then + totemBase.totemified = true + totemBase.skillLevel = support.level + break + end + end + else + -- A totem skill that neither `SummonsTotem` nor `UsedByTotem` should not be possible, but I am leaving this here to alert us in case of unexpected future edge cases + error("Error: Unexpected SkillType behavior for skill with 'totem' flag") + end + end + + return totemBase +end + --- Applies additional modifiers to skills with the "Empowered" flag. --- Checks for "ExtraEmpoweredMod" mods and applies them --- if they match the conditions set by the empowering effect. @@ -465,10 +506,19 @@ function calcs.buildActiveSkillModList(env, activeSkill) skillKeywordFlags = bor(skillKeywordFlags, KeywordFlag.Spell) end - -- Get skill totem ID for totem skills - -- This is used to calculate totem life + -- Find totem base stats if skillFlags.totem then - activeSkill.skillTotemId = activeGrantedEffect.skillTotemId + local totemBase = getTotemBaseStats(activeSkill) + if totemBase.grantedEffect and totemBase.gemData then + activeSkill.skillData.totemBase = totemBase + end + local totemLevelRequirement = activeSkill.skillData.totemBase and activeSkill.skillData.totemBase.grantedEffect.levels[totemBase.skillLevel].levelRequirement or activeEffect.grantedEffect.levels[activeEffect.level].levelRequirement + -- Note: Some active skills related to totem base skills (e.g. on Shockwave Totem) have level requirement = 0, making the additional ` > 0` check necessary + activeSkill.skillData.totemLevel = (totemLevelRequirement and (totemLevelRequirement > 0)) and totemLevelRequirement or 1 + + -- Get skill totem ID for totem skills + -- This is used to calculate totem life + activeSkill.skillTotemId = activeGrantedEffect.skillTotemId or (activeSkill.skillData.totemBase and activeSkill.skillData.totemBase.grantedEffect.skillTotemId) if not activeSkill.skillTotemId then if activeGrantedEffect.color == 2 then activeSkill.skillTotemId = 2 @@ -630,11 +680,6 @@ function calcs.buildActiveSkillModList(env, activeSkill) applyExtraEmpowerMods(activeSkill) - -- Find totem level - if skillFlags.totem then - activeSkill.skillData.totemLevel = 1 or activeEffect.grantedEffect.levels[activeEffect.level].levelRequirement - end - -- Add active mine multiplier if skillFlags.mine then activeSkill.activeMineCount = (env.mode == "CALCS" and activeEffect.srcInstance.skillMineCountCalcs) or (env.mode ~= "CALCS" and activeEffect.srcInstance.skillMineCount) From 17fa1ccd660165b97a21921fcb7b91250ac748ea Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 25 Aug 2025 18:07:16 +0200 Subject: [PATCH 6/8] Reword "totemification" to "totemified" --- src/Modules/CalcActiveSkill.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index b3cf05b900..4dd1fcb19d 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -231,7 +231,7 @@ local function getWeaponFlags(env, weaponData, weaponTypes) return flags, info end --- Get stats from totem base skill in case of separate active skills or "totemification" via supports +-- Get stats from totem base skill in case of separate active skills or skills "totemified" via supports ---@param activeSkill table @activeSkill with totem tag local function getTotemBaseStats(activeSkill) local totemBase = {} From f5a3829d21bfc7c8da44f23d3cbe43050ba11a0f Mon Sep 17 00:00:00 2001 From: majochem Date: Mon, 25 Aug 2025 20:04:25 +0200 Subject: [PATCH 7/8] Get rid of "totemified" --- src/Modules/CalcActiveSkill.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Modules/CalcActiveSkill.lua b/src/Modules/CalcActiveSkill.lua index 4dd1fcb19d..8a30e2e7c0 100644 --- a/src/Modules/CalcActiveSkill.lua +++ b/src/Modules/CalcActiveSkill.lua @@ -231,7 +231,7 @@ local function getWeaponFlags(env, weaponData, weaponTypes) return flags, info end --- Get stats from totem base skill in case of separate active skills or skills "totemified" via supports +-- Get stats from totem base skill in case of separate active skills or skills that receive totem status via supports ---@param activeSkill table @activeSkill with totem tag local function getTotemBaseStats(activeSkill) local totemBase = {} @@ -244,9 +244,8 @@ local function getTotemBaseStats(activeSkill) if activeSkill.activeEffect.grantedEffect.skillTypes[SkillType.UsedByTotem] then -- is totem skill by default totemBase.grantedEffect = activeSkill.activeEffect.gemData.grantedEffect totemBase.gemData = activeSkill.activeEffect.gemData - totemBase.totemified = true totemBase.skillLevel = activeSkill.activeEffect.level - elseif activeSkill.supportList then -- skill is "totemified" via support + elseif activeSkill.supportList then -- skill is receives totem status via support for _, support in ipairs(activeSkill.supportList) do if support.grantedEffect.addSkillTypes and (not support.superseded) and support.isSupporting[activeSkill.activeEffect.srcInstance] then for _, skillType in ipairs(support.grantedEffect.addSkillTypes) do @@ -258,7 +257,6 @@ local function getTotemBaseStats(activeSkill) end end if totemBase.gemData or totemBase.grantedEffect then - totemBase.totemified = true totemBase.skillLevel = support.level break end From 931e49011bb72956b24393e1db8e672670b8c956 Mon Sep 17 00:00:00 2001 From: LocalIdentity Date: Tue, 2 Sep 2025 23:50:02 +1000 Subject: [PATCH 8/8] Add support for Mortar Cannon Adds support for a few stats on mortar cannon and ancestral totem too --- src/Data/SkillStatMap.lua | 7 ++++++- src/Data/Skills/act_str.lua | 37 ++++++++++++++++++++++++++++------- src/Export/Skills/act_str.txt | 35 +++++++++++++++++++++++++-------- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/Data/SkillStatMap.lua b/src/Data/SkillStatMap.lua index ecba94d9c8..d860a5492d 100644 --- a/src/Data/SkillStatMap.lua +++ b/src/Data/SkillStatMap.lua @@ -549,6 +549,9 @@ return { ["totem_skill_attack_speed_+%"] = { mod("Speed", "INC", nil, ModFlag.Attack, KeywordFlag.Totem) }, +["grenade_skill_cooldown_speed_+%"] = { + mod("CooldownRecovery", "INC", nil), +}, -- AoE ["active_skill_base_area_of_effect_radius"] = { skill("radius", nil), @@ -2655,5 +2658,7 @@ return { ["quality_display_sandstorm_swipe_is_gem"] = { -- Display Only }, - +["quality_display_base_totem_duration_is_gem"] = { + -- Display Only +}, } diff --git a/src/Data/Skills/act_str.lua b/src/Data/Skills/act_str.lua index 836340644a..9d13455b89 100644 --- a/src/Data/Skills/act_str.lua +++ b/src/Data/Skills/act_str.lua @@ -509,9 +509,6 @@ skills["SupportAncestralWarriorTotemPlayer"] = { name = "SupportAncestralWarriorTotemPlayer", hidden = true, support = true, - addFlags = { - totem = true, - }, requireSkillTypes = { SkillType.Attack, }, addSkillTypes = { SkillType.UsedByTotem, }, excludeSkillTypes = { SkillType.Meta, SkillType.Triggered, SkillType.Cooldown, SkillType.Channel, SkillType.Persistent, }, @@ -566,13 +563,24 @@ skills["SupportAncestralWarriorTotemPlayer"] = { [39] = { levelRequirement = 0, }, [40] = { levelRequirement = 0, }, }, + addFlags = { + totem = true, + }, statSets = { [1] = { label = "SupportAncestralWarriorTotemPlayer", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", + statMap = { + ["support_ancestral_warrior_totem_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack), + }, + }, baseFlags = { }, + baseMods = { + mod("ActiveTotemLimit", "BASE", 1), + }, constantStats = { { "skill_disabled_unless_cloned", 2 }, { "support_ancestral_warrior_totem_attack_speed_+%_final", -25 }, @@ -1071,7 +1079,7 @@ skills["AttritionPlayer"] = { {mod("Damage", "MORE", nil, 0, KeywordFlag.Hit, { type = "GlobalEffect", effectType = "Buff"}, { type = "Multiplier", var = "EnemyPresenceSeconds", actor = "enemy", limitVar = "AttritionMaxDamage", div = 2, limitTotal = true }, { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" })}, {mod("CullPercent", "MAX", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff"}, { type = "MultiplierThreshold", var = "EnemyPresenceSeconds", actor = "enemy", thresholdVar = "AttritionCullSeconds"}, { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" }), value = 10,} - }, + }, }, baseFlags = { }, @@ -3691,6 +3699,10 @@ skills["ExplosiveGrenadePlayer"] = { label = "Explosive Grenade", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "explosive_grenade", + statMap = { + ["base_skill_show_average_damage_instead_of_dps"] = { + }, + }, baseFlags = { attack = true, area = true, @@ -11225,16 +11237,27 @@ skills["SupportMortarCannonPlayer"] = { [39] = { levelRequirement = 0, }, [40] = { levelRequirement = 0, }, }, + addFlags = { + totem = true, + }, statSets = { [1] = { label = "SupportMortarCannonPlayer", incrementalEffectiveness = 0.054999999701977, statDescriptionScope = "gem_stat_descriptions", - addFlags = { - totem = true, + statMap = { + ["support_grenade_ballista_damage_+%_final"] = { + mod("Damage", "MORE", nil), }, + ["support_grenade_ballista_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack), + }, + }, baseFlags = { }, + baseMods = { + mod("ActiveTotemLimit", "BASE", 1), + }, constantStats = { { "skill_disabled_unless_cloned", 2 }, { "support_grenade_ballista_attack_speed_+%_final", -50 }, @@ -13318,7 +13341,7 @@ skills["SiegeBallistaPlayer"] = { } } skills["SiegeBallistaProjectilePlayer"] = { - name = "", + name = "Artillery", hidden = true, skillTypes = { [SkillType.Attack] = true, [SkillType.RangedAttack] = true, [SkillType.Projectile] = true, [SkillType.Barrageable] = true, [SkillType.AttackInPlaceIsDefault] = true, [SkillType.Fire] = true, [SkillType.Area] = true, [SkillType.CannotChain] = true, [SkillType.UsedByTotem] = true, }, weaponTypes = { diff --git a/src/Export/Skills/act_str.txt b/src/Export/Skills/act_str.txt index 2db18ec683..4516c8e2ee 100644 --- a/src/Export/Skills/act_str.txt +++ b/src/Export/Skills/act_str.txt @@ -30,11 +30,17 @@ local skills, mod, flag, skill = ... #skillEnd #skill SupportAncestralWarriorTotemPlayer - addFlags = { - totem = true, - }, +addFlags = { + totem = true, +}, #set SupportAncestralWarriorTotemPlayer #flags +statMap = { + ["support_ancestral_warrior_totem_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack), + }, +}, +#baseMod mod("ActiveTotemLimit", "BASE", 1) #mods #skillEnd @@ -70,7 +76,7 @@ statMap = { {mod("Damage", "MORE", nil, 0, KeywordFlag.Hit, { type = "GlobalEffect", effectType = "Buff"}, { type = "Multiplier", var = "EnemyPresenceSeconds", actor = "enemy", limitVar = "AttritionMaxDamage", div = 2, limitTotal = true }, { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" })}, {mod("CullPercent", "MAX", nil, 0, 0, { type = "GlobalEffect", effectType = "Buff"}, { type = "MultiplierThreshold", var = "EnemyPresenceSeconds", actor = "enemy", thresholdVar = "AttritionCullSeconds"}, { type = "ActorCondition", actor = "enemy", var = "RareOrUnique" }), value = 10,} - }, + }, }, #mods #skillEnd @@ -275,6 +281,10 @@ statMap = { #skill ExplosiveGrenadePlayer #set ExplosiveGrenadePlayer #flags attack area projectile +statMap = { + ["base_skill_show_average_damage_instead_of_dps"] = { + }, +}, #mods #skillEnd @@ -634,11 +644,20 @@ statMap = { #skillEnd #skill SupportMortarCannonPlayer +addFlags = { + totem = true, +}, #set SupportMortarCannonPlayer - addFlags = { - totem = true, - }, #flags +statMap = { + ["support_grenade_ballista_damage_+%_final"] = { + mod("Damage", "MORE", nil), + }, + ["support_grenade_ballista_attack_speed_+%_final"] = { + mod("Speed", "MORE", nil, ModFlag.Attack), + }, +}, +#baseMod mod("ActiveTotemLimit", "BASE", 1) #mods #skillEnd @@ -746,7 +765,7 @@ statMap = { #mods #skillEnd -#skill SiegeBallistaProjectilePlayer +#skill SiegeBallistaProjectilePlayer Artillery #set SiegeBallistaProjectilePlayer #flags attack projectile totem #mods