landsandboat/scripts/combat/basic/damage_multipliers.lua
Xaver-DaRed 0fb133ed39 Cleanup requires and hook to lua loading
Co-Authored-By: sruon <sruon@users.noreply.github.com>
2026-07-08 14:07:25 +02:00

162 lines
7.4 KiB
Lua

-----------------------------------
xi = xi or {}
xi.combat = xi.combat or {}
xi.combat.damage = xi.combat.damage or {}
-----------------------------------
xi.combat.damage.physicalElementSDT = function(target, physicalElement)
if
physicalElement < xi.damageType.PIERCING or
physicalElement > xi.damageType.HAND_TO_HAND
then
return 1
end
local physicalElementSDTModifier =
{
[xi.damageType.PIERCING ] = xi.mod.PIERCE_SDT,
[xi.damageType.SLASHING ] = xi.mod.SLASH_SDT,
[xi.damageType.BLUNT ] = xi.mod.IMPACT_SDT,
[xi.damageType.HAND_TO_HAND] = xi.mod.HTH_SDT,
}
local sdt = 1 + target:getMod(physicalElementSDTModifier[physicalElement]) / 10000
return utils.clamp(sdt, 0, 3)
end
xi.combat.damage.magicalElementSDT = function(target, magicalElement)
if magicalElement < xi.element.FIRE then
return 1
end
if magicalElement > xi.element.DARK then
return 1
end
local sdt = 1 + target:getMod(xi.data.element.getElementalSDTModifier(magicalElement)) / 10000
return utils.clamp(sdt, 0, 3)
end
xi.combat.damage.calculateDamageAdjustment = function(target, isPhysical, isMagical, isRanged, isBreath)
-- NOTE: -2500 -> 25% less damage taken by target. 2500 -> 25% more damage taken by target.
local targetDamageTaken = 1
-- "Damage Taken -x%"
local globalDamageTaken = target:getMod(xi.mod.DMG) / 10000
-- "Physical Damage Taken -X%", "Physical Damage Taken II -X%"
local physicalDamageTaken = isPhysical and target:getMod(xi.mod.DMGPHYS) / 10000 or 0
local physicalDamageTakenII = isPhysical and target:getMod(xi.mod.DMGPHYS_II) / 10000 or 0
local physicalDamageTakenUncapped = isPhysical and target:getMod(xi.mod.UDMGPHYS) / 10000 or 0
-- "Magic Damage Taken -X%", "Magic Damage Taken II -X%"
local magicDamageTaken = isMagical and target:getMod(xi.mod.DMGMAGIC) / 10000 or 0
local magicDamageTakenII = isMagical and target:getMod(xi.mod.DMGMAGIC_II) / 10000 or 0
local magicDamageTakenUncapped = isMagical and target:getMod(xi.mod.UDMGMAGIC) / 10000 or 0
-- "Ranged Damage Taken -X%" (Doesn't actually exist in gear. Physical damage taken has both.)
local rangedDamageTaken = isRanged and target:getMod(xi.mod.DMGRANGE) / 10000 or 0
local rangedDamageTakenUncapped = isRanged and target:getMod(xi.mod.UDMGRANGE) / 10000 or 0
-- "Breath Damage Taken -X%"
local breathDamageTaken = isBreath and target:getMod(xi.mod.DMGBREATH) / 10000 or 0
local breathDamageTakenUncapped = isBreath and target:getMod(xi.mod.UDMGBREATH) / 10000 or 0
-- The combination of regular "Damage Taken" and "<type> Damage Taken" caps at 50% both ways.
local combinedDamageTaken = utils.clamp(globalDamageTaken + physicalDamageTaken + magicDamageTaken + rangedDamageTaken + breathDamageTaken, -0.5, 0.5)
-- "<type> Damage Taken II" bypasses the regular cap, but combined cap is 87.5% both ways.
targetDamageTaken = utils.clamp(targetDamageTaken + combinedDamageTaken + physicalDamageTakenII + magicDamageTakenII, 0.125, 1.875)
-- Uncapped damage modifiers. Cap is 100% both ways anyway, just in case.
targetDamageTaken = utils.clamp(targetDamageTaken + physicalDamageTakenUncapped + magicDamageTakenUncapped + rangedDamageTakenUncapped + breathDamageTakenUncapped, 0, 2)
return targetDamageTaken
end
xi.combat.damage.ecosystemMultiplier = function(actor, target, actionEcosystem)
local ecosystemMultiplier = 1
local actorEcosystem = actor:getEcosystem()
local targetEcosystem = target:getEcosystem()
local actorNMFactor = actor:isNM() and 1 or 0
local targetNMFactor = target:isNM() and 1 or 0
-- Killer effects can be augmented to apply damage bonuses. (Ex: Ferine, Nukumi Gausapes or Founder's Breastplate)
local actorKillerMod = xi.data.entityCorrelation.getEcosystemKillerMod(actorEcosystem)
local targetKillerMod = xi.data.entityCorrelation.getEcosystemKillerMod(targetEcosystem)
local actorKillerBonus = actor:getMod(targetKillerMod) * (actor:getMod(xi.mod.AUGMENT_KILLER_EFFECTS) / (1 + targetNMFactor)) / 100
local targetKillerBonus = target:getMod(actorKillerMod) * (target:getMod(xi.mod.AUGMENT_KILLER_EFFECTS) / (1 + actorNMFactor)) / 100
ecosystemMultiplier = ecosystemMultiplier + math.floor(actorKillerBonus) / 100 - math.floor(targetKillerBonus) / 100
-- Circles apply an additive damage multiplier and also a damage reduction.
local damageMultiplierMod = xi.data.entityCorrelation.getEcosystemDamageMultiplierMod(targetEcosystem)
local damageResistanceMod = xi.data.entityCorrelation.getEcosystemDamageReductionMod(actorEcosystem)
local damageMultiplierValue = actor:getMod(damageMultiplierMod) / (1 + targetNMFactor)
local damageResistanceValue = target:getMod(damageResistanceMod) / (1 + actorNMFactor)
ecosystemMultiplier = ecosystemMultiplier + math.floor(damageMultiplierValue) / 100 - math.floor(damageResistanceValue) / 100
-- Action ecosystem property. Mostly blue spells. Can be positive or negative. Additive to everything else, not multiplicative.
if actionEcosystem > 0 then
local strongAgainstEco = xi.data.entityCorrelation.getEcosystemStrongAgainst(actionEcosystem)
local weakAgainstEco = xi.data.entityCorrelation.getEcosystemWeakAgainst(actionEcosystem)
-- This action property is strong against target's ecosystem.
if strongAgainstEco and strongAgainstEco == targetEcosystem then
ecosystemMultiplier = ecosystemMultiplier + 0.25 + actor:getMerit(xi.merit.MONSTER_CORRELATION) / 100
-- This action property is weak against target's ecosystem.
elseif weakAgainstEco and weakAgainstEco == targetEcosystem then
ecosystemMultiplier = ecosystemMultiplier - 0.25
end
end
-- Final multiplier caps. TODO: confirm.
ecosystemMultiplier = utils.clamp(ecosystemMultiplier, 0.5, 1.5)
return ecosystemMultiplier
end
xi.combat.damage.scarletDeliriumMultiplier = function(actor)
-- Scarlet delirium are 2 different status effects. SCARLET_DELIRIUM_1 is the one that boosts power.
if not actor:hasStatusEffect(xi.effect.SCARLET_DELIRIUM_1) then
return 1
end
local scarletDeliriumMultiplier = 1 + actor:getStatusEffect(xi.effect.SCARLET_DELIRIUM_1):getPower() / 1000
return scarletDeliriumMultiplier
end
-- Handles Automaton attachment "Steam Jacket", which reduces damage from consecutive elemental damage.
xi.combat.damage.steamJacketMultiplier = function(target, magicalElement)
-- Early return: Action isn't elemental.
if magicalElement < xi.element.FIRE then
return 1
end
-- Early return: Action isn't elemental.
if magicalElement > xi.element.DARK then
return 1
end
-- Early return: Target can't track an element.
local steamJacketModifierValue = target:getMod(xi.mod.AUTO_STEAM_JACKET_REDUCTION)
if steamJacketModifierValue <= 0 then
return 1
end
-- Handle element tracking.
local trackedElement = target:getLocalVar('[steamJacket]Element')
target:setLocalVar('[steamJacket]Element', magicalElement)
-- Early return: Action element doesn't match Steam Jacket's element.
if trackedElement ~= magicalElement then
return 1
end
return 1 - steamJacketModifierValue / 100
end