- Added Corpse Life input for DD - Added support for Hungry Abyss - lcurl.dll should now be compiled against the correct CRT
723 lines
28 KiB
Lua
723 lines
28 KiB
Lua
-- Path of Building
|
|
--
|
|
-- Module: Calc Perform
|
|
-- Manages the offence/defence calculations.
|
|
--
|
|
local calcs = ...
|
|
|
|
local pairs = pairs
|
|
local ipairs = ipairs
|
|
local t_insert = table.insert
|
|
local m_min = math.min
|
|
local m_ceil = math.ceil
|
|
local m_floor = math.floor
|
|
local s_format = string.format
|
|
|
|
local tempTable1 = { }
|
|
|
|
-- Merge an instance of a buff, taking the highest value of each modifier
|
|
local function mergeBuff(src, destTable, destKey)
|
|
if not destTable[destKey] then
|
|
destTable[destKey] = { }
|
|
end
|
|
local dest = destTable[destKey]
|
|
for _, mod in ipairs(src) do
|
|
local param = modLib.formatModParams(mod)
|
|
for index, destMod in ipairs(dest) do
|
|
if param == modLib.formatModParams(destMod) then
|
|
if type(destMod.value) == "number" and mod.value > destMod.value then
|
|
dest[index] = mod
|
|
end
|
|
param = nil
|
|
break
|
|
end
|
|
end
|
|
if param then
|
|
t_insert(dest, mod)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Calculate attributes and life/mana pools, and set conditions
|
|
local function doActorAttribsPoolsConditions(env, actor)
|
|
local modDB = actor.modDB
|
|
local output = actor.output
|
|
local breakdown = actor.breakdown
|
|
local condList = modDB.conditions
|
|
|
|
-- Set conditions
|
|
if actor.weaponData1.type == "Staff" then
|
|
condList["UsingStaff"] = true
|
|
end
|
|
if actor.weaponData1.type == "Bow" then
|
|
condList["UsingBow"] = true
|
|
end
|
|
if actor.itemList["Weapon 2"] and actor.itemList["Weapon 2"].type == "Shield" then
|
|
condList["UsingShield"] = true
|
|
end
|
|
if actor.weaponData1.type and actor.weaponData2.type then
|
|
condList["DualWielding"] = true
|
|
if actor.weaponData1.type == "Claw" and actor.weaponData2.type == "Claw" then
|
|
condList["DualWieldingClaws"] = true
|
|
end
|
|
end
|
|
if actor.weaponData1.type == "None" then
|
|
condList["Unarmed"] = true
|
|
end
|
|
if (modDB.multipliers["NormalItem"] or 0) > 0 then
|
|
condList["UsingNormalItem"] = true
|
|
end
|
|
if (modDB.multipliers["MagicItem"] or 0) > 0 then
|
|
condList["UsingMagicItem"] = true
|
|
end
|
|
if (modDB.multipliers["RareItem"] or 0) > 0 then
|
|
condList["UsingRareItem"] = true
|
|
end
|
|
if (modDB.multipliers["UniqueItem"] or 0) > 0 then
|
|
condList["UsingUniqueItem"] = true
|
|
end
|
|
if (modDB.multipliers["CorruptedItem"] or 0) > 0 then
|
|
condList["UsingCorruptedItem"] = true
|
|
else
|
|
condList["NotUsingCorruptedItem"] = true
|
|
end
|
|
if env.mode_combat then
|
|
if not modDB:Sum("FLAG", nil, "NeverCrit") then
|
|
condList["CritInPast8Sec"] = true
|
|
end
|
|
if not actor.mainSkill.skillData.triggered then
|
|
if actor.mainSkill.skillFlags.attack then
|
|
condList["AttackedRecently"] = true
|
|
elseif actor.mainSkill.skillFlags.spell then
|
|
condList["CastSpellRecently"] = true
|
|
end
|
|
end
|
|
if actor.mainSkill.skillFlags.hit and not actor.mainSkill.skillFlags.trap and not actor.mainSkill.skillFlags.mine and not actor.mainSkill.skillFlags.totem then
|
|
condList["HitRecently"] = true
|
|
end
|
|
if actor.mainSkill.skillFlags.movement then
|
|
condList["UsedMovementSkillRecently"] = true
|
|
end
|
|
if actor.mainSkill.skillFlags.totem then
|
|
condList["HaveTotem"] = true
|
|
condList["SummonedTotemRecently"] = true
|
|
end
|
|
if actor.mainSkill.skillFlags.mine then
|
|
condList["DetonatedMinesRecently"] = true
|
|
end
|
|
end
|
|
|
|
-- Calculate attributes
|
|
for _, stat in pairs({"Str","Dex","Int"}) do
|
|
output[stat] = round(calcLib.val(modDB, stat))
|
|
if breakdown then
|
|
breakdown[stat] = breakdown.simple(nil, nil, output[stat], stat)
|
|
end
|
|
end
|
|
|
|
-- Add attribute bonuses
|
|
modDB:NewMod("Life", "BASE", m_floor(output.Str / 2), "Strength")
|
|
actor.strDmgBonus = round((output.Str + modDB:Sum("BASE", nil, "DexIntToMeleeBonus")) / 5)
|
|
modDB:NewMod("PhysicalDamage", "INC", actor.strDmgBonus, "Strength", ModFlag.Melee)
|
|
modDB:NewMod("Accuracy", "BASE", output.Dex * 2, "Dexterity")
|
|
if not modDB:Sum("FLAG", nil, "IronReflexes") then
|
|
modDB:NewMod("Evasion", "INC", round(output.Dex / 5), "Dexterity")
|
|
end
|
|
modDB:NewMod("Mana", "BASE", round(output.Int / 2), "Intelligence")
|
|
modDB:NewMod("EnergyShield", "INC", round(output.Int / 5), "Intelligence")
|
|
|
|
-- Life/mana pools
|
|
if modDB:Sum("FLAG", nil, "ChaosInoculation") then
|
|
output.Life = 1
|
|
condList["FullLife"] = true
|
|
else
|
|
local base = modDB:Sum("BASE", nil, "Life")
|
|
local inc = modDB:Sum("INC", nil, "Life")
|
|
local more = modDB:Sum("MORE", nil, "Life")
|
|
local conv = modDB:Sum("BASE", nil, "LifeConvertToEnergyShield")
|
|
output.Life = round(base * (1 + inc/100) * more * (1 - conv/100))
|
|
if breakdown then
|
|
if inc ~= 0 or more ~= 1 or conv ~= 0 then
|
|
breakdown.Life = { }
|
|
breakdown.Life[1] = s_format("%g ^8(base)", base)
|
|
if inc ~= 0 then
|
|
t_insert(breakdown.Life, s_format("x %.2f ^8(increased/reduced)", 1 + inc/100))
|
|
end
|
|
if more ~= 1 then
|
|
t_insert(breakdown.Life, s_format("x %.2f ^8(more/less)", more))
|
|
end
|
|
if conv ~= 0 then
|
|
t_insert(breakdown.Life, s_format("x %.2f ^8(converted to Energy Shield)", 1 - conv/100))
|
|
end
|
|
t_insert(breakdown.Life, s_format("= %g", output.Life))
|
|
end
|
|
end
|
|
end
|
|
output.Mana = round(calcLib.val(modDB, "Mana"))
|
|
if breakdown then
|
|
breakdown.Mana = breakdown.simple(nil, nil, output.Mana, "Mana")
|
|
end
|
|
|
|
-- Life/mana reservation
|
|
for _, pool in pairs({"Life", "Mana"}) do
|
|
local max = output[pool]
|
|
local reserved
|
|
if max > 0 then
|
|
reserved = (actor["reserved_"..pool.."Base"] or 0) + m_ceil(max * (actor["reserved_"..pool.."Percent"] or 0) / 100)
|
|
output[pool.."Reserved"] = reserved
|
|
output[pool.."ReservedPercent"] = reserved / max * 100
|
|
output[pool.."Unreserved"] = max - reserved
|
|
output[pool.."UnreservedPercent"] = (max - reserved) / max * 100
|
|
if (max - reserved) / max <= 0.35 then
|
|
condList["Low"..pool] = true
|
|
end
|
|
else
|
|
reserved = 0
|
|
end
|
|
if reserved == 0 then
|
|
condList["No"..pool.."Reserved"] = true
|
|
end
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "GrantReserved"..pool.."AsAura")) do
|
|
local auraMod = copyTable(value.mod)
|
|
auraMod.value = m_floor(auraMod.value * m_min(reserved, max))
|
|
modDB:NewMod("ExtraAura", "LIST", { mod = auraMod })
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Process charges, enemy modifiers, and other buffs
|
|
local function doActorMisc(env, actor)
|
|
local modDB = actor.modDB
|
|
local enemyDB = actor.enemy.modDB
|
|
local output = actor.output
|
|
local condList = modDB.conditions
|
|
|
|
-- Calculate current and maximum charges
|
|
output.PowerChargesMax = modDB:Sum("BASE", nil, "PowerChargesMax")
|
|
output.FrenzyChargesMax = modDB:Sum("BASE", nil, "FrenzyChargesMax")
|
|
output.EnduranceChargesMax = modDB:Sum("BASE", nil, "EnduranceChargesMax")
|
|
if modDB:Sum("FLAG", nil, "UsePowerCharges") then
|
|
output.PowerCharges = output.PowerChargesMax
|
|
else
|
|
output.PowerCharges = 0
|
|
end
|
|
if modDB:Sum("FLAG", nil, "UseFrenzyCharges") then
|
|
output.FrenzyCharges = output.FrenzyChargesMax
|
|
else
|
|
output.FrenzyCharges = 0
|
|
end
|
|
if modDB:Sum("FLAG", nil, "UseEnduranceCharges") then
|
|
output.EnduranceCharges = output.EnduranceChargesMax
|
|
else
|
|
output.EnduranceCharges = 0
|
|
end
|
|
modDB.multipliers["PowerCharge"] = output.PowerCharges
|
|
modDB.multipliers["FrenzyCharge"] = output.FrenzyCharges
|
|
modDB.multipliers["EnduranceCharge"] = output.EnduranceCharges
|
|
if output.PowerCharges == 0 then
|
|
condList["HaveNoPowerCharges"] = true
|
|
end
|
|
if output.PowerCharges == output.PowerChargesMax then
|
|
condList["AtMaxPowerCharges"] = true
|
|
end
|
|
if output.FrenzyCharges == 0 then
|
|
condList["HaveNoFrenzyCharges"] = true
|
|
end
|
|
if output.FrenzyCharges == output.FrenzyChargesMax then
|
|
condList["AtMaxFrenzyCharges"] = true
|
|
end
|
|
if output.EnduranceCharges == 0 then
|
|
condList["HaveNoEnduranceCharges"] = true
|
|
end
|
|
if output.EnduranceCharges == output.EnduranceChargesMax then
|
|
condList["AtMaxEnduranceCharges"] = true
|
|
end
|
|
|
|
-- Process enemy modifiers
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "EnemyModifier")) do
|
|
enemyDB:AddMod(value.mod)
|
|
end
|
|
|
|
-- Add misc buffs
|
|
if env.mode_combat then
|
|
if modDB:Sum("FLAG", nil, "Fortify") then
|
|
local effect = m_floor(20 * (1 + modDB:Sum("INC", nil, "FortifyEffectOnSelf", "BuffEffectOnSelf") / 100))
|
|
modDB:NewMod("DamageTakenWhenHit", "INC", -20, "Fortify")
|
|
end
|
|
if modDB:Sum("FLAG", nil, "Onslaught") then
|
|
local effect = m_floor(20 * (1 + modDB:Sum("INC", nil, "OnslaughtEffect", "BuffEffectOnSelf") / 100))
|
|
modDB:NewMod("Speed", "INC", effect, "Onslaught")
|
|
modDB:NewMod("MovementSpeed", "INC", effect, "Onslaught")
|
|
end
|
|
if modDB:Sum("FLAG", nil, "UnholyMight") then
|
|
local effect = m_floor(30 * (1 + modDB:Sum("INC", nil, "BuffEffectOnSelf") / 100))
|
|
modDB:NewMod("PhysicalDamageGainAsChaos", "BASE", effect, "Unholy Might")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Finalises the environment and performs the stat calculations:
|
|
-- 1. Merges keystone modifiers
|
|
-- 2. Initialises minion skills
|
|
-- 3. Initialises the main skill's minion, if present
|
|
-- 4. Merges flask effects
|
|
-- 5. Calculates reservations
|
|
-- 6. Sets conditions and calculates attributes and life/mana pools (doActorAttribsPoolsConditions)
|
|
-- 7. Processes buffs and debuffs
|
|
-- 8. Processes charges and misc buffs (doActorMisc)
|
|
-- 9. Calculates defence and offence stats (calcs.defence, calcs.offence)
|
|
function calcs.perform(env)
|
|
local modDB = env.modDB
|
|
local enemyDB = env.enemyDB
|
|
|
|
-- Merge keystone modifiers
|
|
do
|
|
local keystoneList = wipeTable(tempTable1)
|
|
for _, name in ipairs(modDB:Sum("LIST", nil, "Keystone")) do
|
|
keystoneList[name] = true
|
|
end
|
|
for name in pairs(keystoneList) do
|
|
modDB:AddList(env.build.tree.keystoneMap[name].modList)
|
|
end
|
|
end
|
|
|
|
-- Build minion skills
|
|
for _, activeSkill in ipairs(env.activeSkillList) do
|
|
if activeSkill.minion then
|
|
calcs.createMinionSkills(env, activeSkill)
|
|
end
|
|
end
|
|
|
|
env.player.output = { }
|
|
env.enemy.output = { }
|
|
local output = env.player.output
|
|
|
|
env.minion = env.player.mainSkill.minion
|
|
if env.minion then
|
|
-- Initialise minion modifier database
|
|
output.Minion = { }
|
|
env.minion.output = output.Minion
|
|
env.minion.enemy = env.enemy
|
|
env.minion.modDB = common.New("ModDB")
|
|
env.minion.modDB.actor = env.minion
|
|
env.minion.modDB.multipliers["Level"] = env.minion.level
|
|
calcs.initModDB(env, env.minion.modDB)
|
|
env.minion.modDB:NewMod("Life", "BASE", m_floor(data.monsterAllyLifeTable[env.minion.level] * env.minion.minionData.life), "Base")
|
|
if env.minion.minionData.energyShield then
|
|
env.minion.modDB:NewMod("EnergyShield", "BASE", m_floor(data.monsterAllyLifeTable[env.minion.level] * env.minion.minionData.life * env.minion.minionData.energyShield), "Base")
|
|
end
|
|
env.minion.modDB:NewMod("Evasion", "BASE", data.monsterEvasionTable[env.minion.level], "Base")
|
|
env.minion.modDB:NewMod("Accuracy", "BASE", data.monsterAccuracyTable[env.minion.level], "Base")
|
|
env.minion.modDB:NewMod("CritMultiplier", "BASE", 30, "Base")
|
|
env.minion.modDB:NewMod("FireResist", "BASE", env.minion.minionData.fireResist, "Base")
|
|
env.minion.modDB:NewMod("ColdResist", "BASE", env.minion.minionData.coldResist, "Base")
|
|
env.minion.modDB:NewMod("LightningResist", "BASE", env.minion.minionData.lightningResist, "Base")
|
|
env.minion.modDB:NewMod("ChaosResist", "BASE", env.minion.minionData.chaosResist, "Base")
|
|
env.minion.modDB:NewMod("CritChance", "INC", 200, "Base", { type = "Multiplier", var = "PowerCharge" })
|
|
env.minion.modDB:NewMod("Speed", "INC", 15, "Base", { type = "Multiplier", var = "FrenzyCharge" })
|
|
env.minion.modDB:NewMod("Damage", "MORE", 4, "Base", { type = "Multiplier", var = "FrenzyCharge" })
|
|
env.minion.modDB:NewMod("MovementSpeed", "INC", 5, "Base", { type = "Multiplier", var = "FrenzyCharge" })
|
|
env.minion.modDB:NewMod("PhysicalDamageReduction", "BASE", 15, "Base", { type = "Multiplier", var = "EnduranceCharge" })
|
|
env.minion.modDB:NewMod("ElementalResist", "BASE", 15, "Base", { type = "Multiplier", var = "EnduranceCharge" })
|
|
env.minion.modDB:NewMod("ProjectileCount", "BASE", 1, "Base")
|
|
for _, mod in ipairs(env.minion.minionData.modList) do
|
|
env.minion.modDB:AddMod(mod)
|
|
end
|
|
if env.aegisModList then
|
|
env.minion.itemList["Weapon 2"] = env.player.itemList["Weapon 2"]
|
|
env.player.itemList["Weapon 2"] = nil
|
|
env.minion.modDB:AddList(env.aegisModList)
|
|
end
|
|
if env.player.mainSkill.skillData.minionUseBowAndQuiver then
|
|
if env.player.weaponData1.type == "Bow" then
|
|
env.minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1])
|
|
end
|
|
if env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 2"].type == "Quiver" then
|
|
env.minion.modDB:AddList(env.player.itemList["Weapon 2"].modList)
|
|
end
|
|
end
|
|
if modDB:Sum("FLAG", nil, "StrengthAddedToMinions") then
|
|
env.minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Player")
|
|
end
|
|
end
|
|
|
|
local breakdown
|
|
if env.mode == "CALCS" then
|
|
-- Initialise breakdown module
|
|
breakdown = LoadModule("Modules/CalcBreakdown", modDB, output, env.player)
|
|
env.player.breakdown = breakdown
|
|
if env.minion then
|
|
env.minion.breakdown = LoadModule("Modules/CalcBreakdown", env.minion.modDB, env.minion.output, env.minion)
|
|
end
|
|
end
|
|
|
|
-- Merge flask modifiers
|
|
if env.mode_combat then
|
|
local effectInc = modDB:Sum("INC", nil, "FlaskEffect")
|
|
local flaskBuffs = { }
|
|
for item in pairs(env.flasks) do
|
|
-- Avert thine eyes, lest they be forever scarred
|
|
-- I have no idea how to determine which buff is applied by a given flask,
|
|
-- so utility flasks are grouped by base, unique flasks are grouped by name, and magic flasks by their modifiers
|
|
local effectMod = 1 + (effectInc + item.flaskData.effectInc) / 100
|
|
if item.buffModList[1] then
|
|
local srcList = common.New("ModList")
|
|
srcList:ScaleAddList(item.buffModList, effectMod)
|
|
mergeBuff(srcList, flaskBuffs, item.baseName)
|
|
end
|
|
if item.modList[1] then
|
|
local srcList = common.New("ModList")
|
|
srcList:ScaleAddList(item.modList, effectMod)
|
|
local key
|
|
if item.rarity == "UNIQUE" then
|
|
key = item.title
|
|
else
|
|
key = ""
|
|
for _, mod in ipairs(item.modList) do
|
|
key = key .. modLib.formatModParams(mod) .. "&"
|
|
end
|
|
end
|
|
mergeBuff(srcList, flaskBuffs, key)
|
|
end
|
|
end
|
|
if not modDB:Sum("FLAG", nil, "FlasksDoNotApplyToPlayer") then
|
|
for _, buffModList in pairs(flaskBuffs) do
|
|
modDB.conditions["UsingFlask"] = true
|
|
modDB:AddList(buffModList)
|
|
end
|
|
end
|
|
if env.minion and modDB:Sum("FLAG", env.player.mainSkill.skillCfg, "FlasksApplyToMinion") then
|
|
for _, buffModList in pairs(flaskBuffs) do
|
|
env.minion.modDB.conditions["UsingFlask"] = true
|
|
env.minion.modDB:AddList(buffModList)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Calculate skill life and mana reservations
|
|
env.player.reserved_LifeBase = 0
|
|
env.player.reserved_LifePercent = modDB:Sum("BASE", nil, "ExtraLifeReserved")
|
|
env.player.reserved_ManaBase = 0
|
|
env.player.reserved_ManaPercent = 0
|
|
if breakdown then
|
|
breakdown.LifeReserved = { reservations = { } }
|
|
breakdown.ManaReserved = { reservations = { } }
|
|
end
|
|
for _, activeSkill in ipairs(env.activeSkillList) do
|
|
if activeSkill.skillTypes[SkillType.ManaCostReserved] and not activeSkill.skillFlags.totem then
|
|
local skillModList = activeSkill.skillModList
|
|
local skillCfg = activeSkill.skillCfg
|
|
local baseVal = activeSkill.skillData.manaCostOverride or activeSkill.skillData.manaCost or 0
|
|
local suffix = activeSkill.skillTypes[SkillType.ManaCostPercent] and "Percent" or "Base"
|
|
local mult = skillModList:Sum("MORE", skillCfg, "ManaCost")
|
|
local more = modDB:Sum("MORE", skillCfg, "ManaReserved") * skillModList:Sum("MORE", skillCfg, "ManaReserved")
|
|
local inc = modDB:Sum("INC", skillCfg, "ManaReserved") + skillModList:Sum("INC", skillCfg, "ManaReserved")
|
|
local base = m_floor(baseVal * mult)
|
|
local cost = base - m_floor(base * -m_floor((100 + inc) * more - 100) / 100)
|
|
local pool
|
|
if modDB:Sum("FLAG", skillCfg, "BloodMagic", "SkillBloodMagic") or skillModList:Sum("FLAG", skillCfg, "SkillBloodMagic") then
|
|
pool = "Life"
|
|
else
|
|
pool = "Mana"
|
|
end
|
|
env.player["reserved_"..pool..suffix] = env.player["reserved_"..pool..suffix] + cost
|
|
if breakdown then
|
|
t_insert(breakdown[pool.."Reserved"].reservations, {
|
|
skillName = activeSkill.activeGem.name,
|
|
base = baseVal .. (activeSkill.skillTypes[SkillType.ManaCostPercent] and "%" or ""),
|
|
mult = mult ~= 1 and ("x "..mult),
|
|
more = more ~= 1 and ("x "..more),
|
|
inc = inc ~= 0 and ("x "..(1 + inc/100)),
|
|
total = cost .. (activeSkill.skillTypes[SkillType.ManaCostPercent] and "%" or ""),
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Calculate attributes and life/mana pools
|
|
doActorAttribsPoolsConditions(env, env.player)
|
|
if env.minion then
|
|
for _, source in ipairs({modDB, env.player.mainSkill.skillModList}) do
|
|
for _, value in ipairs(source:Sum("LIST", env.player.mainSkill.skillCfg, "MinionModifier")) do
|
|
env.minion.modDB:AddMod(value.mod)
|
|
end
|
|
end
|
|
doActorAttribsPoolsConditions(env, env.minion)
|
|
end
|
|
|
|
-- Check for extra modifiers to apply to aura skills
|
|
local extraAuraModList = { }
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "ExtraAuraEffect")) do
|
|
t_insert(extraAuraModList, value.mod)
|
|
end
|
|
|
|
-- Combine buffs/debuffs
|
|
output.EnemyCurseLimit = modDB:Sum("BASE", nil, "EnemyCurseLimit")
|
|
local buffs = { }
|
|
local minionBuffs = { }
|
|
local debuffs = { }
|
|
local curses = {
|
|
limit = output.EnemyCurseLimit,
|
|
}
|
|
local minionCurses = {
|
|
limit = 1,
|
|
}
|
|
local affectedByAura = { }
|
|
for _, activeSkill in ipairs(env.activeSkillList) do
|
|
local skillModList = activeSkill.skillModList
|
|
local skillCfg = activeSkill.skillCfg
|
|
if env.mode_buffs then
|
|
if activeSkill.buffModList and
|
|
not activeSkill.skillFlags.curse and
|
|
(not activeSkill.skillFlags.totem or activeSkill.skillData.allowTotemBuff) then
|
|
if not activeSkill.skillData.buffNotPlayer then
|
|
activeSkill.buffSkill = true
|
|
local srcList = common.New("ModList")
|
|
local inc = modDB:Sum("INC", skillCfg, "BuffEffect", "BuffEffectOnSelf")
|
|
local more = modDB:Sum("MORE", skillCfg, "BuffEffect", "BuffEffectOnSelf")
|
|
srcList:ScaleAddList(activeSkill.buffModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, buffs, activeSkill.activeGem.name)
|
|
end
|
|
if env.minion and (activeSkill.skillData.buffMinions or activeSkill.skillData.buffAllies) then
|
|
activeSkill.minionBuffSkill = true
|
|
local srcList = common.New("ModList")
|
|
local inc = modDB:Sum("INC", skillCfg, "BuffEffect") + env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf")
|
|
local more = modDB:Sum("MORE", skillCfg, "BuffEffect") * env.minion.modDB:Sum("MORE", nil, "BuffEffectOnSelf")
|
|
srcList:ScaleAddList(activeSkill.buffModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, minionBuffs, activeSkill.activeGem.name)
|
|
end
|
|
end
|
|
if activeSkill.auraModList then
|
|
if not activeSkill.skillData.auraCannotAffectSelf then
|
|
activeSkill.buffSkill = true
|
|
affectedByAura[env.player] = true
|
|
local srcList = common.New("ModList")
|
|
local inc = modDB:Sum("INC", skillCfg, "AuraEffect", "BuffEffectOnSelf", "AuraEffectOnSelf") + skillModList:Sum("INC", skillCfg, "AuraEffect")
|
|
local more = modDB:Sum("MORE", skillCfg, "AuraEffect", "BuffEffectOnSelf", "AuraEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "AuraEffect")
|
|
srcList:ScaleAddList(activeSkill.auraModList, (1 + inc / 100) * more)
|
|
srcList:ScaleAddList(extraAuraModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, buffs, activeSkill.activeGem.name)
|
|
end
|
|
if env.minion and not modDB:Sum("FLAG", nil, "YourAurasCannotAffectAllies") then
|
|
activeSkill.minionBuffSkill = true
|
|
affectedByAura[env.minion] = true
|
|
local srcList = common.New("ModList")
|
|
local inc = modDB:Sum("INC", skillCfg, "AuraEffect") + env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + skillModList:Sum("INC", skillCfg, "AuraEffect")
|
|
local more = modDB:Sum("MORE", skillCfg, "AuraEffect") * env.minion.modDB:Sum("MORE", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "AuraEffect")
|
|
srcList:ScaleAddList(activeSkill.auraModList, (1 + inc / 100) * more)
|
|
srcList:ScaleAddList(extraAuraModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, minionBuffs, activeSkill.activeGem.name)
|
|
end
|
|
end
|
|
if activeSkill.minion then
|
|
for _, activeSkill in ipairs(activeSkill.minion.activeSkillList) do
|
|
local skillModList = activeSkill.skillModList
|
|
local skillCfg = activeSkill.skillCfg
|
|
if activeSkill.auraModList and activeSkill.skillData.enable then
|
|
if not modDB:Sum("FLAG", nil, "AlliesAurasCannotAffectSelf") then
|
|
local srcList = common.New("ModList")
|
|
local inc = modDB:Sum("INC", skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") + skillModList:Sum("INC", skillCfg, "AuraEffect")
|
|
local more = modDB:Sum("MORE", skillCfg, "BuffEffectOnSelf", "AuraEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "AuraEffect")
|
|
srcList:ScaleAddList(activeSkill.auraModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, buffs, activeSkill.activeGem.data.id)
|
|
end
|
|
if env.minion and (env.minion ~= activeSkill.minion or not activeSkill.skillData.auraCannotAffectSelf) then
|
|
local srcList = common.New("ModList")
|
|
local inc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") + skillModList:Sum("INC", skillCfg, "AuraEffect")
|
|
local more = env.minion.modDB:Sum("MORE", nil, "BuffEffectOnSelf", "AuraEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "AuraEffect")
|
|
srcList:ScaleAddList(activeSkill.auraModList, (1 + inc / 100) * more)
|
|
mergeBuff(srcList, minionBuffs, activeSkill.activeGem.data.id)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if env.mode_effective then
|
|
if activeSkill.debuffModList then
|
|
activeSkill.debuffSkill = true
|
|
local srcList = common.New("ModList")
|
|
srcList:ScaleAddList(activeSkill.debuffModList, activeSkill.skillData.stackCount or 1)
|
|
mergeBuff(srcList, debuffs, activeSkill.activeGem.name)
|
|
end
|
|
if (activeSkill.curseModList or (activeSkill.skillFlags.curse and activeSkill.buffModList))
|
|
and (not enemyDB:Sum("FLAG", nil, "Hexproof") or modDB:Sum("FLAG", nil, "CursesIgnoreHexproof")) then
|
|
local curse = {
|
|
name = activeSkill.activeGem.name,
|
|
fromPlayer = true,
|
|
priority = activeSkill.skillTypes[SkillType.Aura] and 3 or 1,
|
|
}
|
|
local inc = modDB:Sum("INC", skillCfg, "CurseEffect") + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") + skillModList:Sum("INC", skillCfg, "CurseEffect")
|
|
local more = modDB:Sum("MORE", skillCfg, "CurseEffect") * enemyDB:Sum("MORE", nil, "CurseEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "CurseEffect")
|
|
if activeSkill.curseModList then
|
|
curse.modList = common.New("ModList")
|
|
curse.modList:ScaleAddList(activeSkill.curseModList, (1 + inc / 100) * more)
|
|
end
|
|
if activeSkill.buffModList then
|
|
-- Curse applies a buff; scale by curse effect, then buff effect
|
|
local temp = common.New("ModList")
|
|
temp:ScaleAddList(activeSkill.buffModList, (1 + inc / 100) * more)
|
|
curse.buffModList = common.New("ModList")
|
|
local buffInc = modDB:Sum("INC", skillCfg, "BuffEffectOnSelf")
|
|
local buffMore = modDB:Sum("MORE", skillCfg, "BuffEffectOnSelf")
|
|
curse.buffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore)
|
|
if env.minion then
|
|
curse.minionBuffModList = common.New("ModList")
|
|
local buffInc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf")
|
|
local buffMore = env.minion.modDB:Sum("MORE", nil, "BuffEffectOnSelf")
|
|
curse.minionBuffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore)
|
|
end
|
|
end
|
|
t_insert(curses, curse)
|
|
end
|
|
if activeSkill.minion then
|
|
for _, activeSkill in ipairs(activeSkill.minion.activeSkillList) do
|
|
local skillModList = activeSkill.skillModList
|
|
local skillCfg = activeSkill.skillCfg
|
|
if activeSkill.curseModList and activeSkill.skillData.enable and not enemyDB:Sum("FLAG", nil, "Hexproof") then
|
|
local curse = {
|
|
name = activeSkill.activeGem.name,
|
|
priority = 1,
|
|
}
|
|
local inc = enemyDB:Sum("INC", nil, "CurseEffectOnSelf") + skillModList:Sum("INC", skillCfg, "CurseEffect")
|
|
local more = enemyDB:Sum("MORE", nil, "CurseEffectOnSelf") * skillModList:Sum("MORE", skillCfg, "CurseEffect")
|
|
curse.modList = common.New("ModList")
|
|
curse.modList:ScaleAddList(activeSkill.curseModList, (1 + inc / 100) * more)
|
|
t_insert(minionCurses, curse)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Check for extra curses
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "ExtraCurse")) do
|
|
local gemModList = common.New("ModList")
|
|
calcs.mergeGemMods(gemModList, {
|
|
level = value.level,
|
|
quality = 0,
|
|
data = data.gems[value.name],
|
|
})
|
|
local curseModList = { }
|
|
for _, mod in ipairs(gemModList) do
|
|
for _, tag in ipairs(mod.tagList) do
|
|
if tag.type == "GlobalEffect" and tag.effectType == "Curse" then
|
|
t_insert(curseModList, mod)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if value.applyToPlayer then
|
|
-- Sources for curses on the player don't usually respect any kind of limit, so there's little point bothering with slots
|
|
modDB.multipliers["CurseOnSelf"] = (modDB.multipliers["CurseOnSelf"] or 0) + 1
|
|
modDB:ScaleAddList(curseModList, (1 + modDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * modDB:Sum("MORE", nil, "CurseEffectOnSelf"))
|
|
elseif not enemyDB:Sum("FLAG", nil, "Hexproof") or modDB:Sum("FLAG", nil, "CursesIgnoreHexproof") then
|
|
local curse = {
|
|
name = value.name,
|
|
fromPlayer = true,
|
|
priority = 2,
|
|
}
|
|
curse.modList = common.New("ModList")
|
|
curse.modList:ScaleAddList(curseModList, (1 + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * enemyDB:Sum("MORE", nil, "CurseEffectOnSelf"))
|
|
t_insert(curses, curse)
|
|
end
|
|
end
|
|
|
|
-- Assign curses to slots
|
|
local curseSlots = { }
|
|
env.curseSlots = curseSlots
|
|
for _, source in ipairs({curses, minionCurses}) do
|
|
for _, curse in ipairs(source) do
|
|
local slot
|
|
for i = 1, source.limit do
|
|
if not curseSlots[i] then
|
|
slot = i
|
|
break
|
|
elseif curseSlots[i].name == curse.name then
|
|
if curseSlots[i].priority < curse.priority then
|
|
slot = i
|
|
else
|
|
slot = nil
|
|
end
|
|
break
|
|
elseif curseSlots[i].priority < curse.priority then
|
|
slot = i
|
|
end
|
|
end
|
|
if slot then
|
|
curseSlots[slot] = curse
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Apply buff/debuff modifiers
|
|
for _, modList in pairs(buffs) do
|
|
modDB:AddList(modList)
|
|
end
|
|
if env.minion then
|
|
for _, modList in pairs(minionBuffs) do
|
|
env.minion.modDB:AddList(modList)
|
|
end
|
|
end
|
|
for _, modList in pairs(debuffs) do
|
|
enemyDB:AddList(modList)
|
|
end
|
|
modDB.multipliers["CurseOnEnemy"] = #curseSlots
|
|
local affectedByCurse = { }
|
|
for _, slot in ipairs(curseSlots) do
|
|
enemyDB.conditions["Cursed"] = true
|
|
if slot.fromPlayer then
|
|
affectedByCurse[env.enemy] = true
|
|
end
|
|
if slot.modList then
|
|
enemyDB:AddList(slot.modList)
|
|
end
|
|
if slot.buffModList then
|
|
modDB:AddList(slot.buffModList)
|
|
end
|
|
if slot.minionBuffModList then
|
|
env.minion.modDB:AddList(slot.minionBuffModList)
|
|
end
|
|
end
|
|
|
|
-- Check for extra auras
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "ExtraAura")) do
|
|
local modList = { value.mod }
|
|
if not value.onlyAllies then
|
|
local inc = modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
|
|
local more = modDB:Sum("MORE", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
|
|
modDB:ScaleAddList(modList, (1 + inc / 100) * more)
|
|
end
|
|
if env.minion and not modDB:Sum("FLAG", nil, "SelfAurasCannotAffectAllies") then
|
|
local inc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
|
|
local more = env.minion.modDB:Sum("MORE", nil, "BuffEffectOnSelf", "AuraEffectOnSelf")
|
|
env.minion.modDB:ScaleAddList(modList, (1 + inc / 100) * more)
|
|
end
|
|
end
|
|
|
|
-- Check for modifiers to apply to actors affected by player auras or curses
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "AffectedByAuraMod")) do
|
|
for actor in pairs(affectedByAura) do
|
|
actor.modDB:AddMod(value.mod)
|
|
end
|
|
end
|
|
for _, value in ipairs(modDB:Sum("LIST", nil, "AffectedByCurseMod")) do
|
|
for actor in pairs(affectedByCurse) do
|
|
actor.modDB:AddMod(value.mod)
|
|
end
|
|
end
|
|
|
|
-- Process misc buffs/modifiers
|
|
doActorMisc(env, env.player)
|
|
if env.minion then
|
|
doActorMisc(env, env.minion)
|
|
end
|
|
doActorMisc(env, env.enemy)
|
|
|
|
-- Defence/offence calculations
|
|
calcs.defence(env, env.player)
|
|
calcs.offence(env, env.player)
|
|
if env.minion then
|
|
calcs.defence(env, env.minion)
|
|
calcs.offence(env, env.minion)
|
|
end
|
|
end |