Skip to content
Merged
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
21 changes: 21 additions & 0 deletions spec/System/TestSkills_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,25 @@ describe("TestAttacks", function()
local finalCost = build.calcsTab.mainOutput.ManaCost
assert.are.equals(7, round(finalCost))
end)

it("evaluates BaseFlag tags using PoB 1 skill data", function()
build.skillsTab:PasteSocketGroup("Absolution 20/0 1\n")
runCallback("OnFrame")

local durationSkill = build.calcsTab.mainEnv.player.mainSkill
durationSkill.skillModList:NewMod("BaseFlagTest", "BASE", 1, "Test", { type = "BaseFlag", baseFlag = "duration" })
durationSkill.skillModList:NewMod("NegatedBaseFlagTest", "BASE", 1, "Test", { type = "BaseFlag", baseFlag = "duration", neg = true })
assert.are.equals(1, durationSkill.skillModList:Sum("BASE", durationSkill.skillCfg, "BaseFlagTest"))
assert.are.equals(0, durationSkill.skillModList:Sum("BASE", durationSkill.skillCfg, "NegatedBaseFlagTest"))

newBuild()
build.skillsTab:PasteSocketGroup("Fireball 20/0 1\n")
runCallback("OnFrame")

local nonDurationSkill = build.calcsTab.mainEnv.player.mainSkill
nonDurationSkill.skillModList:NewMod("BaseFlagTest", "BASE", 1, "Test", { type = "BaseFlag", baseFlag = "duration" })
nonDurationSkill.skillModList:NewMod("NegatedBaseFlagTest", "BASE", 1, "Test", { type = "BaseFlag", baseFlag = "duration", neg = true })
assert.are.equals(0, nonDurationSkill.skillModList:Sum("BASE", nonDurationSkill.skillCfg, "BaseFlagTest"))
assert.are.equals(1, nonDurationSkill.skillModList:Sum("BASE", nonDurationSkill.skillCfg, "NegatedBaseFlagTest"))
end)
end)
2 changes: 2 additions & 0 deletions src/Classes/CalcBreakdownControl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ function CalcBreakdownClass:AddModSection(sectionData, modList)
if not desc then
desc = "Skill type: "..(tag.neg and "Not " or "").."?"
end
elseif tag.type == "BaseFlag" then
desc = "Base flag: "..(tag.neg and "Not " or "")..self:FormatModName(tostring(tag.baseFlag))
elseif tag.type == "SlotNumber" then
desc = "When in slot #"..tag.num
elseif tag.type == "GlobalEffect" then
Expand Down
66 changes: 45 additions & 21 deletions src/Classes/ModStore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ local ModStoreClass = newClass("ModStore", function(self, parent)
self.conditions = { }
end)

local function getActor(self, actorType)
if actorType == "player" then
return self.actor.player or (self.actor.parent and self.actor.parent.player) or (self.actor.enemy and self.actor.enemy.player)
else
return self.actor[actorType]
end
end

