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
26 changes: 26 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,30 @@ describe("TestSkills", function()
runCallback("OnFrame")
assert.True(build.calcsTab.mainOutput.TotalDPS > iceShotDPS)
end)

it("Test Pinnacle of Power", function()
build.configTab.input.enemyIsBoss = "None"
build.configTab.input.usePowerCharges = true
build.configTab.input.overridePowerCharges = 3
build.configTab:BuildModList()
runCallback("OnFrame")

build.skillsTab:PasteSocketGroup("Fireball 20/0 1")
runCallback("OnFrame")
assert.True(build.calcsTab.calcsOutput.FreezeBuildupAvg == 0)
assert.True(build.calcsTab.calcsOutput.ShockEffectMod == nil)

build.skillsTab:PasteSocketGroup("Pinnacle of Power 20/0 1")
runCallback("OnFrame")
local basePinnacleDamage = build.calcsTab.calcsOutput.TotalDPS
assert.True(build.calcsTab.calcsOutput.FreezeBuildupAvg > 0)
assert.True(build.calcsTab.calcsOutput.ShockEffectMod ~= nil)
assert.are.equals(build.calcsTab.calcsOutput.BuffList, "Pinnacle of Power")


build.skillsTab:PasteSocketGroup("Pinnacle of Power 20/0 1\nHeightened Charges 1/0 1")
runCallback("OnFrame")
-- Heightened Charges should increased the buff effect, therefore Fireball should have more damage than base Pinnacle of Power
assert.True(build.calcsTab.calcsOutput.TotalDPS > basePinnacleDamage)
end)
end)
14 changes: 0 additions & 14 deletions src/Classes/ModStore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -350,13 +350,6 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
tag.div = GetMultiplier(self, tag.divVar, cfg)
end
local mult = m_floor(base / (tag.div or 1) + 0.0001)
-- scale effects of Multiplier mod
if tag.scalar then
local scalar = 1 + GetMultiplier(target, tag.scalar, cfg) / 100
if scalar > 1 then
mult = mult * scalar
end
end
local limitTotal
local limitNegTotal
if tag.limit or tag.limitVar then
Expand Down Expand Up @@ -431,13 +424,6 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
if (tag.upper and mult > threshold) or (tag.equals and mult ~= threshold) or (not (tag.upper and tag.exact) and mult < threshold) then
return
end
-- scale effects of Multiplier mod
if tag.scalar then
local scalar = 1 + GetMultiplier(target, tag.scalar, cfg) / 100
if scalar > 1 then
value = value * scalar
end
end
elseif tag.type == "PerStat" then
local base
local target = self
Expand Down
15 changes: 15 additions & 0 deletions src/Data/Skills/other.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6048,6 +6048,21 @@ skills["PinnacleOfPowerPlayer"] = {
label = "Pinnacle of Power",
incrementalEffectiveness = 0.054999999701977,
statDescriptionScope = "pinnacle_of_power",
statMap = {
["elemental_power_elemental_damage_+%_final_per_power_charge"] = {
mod("Damage", "MORE", nil, 0, 0, { type = "SkillType", skillTypeList = { SkillType.Cold, SkillType.Fire, SkillType.Lightning } }, { type = "Multiplier", var = "RemovablePowerCharge", scalar = "ConsumedPowerChargeEffect" }, { type = "GlobalEffect", effectType = "Buff" }),
flag("ColdCanIgnite", { type = "GlobalEffect", effectType = "Buff" }), flag("ColdCanShock", { type = "GlobalEffect", effectType = "Buff" }),
flag("FireCanFreeze", { type = "GlobalEffect", effectType = "Buff" }), flag("FireCanShock", { type = "GlobalEffect", effectType = "Buff" }),
flag("LightningCanFreeze", { type = "GlobalEffect", effectType = "Buff" }), flag("LightningCanIgnite", { type = "GlobalEffect", effectType = "Buff" }),
},
["elemental_power_buff_duration_per_power_charge_ms"] = {
mod("Duration", "BASE", nil, 0, 0, { type = "Multiplier", var = "RemovablePowerCharge", scalar = "ConsumedPowerChargeEffect" }),
div = 1000,
},
["quality_stat_elemental_power_elemental_damage_+%_final_per_power_charge_is_gem"] = {
-- display only
},
},
baseFlags = {
buff = true,
duration = true,
Expand Down
15 changes: 15 additions & 0 deletions src/Export/Skills/other.txt
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,21 @@ statMap = {
#skill PinnacleOfPowerPlayer
#set PinnacleOfPowerPlayer
#flags buff duration
statMap = {
["elemental_power_elemental_damage_+%_final_per_power_charge"] = {
mod("Damage", "MORE", nil, 0, 0, { type = "SkillType", skillTypeList = { SkillType.Cold, SkillType.Fire, SkillType.Lightning } }, { type = "Multiplier", var = "RemovablePowerCharge", scalar = "ConsumedPowerChargeEffect" }, { type = "GlobalEffect", effectType = "Buff" }),
flag("ColdCanIgnite", { type = "GlobalEffect", effectType = "Buff" }), flag("ColdCanShock", { type = "GlobalEffect", effectType = "Buff" }),
flag("FireCanFreeze", { type = "GlobalEffect", effectType = "Buff" }), flag("FireCanShock", { type = "GlobalEffect", effectType = "Buff" }),
flag("LightningCanFreeze", { type = "GlobalEffect", effectType = "Buff" }), flag("LightningCanIgnite", { type = "GlobalEffect", effectType = "Buff" }),
},
["elemental_power_buff_duration_per_power_charge_ms"] = {
mod("Duration", "BASE", nil, 0, 0, { type = "Multiplier", var = "RemovablePowerCharge", scalar = "ConsumedPowerChargeEffect" }),
div = 1000,
},
["quality_stat_elemental_power_elemental_damage_+%_final_per_power_charge_is_gem"] = {
-- display only
},
},
#mods
#skillEnd

Expand Down
55 changes: 37 additions & 18 deletions src/Modules/CalcActiveSkill.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ local function mergeLevelMod(modList, mod, value)
end
end

-- allow Multiplier mods to be scaled by sources of the multipliedVariableEffect, e.g. var = RemovablePowerCharges, scalar = ConsumedPowerChargeEffect
-- e.g. Pinnacle of Power, I had this scaling logic in ModStore prior as tag.scalar but it was not working with the Buff portion
local function checkForScalarMultiplier(modOrGroup, modList)
local scale = 0
if modOrGroup.scalar then
scale = modList:Sum("BASE", nil, "Multiplier:"..modOrGroup.scalar)
else
for _, config in ipairs(modOrGroup) do
if config.scalar then
scale = modList:Sum("BASE", nil, "Multiplier:"..config.scalar)
break
end
end
end
return 1 + scale / 100
end

-- Merge skill effect modifiers with given mod list
-- If a stat set is provided, only merge modifiers from that statset
function calcs.mergeSkillInstanceMods(env, modList, skillEffect, statSet, extraStats)
Expand All @@ -56,8 +73,8 @@ function calcs.mergeSkillInstanceMods(env, modList, skillEffect, statSet, extraS
if statSet and not isValueInArray(skillEffect.grantedEffect.statSets, statSet) then
return
end
local grantedEffect = skillEffect.grantedEffect
for _, statSet in ipairs(statSet and {statSet} or grantedEffect.statSets) do
local grantedEffect = skillEffect.grantedEffect
for _, statSet in ipairs(statSet and {statSet} or grantedEffect.statSets) do
local stats = calcLib.buildSkillInstanceStats(skillEffect, grantedEffect, statSet)
if extraStats and extraStats[1] then
for _, stat in pairs(extraStats) do
Expand All @@ -69,14 +86,16 @@ function calcs.mergeSkillInstanceMods(env, modList, skillEffect, statSet, extraS
if map then
-- Some mods need different scalars for different stats, but the same value. Putting them in a group allows this
for _, modOrGroup in ipairs(map) do
local scalar = checkForScalarMultiplier(modOrGroup, modList)
-- Found a mod, since all mods have names
if modOrGroup.name then
modOrGroup.source = string.format("Skill:%s", grantedEffect.id)
mergeLevelMod(modList, modOrGroup, map.value or statValue * (map.mult or 1) / (map.div or 1) + (map.base or 0))
mergeLevelMod(modList, modOrGroup, map.value or statValue * (map.mult or 1) * scalar / (map.div or 1) + (map.base or 0))
else
for _, mod in ipairs(modOrGroup) do
local scalar = checkForScalarMultiplier(mod)
mod.source = string.format("Skill:%s", grantedEffect.id)
mergeLevelMod(modList, mod, modOrGroup.value or statValue * (modOrGroup.mult or 1) / (modOrGroup.div or 1) + (modOrGroup.base or 0))
mergeLevelMod(modList, mod, modOrGroup.value or statValue * (modOrGroup.mult or 1) * scalar / (modOrGroup.div or 1) + (modOrGroup.base or 0))
end
end
end
Expand All @@ -100,7 +119,7 @@ function calcs.createActiveSkill(activeEffect, supportList, env, actor, socketGr
}

local activeGrantedEffect = activeEffect.grantedEffect

-- Initialise skill types
activeSkill.skillTypes = copyTable(activeGrantedEffect.skillTypes)
if activeGrantedEffect.minionSkillTypes then
Expand All @@ -109,12 +128,12 @@ function calcs.createActiveSkill(activeEffect, supportList, env, actor, socketGr

-- Initialise skill flag set ('attack', 'projectile', etc)
local statSet, skillFlags
if env.mode == "CALCS" then
if env.mode == "CALCS" then
statSet = activeEffect.grantedEffect.statSets[activeEffect.statSetCalcs.index]
skillFlags = statSet and copyTable(statSet.baseFlags) or { }
activeEffect.statSetCalcs.statSet = statSet
activeEffect.statSetCalcs.skillFlags = skillFlags
else
else
statSet = activeEffect.grantedEffect.statSets[activeEffect.statSet.index]
skillFlags = statSet and copyTable(statSet.baseFlags) or { }
activeEffect.statSet.statSet = statSet
Expand Down Expand Up @@ -261,7 +280,7 @@ local function getTotemBaseStats(activeSkill)
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.grantedEffect = activeSkill.activeEffect.gemData.grantedEffect
totemBase.gemData = activeSkill.activeEffect.gemData
totemBase.skillLevel = activeSkill.activeEffect.level
elseif activeSkill.supportList then -- skill is receives totem status via support
Expand Down Expand Up @@ -703,7 +722,7 @@ function calcs.buildActiveSkillModList(env, activeSkill)
skillModList:AddMod(value.mod)
t_insert(activeSkill.extraSkillModList, value.mod)
end

applyExtraEmpowerMods(activeSkill)

-- Add active mine multiplier
Expand All @@ -722,7 +741,7 @@ function calcs.buildActiveSkillModList(env, activeSkill)
local noPotentialStage = true
if activeEffect.grantedEffect.parts then
for _, part in ipairs(activeEffect.grantedEffect.parts) do
if part.stages then
if part.stages then
noPotentialStage = false
break
end
Expand Down Expand Up @@ -808,12 +827,12 @@ function calcs.buildActiveSkillModList(env, activeSkill)
minion.parent = env.player
minion.enemy = env.enemy
end
minion.level = activeSkill.skillData.minionLevelIsEnemyLevel and env.enemyLevel or
activeSkill.skillData.minionLevelIsTriggeredSkillLevel and activeEffect.srcInstance.supportEffect and activeEffect.srcInstance.supportEffect.activeSkillLevel and data.minionLevelTable[activeEffect.srcInstance.supportEffect.activeSkillLevel] or
activeSkill.skillData.minionLevelIsPlayerLevel and (m_min(env.build and env.build.characterLevel or activeSkill.skillData.minionLevel or activeEffect.grantedEffectLevel.levelRequirement, activeSkill.skillData.minionLevelIsPlayerLevel)) or
minion.level = activeSkill.skillData.minionLevelIsEnemyLevel and env.enemyLevel or
activeSkill.skillData.minionLevelIsTriggeredSkillLevel and activeEffect.srcInstance.supportEffect and activeEffect.srcInstance.supportEffect.activeSkillLevel and data.minionLevelTable[activeEffect.srcInstance.supportEffect.activeSkillLevel] or
activeSkill.skillData.minionLevelIsPlayerLevel and (m_min(env.build and env.build.characterLevel or activeSkill.skillData.minionLevel or activeEffect.grantedEffectLevel.levelRequirement, activeSkill.skillData.minionLevelIsPlayerLevel)) or
activeSkill.skillData.minionLevel or data.minionLevelTable[activeSkill.activeEffect.level] or 1
-- fix minion level between 1 and 100
minion.level = m_min(m_max(minion.level,1),100)
minion.level = m_min(m_max(minion.level,1),100)
minion.itemList = { }
minion.uses = activeGrantedEffect.minionUses
minion.lifeTable = env.data.monsterAllyLifeTable
Expand Down Expand Up @@ -870,7 +889,7 @@ function calcs.buildActiveSkillModList(env, activeSkill)
minion.weaponData1 = env.player.weaponData1
end
end
if minion.uses["Weapon 2"] then
if minion.uses["Weapon 2"] then
if minion.itemSet then
local item = env.build.itemsTab.items[minion.itemSet[minion.itemSet.useSecondWeaponSet and "Weapon 2 Swap" or "Weapon 2"].selItemId]
if item and item.weaponData then
Expand Down Expand Up @@ -994,7 +1013,7 @@ function calcs.createMinionSkills(env, activeSkill)
}
local minionSkillIndex = activeSkill.activeEffect.srcInstance.skillMinionSkill
local minionSkillIndexCalcs = activeSkill.activeEffect.srcInstance.skillMinionSkillCalcs
local minionStatSetIndex = activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookup and activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookup[activeSkill.activeEffect.grantedEffect.id]
local minionStatSetIndex = activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookup and activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookup[activeSkill.activeEffect.grantedEffect.id]
and activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookup[activeSkill.activeEffect.grantedEffect.id][minionSkillIndex] or 1
local minionStatSetCalcsIndex = activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookupCalcs and activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookupCalcs[activeSkill.activeEffect.grantedEffect.id]
and activeSkill.activeEffect.srcInstance.skillMinionSkillStatSetIndexLookupCalcs[activeSkill.activeEffect.grantedEffect.id][minionSkillIndexCalcs] or 1
Expand All @@ -1018,7 +1037,7 @@ function calcs.createMinionSkills(env, activeSkill)
local skillFlags
if env.mode == "CALCS" then
skillFlags = minionSkill.activeEffect.statSetCalcs.skillFlags
else
else
skillFlags = minionSkill.activeEffect.statSet.skillFlags
end
skillFlags.minion = true
Expand All @@ -1027,7 +1046,7 @@ function calcs.createMinionSkills(env, activeSkill)
minionSkill.skillData.damageEffectiveness = 1 + (activeSkill.skillData.minionDamageEffectiveness or 0) / 100
t_insert(minion.activeSkillList, minionSkill)
end
local skillIndex
local skillIndex
if env.mode == "CALCS" then
skillIndex = m_max(m_min(activeEffect.srcInstance.skillMinionSkillCalcs or 1, #minion.activeSkillList), 1)
activeEffect.srcInstance.skillMinionSkillCalcs = skillIndex
Expand Down
Loading