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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,41 @@ describe("TestSkills", function()
end
end

local function assertGemSupportLevel(gemName, expectedLevel, expectedCount)
local count = 0
for _, activeSkill in ipairs(build.calcsTab.calcsEnv.player.activeSkillList) do
if activeSkill.activeEffect.gemData and activeSkill.activeEffect.gemData.name == gemName then
count = count + 1
assert.are.equals(expectedLevel, activeSkill.skillModList:Sum("BASE", activeSkill.skillCfg, "GemSupportLevel"))
end
end
assert.are.equals(expectedCount, count)
end

it("evaluates GemTag mod tags against active skill gem tags", function()
local modDB = build.calcsTab.mainEnv.modDB

modDB:NewMod("Damage", "INC", 10, "Test Fire GemTag", { type = "GemTag", gemTag = "Fire" })
modDB:NewMod("Damage", "INC", 20, "Test Elemental GemTagList", { type = "GemTag", gemTagList = { "Cold", "Lightning" } })
modDB:NewMod("Damage", "INC", 40, "Test Not Minion GemTag", { type = "GemTag", gemTag = "Minion", neg = true })

assert.are.equals(50, modDB:Sum("INC", { skillGem = { tags = { fire = true } } }, "Damage"))
assert.are.equals(60, modDB:Sum("INC", { skillGem = { tags = { cold = true } } }, "Damage"))
assert.are.equals(0, modDB:Sum("INC", { skillGem = { tags = { minion = true } } }, "Damage"))
end)

it("applies Fire Mastery level to Apocalypse through the source gem tag", function()
build.skillsTab:PasteSocketGroup("Apocalypse 20/0 1\nFire Mastery 1/0 1")
runCallback("OnFrame")
assertGemSupportLevel("Apocalypse", 1, 4)
end)

it("evaluates conditional gem levels using the source gem support count", function()
build.skillsTab:PasteSocketGroup("Apocalypse 20/0 1\nFire Mastery 1/0 1\nUhtred's Omen 1/0 1")
runCallback("OnFrame")
assertGemSupportLevel("Apocalypse", 3, 4)
end)


it("uses granted effect minion list when active skill minion list is missing", function()
local srcInstance = { statSet = { }, skillPart = { }, nameSpec = "Spectre: Test" }
Expand Down
2 changes: 2 additions & 0 deletions src/Classes/CalcBreakdownControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,8 @@ function CalcBreakdownClass:AddModSection(sectionData, modList)
else
desc = "Skill type: "..(tag.neg and "Not " or "")..self:FormatModName(SkillTypeName[tag.skillType])
end
elseif tag.type == "GemTag" then
desc = "Gem tag: "..(tag.neg and "Not " or "")..self:FormatVarNameOrList(tag.gemTag, tag.gemTagList)
elseif tag.type == "BaseFlag" then
desc = "Base flag: "..(tag.neg and "Not " or "")..self:FormatModName(tostring(tag.baseFlag))
elseif tag.type == "SlotNumber" then
Expand Down
19 changes: 19 additions & 0 deletions src/Classes/ModStore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,25 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
if not match then
return
end
elseif tag.type == "GemTag" then
local match = false
local gemTags = cfg and cfg.skillGem and cfg.skillGem.tags
if tag.gemTagList then
for _, gemTag in pairs(tag.gemTagList) do
if gemTags and gemTags[gemTag:lower()] then
match = true
break
end
end
else
match = gemTags and gemTags[tag.gemTag:lower()]
end
if tag.neg then
match = not match
end
if not match then
return
end
elseif tag.type == "BaseFlag" then
local match = false
if cfg and cfg.skillGem and cfg.skillGem.grantedEffect and cfg.skillGem.grantedEffect.statSets and cfg.skillGem.grantedEffect.statSets[1] then
Expand Down
20 changes: 10 additions & 10 deletions src/Data/SkillStatMap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3017,23 +3017,23 @@ return {
--
--Fire
["supported_fire_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Fire }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Fire" }),
},
--Cold
["supported_cold_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Cold }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Cold" }),
},
--Lightning
["supported_lightning_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Lightning }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Lightning" }),
},
--Chaos
["supported_chaos_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Chaos }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Chaos" }),
},
--Physical
["supported_physical_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Physical }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Physical" }),
},
--Active
["supported_active_skill_gem_level_+"] = {
Expand All @@ -3044,23 +3044,23 @@ return {
},
--Aura
["supported_aura_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Aura }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Aura" }),
},
--Curse
["supported_curse_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, KeywordFlag.Curse),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Curse" }),
},
--Strike
["supported_strike_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.MeleeSingleTarget }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Strike" }),
},
--Elemental
["supported_elemental_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, OR64(KeywordFlag.Lightning, KeywordFlag.Cold, KeywordFlag.Fire)),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTagList = { "Lightning", "Cold", "Fire" } }),
},
--Minion
["supported_minion_skill_gem_level_+"] = {
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "SkillType", skillType = SkillType.Minion }),
mod("SupportedGemProperty", "LIST", { keyword = "grants_active_skill", key = "level", value = nil }, 0, 0, { type = "GemTag", gemTag = "Minion" }),
},
-- Remnant stats
["remnant_effect_+%"] = {
Expand Down
37 changes: 34 additions & 3 deletions src/Modules/CalcActiveSkill.lua
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,35 @@ function calcs.createActiveSkill(activeEffect, supportList, env, actor, socketGr
return activeSkill
end

local function getSourceGemPropertyInfo(env, activeSkill)
local activeEffect = activeSkill.activeEffect
local sourceGem = activeEffect.srcInstance
if not sourceGem or not activeEffect.gemData or activeEffect.gemData.tags.support then
return { }
end

env.sourceGemPropertyInfo = env.sourceGemPropertyInfo or { }
if not env.sourceGemPropertyInfo[sourceGem] then
local modList = new("ModList", activeSkill.actor.modDB)
local supportCount = 0
for _, supportEffect in ipairs(activeSkill.supportList) do
if supportEffect.isSupporting and supportEffect.isSupporting[sourceGem] then
calcs.mergeSkillInstanceMods(env, modList, supportEffect)
if not supportEffect.grantedEffect.hidden then
supportCount = supportCount + 1
end
end
end
modList:NewMod("Multiplier:SupportCount", "BASE", supportCount, "Support Count")
env.sourceGemPropertyInfo[sourceGem] = modList:Tabulate("LIST", {
skillName = activeEffect.gemData.name,
skillGem = activeEffect.gemData,
slotName = activeSkill.slotName,
}, "SupportedGemProperty")
end
return env.sourceGemPropertyInfo[sourceGem]
end

function calcs.getActiveSkillDisplayName(activeSkill)
local skillName = activeSkill.activeEffect.grantedEffect.name
local skillMinion = activeSkill.minion
Expand Down Expand Up @@ -741,11 +770,13 @@ function calcs.buildActiveSkillModList(env, activeSkill)
if activeSkill.activeEffect.srcInstance and activeSkill.activeEffect.srcInstance.corrupted and not (activeSkill.activeEffect.srcInstance.fromItem or activeSkill.activeEffect.srcInstance.fromTree or activeSkill.activeEffect.grantedEffect.fromItem or activeSkill.activeEffect.grantedEffect.fromTree) then
skillModList:NewMod("GemCorruptionLevel", "BASE", activeSkill.activeEffect.srcInstance.corruptLevel, "Corruption")
end
for _, supportProperty in ipairs(skillModList:Tabulate("LIST", activeSkill.skillCfg, "SupportedGemProperty")) do
for _, supportProperty in ipairs(getSourceGemPropertyInfo(env, activeSkill)) do
local value = supportProperty.value
if value.keyword == "grants_active_skill" and activeSkill.activeEffect.gemData and not activeSkill.activeEffect.gemData.tags.support then
if value.keyword == "grants_active_skill" then
activeEffect[value.key] = activeEffect[value.key] + value.value
skillModList:NewMod("GemSupport".. value.key:gsub("^%l", string.upper), "BASE", value.value, supportProperty.mod.source, #supportProperty.mod > 0 and supportProperty.mod[1] or nil)
local gemTag = supportProperty.mod[1]
gemTag = gemTag and gemTag.type == "GemTag" and gemTag or nil
skillModList:NewMod("GemSupport".. value.key:gsub("^%l", string.upper), "BASE", value.value, supportProperty.mod.source, gemTag)
end
end

Expand Down
2 changes: 2 additions & 0 deletions src/Modules/CalcSetup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ function wipeEnv(env, accelerate)
if not accelerate.skills then
-- Player Active Skills generation
wipeTable(env.player.activeSkillList)
env.sourceGemPropertyInfo = { }

-- Enhances Active Skills with skill ModFlags, KeywordFlags
-- and modifiers that affect skill scaling (e.g., global buffs/effects)
Expand Down Expand Up @@ -1678,6 +1679,7 @@ function calcs.initEnv(build, mode, override, specEnv)
level = value.level,
quality = 0,
enabled = true,
isSupporting = { },
})
end
end
Expand Down
Loading