function ModStoreClass:ScaleAddMod(mod, scale, replace)
local unscalable = false
for _, effects in ipairs(mod) do
Expand Down Expand Up @@ -323,15 +331,17 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
-- This explicit target is necessary because even though the GetMultiplier method does call self.parent.GetMultiplier, it does so with noMod = true,
-- disabling the summation (3rd part): (not noMod and self:Sum("BASE", cfg, multiplierName[var]) or 0)
if tag.limitActor then
if self.actor[tag.limitActor] then
limitTarget = self.actor[tag.limitActor].modDB
local limitActor = getActor(self, tag.limitActor)
if limitActor then
limitTarget = limitActor.modDB
else
return
end
end
if tag.actor then
if self.actor[tag.actor] then
target = self.actor[tag.actor].modDB
local actor = getActor(self, tag.actor)
if actor then
target = actor.modDB
else
return
end
Expand Down Expand Up @@ -398,15 +408,17 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
local target = self
local thresholdTarget = self
if tag.thresholdActor then
if self.actor[tag.thresholdActor] then
thresholdTarget = self.actor[tag.thresholdActor].modDB
local thresholdActor = getActor(self, tag.thresholdActor)
if thresholdActor then
thresholdTarget = thresholdActor.modDB
else
return
end
end
if tag.actor then
if self.actor[tag.actor] then
target = self.actor[tag.actor].modDB
local actor = getActor(self, tag.actor)
if actor then
target = actor.modDB
else
return
end
Expand All @@ -428,8 +440,9 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
local target = self
-- This functions similar to the above tagTypes in regard to which actor to use, but for PerStat
-- if the actor is 'parent', we don't want to return if we're already using 'parent', just keep using 'self'
if tag.actor and self.actor[tag.actor] then
target = self.actor[tag.actor].modDB
local actor = getActor(self, tag.actor)
if actor then
target = actor.modDB
end
if tag.statList then
base = 0
Expand All @@ -450,7 +463,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
limitTotal = limit
else
mult = m_min(mult, limit)
end
end
end
if type(value) == "table" then
value = copyTable(value)
Expand All @@ -476,8 +489,9 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
local target = self
-- This functions similar to the above tagTypes in regard to which actor to use, but for PercentStat
-- if the actor is 'parent', we don't want to return if we're already using 'parent', just keep using 'self'
if tag.actor and self.actor[tag.actor] then
target = self.actor[tag.actor].modDB
local actor = getActor(self, tag.actor)
if actor then
target = actor.modDB
end
if tag.statList then
base = 0
Expand All @@ -499,7 +513,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
limitTotal = limit
else
mult = m_min(mult, limit)
end
end
end
if type(value) == "table" then
value = copyTable(value)
Expand Down Expand Up @@ -555,17 +569,17 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
end
end
end
-- Syntax: { type = "MeleeProximity", ramp = {MaxBonusPct,MinBonusPct} }
-- Both MaxBonusPct and MinBonusPct are percent in decimal form (1.0 = 100%)
-- Example: { type = "MeleeProximity", ramp = {1,0} } ## Duelist-Slayer: Impact
-- Syntax: { type = "MeleeProximity", ramp = {MaxBonusPct,MinBonusPct} }
-- Both MaxBonusPct and MinBonusPct are percent in decimal form (1.0 = 100%)
-- Example: { type = "MeleeProximity", ramp = {1,0} } ## Duelist-Slayer: Impact
elseif tag.type == "MeleeProximity" then
if not cfg or not cfg.skillDist then
return
end
-- Max potency is 0-15 units of distance
if cfg.skillDist <= 15 then
value = value * tag.ramp[1]
-- Reduced potency (linear) until 40 units
-- Reduced potency (linear) until 40 units
elseif cfg.skillDist >= 16 and cfg.skillDist <= 39 then
value = value * (tag.ramp[1] - ((tag.ramp[1] / 25) * (cfg.skillDist - 15)))
elseif cfg.skillDist >= 40 then
Expand Down Expand Up @@ -608,7 +622,8 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
local match = false
local target = self
if tag.actor then
target = self.actor[tag.actor] and self.actor[tag.actor].modDB
local actor = getActor(self, tag.actor)
target = actor and actor.modDB
end
if target and (tag.var or tag.varList) then
if tag.varList then
Expand Down Expand Up @@ -713,7 +728,7 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
end
return false
end

local match = {}
if tag.slotName then
match["slotName"] = (tag.slotName == cfg.slotName) or false
Expand Down Expand Up @@ -820,6 +835,15 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
if not match then
return
end
elseif tag.type == "BaseFlag" then
local baseFlags = cfg and ((cfg.skillGrantedEffect and cfg.skillGrantedEffect.baseFlags) or cfg.baseFlags)
local match = baseFlags and baseFlags[tag.baseFlag] or false
if tag.neg then
match = not match
end
if not match then
return
end
elseif tag.type == "SlotName" then
if not cfg then
return
Expand Down Expand Up @@ -901,4 +925,4 @@ function ModStoreClass:EvalMod(mod, cfg, globalLimits)
end
end
return value
end
end
Loading