201 lines
8.6 KiB
Lua
201 lines
8.6 KiB
Lua
-----------------------------------
|
|
-- Global file for additional effects (damage)
|
|
-----------------------------------
|
|
require('scripts/globals/combat/damage_multipliers')
|
|
require('scripts/globals/combat/magic_hit_rate')
|
|
-----------------------------------
|
|
xi = xi or {}
|
|
xi.combat = xi.combat or {}
|
|
xi.combat.action = xi.combat.action or {}
|
|
-----------------------------------
|
|
|
|
local defaultsTable =
|
|
{
|
|
[xi.element.NONE ] = { xi.subEffect.LIGHT_DAMAGE }, -- Like Excalibur.
|
|
[xi.element.FIRE ] = { xi.subEffect.FIRE_DAMAGE },
|
|
[xi.element.ICE ] = { xi.subEffect.ICE_DAMAGE },
|
|
[xi.element.WIND ] = { xi.subEffect.WIND_DAMAGE },
|
|
[xi.element.EARTH ] = { xi.subEffect.EARTH_DAMAGE },
|
|
[xi.element.THUNDER] = { xi.subEffect.LIGHTNING_DAMAGE },
|
|
[xi.element.WATER ] = { xi.subEffect.WATER_DAMAGE },
|
|
[xi.element.LIGHT ] = { xi.subEffect.LIGHT_DAMAGE },
|
|
[xi.element.DARK ] = { xi.subEffect.DARKNESS_DAMAGE },
|
|
}
|
|
|
|
-----------------------------------
|
|
-- Local functions to ensure defaults are set.
|
|
-----------------------------------
|
|
local function validateParameters(actor, target, fedData)
|
|
local params = {}
|
|
|
|
-- Additional effect target.
|
|
params.aeTarget = fedData.aeTarget or target -- Default to the current attack target.
|
|
|
|
-- Chance.
|
|
params.chance = fedData.chance or 100 -- Default: Always proc.
|
|
|
|
-- Limit undead
|
|
params.limitUndead = fedData.limitUndead or false -- Default: Works on undead.
|
|
|
|
-- Action properties.
|
|
params.attackType = fedData.attackType or xi.attackType.SPECIAL -- Physical, Magical, Ranged, Breath or Special.
|
|
params.physicalElement = fedData.physicalElement or xi.damageType.NONE -- None, H2H, Slashing, Piercing or Blunt.
|
|
params.magicalElement = fedData.magicalElement or xi.element.NONE -- None, Fire, Ice, Wind, Earth, Thunder, Water, Light, Dark.
|
|
|
|
-- Base damage parameters.
|
|
params.basePower = fedData.basePower or 0
|
|
params.actorStat = fedData.actorStat or 0
|
|
params.targetStat = fedData.targetStat or params.actorStat
|
|
|
|
-- Multiplier properties.
|
|
params.canMAB = fedData.canMAB or false
|
|
params.canResist = fedData.canResist or false
|
|
params.lowestResist = fedData.lowestResist or 0.125
|
|
params.canResistExtra = fedData.canResistExtra or false
|
|
|
|
-- Drain properties.
|
|
params.drainHP = fedData.drainHP or false
|
|
params.drainMP = fedData.drainMP or false
|
|
params.drainTP = fedData.drainTP or false
|
|
params.overDrain = fedData.overDrain or false
|
|
|
|
-- Animations and messaging.
|
|
params.animation = fedData.animation or defaultsTable[params.magicalElement][1]
|
|
params.messageDamage = fedData.messageDamage or xi.msg.basic.ADD_EFFECT_DMG
|
|
params.messageHeal = fedData.messageHeal or xi.msg.basic.ADD_EFFECT_HEAL
|
|
|
|
return params
|
|
end
|
|
|
|
local function hasEnspell(actor)
|
|
local enspellTable =
|
|
{
|
|
[ 1] = xi.effect.ENFIRE,
|
|
[ 2] = xi.effect.ENFIRE_II,
|
|
[ 3] = xi.effect.ENBLIZZARD,
|
|
[ 4] = xi.effect.ENBLIZZARD_II,
|
|
[ 5] = xi.effect.ENAERO,
|
|
[ 6] = xi.effect.ENAERO_II,
|
|
[ 7] = xi.effect.ENSTONE,
|
|
[ 8] = xi.effect.ENSTONE_II,
|
|
[ 9] = xi.effect.ENTHUNDER,
|
|
[10] = xi.effect.ENTHUNDER_II,
|
|
[11] = xi.effect.ENWATER,
|
|
[12] = xi.effect.ENWATER_II,
|
|
[13] = xi.effect.ENLIGHT,
|
|
[14] = xi.effect.ENDARK,
|
|
}
|
|
|
|
for i = 1, #enspellTable do
|
|
if actor:hasStatusEffect(enspellTable[i]) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Global functions called from "emtity.onAdditionalEffect()"
|
|
-----------------------------------
|
|
xi.combat.action.executeAddEffectDamage = function(actor, target, fedData)
|
|
local params = validateParameters(actor, target, fedData)
|
|
|
|
-- Early return: En-spell overrides innate/weapon additional effects.
|
|
if hasEnspell(actor) then
|
|
return 0, 0, 0
|
|
end
|
|
|
|
-- Early return: No proc.
|
|
if math.random(1, 100) > params.chance then
|
|
return 0, 0, 0
|
|
end
|
|
|
|
-- Early return: Limit undead.
|
|
if params.limitUndead and params.aeTarget:isUndead() then
|
|
return 0, 0, 0
|
|
end
|
|
|
|
-- Additional variables.
|
|
local isPhysical = params.attackType == xi.attackType.PHYSICAL or false
|
|
local isMagical = params.attackType == xi.attackType.MAGICAL or false
|
|
local isRanged = params.attackType == xi.attackType.RANGED or false
|
|
local isBreath = params.attackType == xi.attackType.BREATH or false
|
|
|
|
-- Calculate base power.
|
|
local damage = params.basePower + actor:getMod(params.actorStat) - params.aeTarget:getMod(params.targetStat)
|
|
|
|
-- Calculate mandatory multipliers.
|
|
local multiplierAbsorption = xi.spells.damage.calculateAbsorption(params.aeTarget, params.magicalElement, params.isMagical)
|
|
local multiplierNullification = xi.spells.damage.calculateNullification(params.aeTarget, params.magicalElement, isMagical, isBreath)
|
|
local multiplierDamageTypeSDT = xi.combat.damage.calculateDamageAdjustment(params.aeTarget, isPhysical, isMagical, isRanged, isBreath)
|
|
local multiplierPhysicalElementSDT = xi.combat.damage.physicalElementSDT(params.aeTarget, params.physicalElement)
|
|
local multiplierMagicalElementSDT = xi.combat.damage.magicalElementSDT(params.aeTarget, params.magicalElement)
|
|
local multiplierElementalStaff = xi.spells.damage.calculateElementalStaffBonus(actor, params.magicalElement)
|
|
local multiplierElementalAffinity = xi.spells.damage.calculateElementalAffinityBonus(actor, params.magicalElement)
|
|
local multiplierDayWeather = xi.spells.damage.calculateDayAndWeather(actor, params.magicalElement, false)
|
|
|
|
-- Calculate optional multipliers.
|
|
local multiplierMagicDiff = params.canMAB and xi.spells.damage.calculateMagicBonusDiff(actor, params.aeTarget, 0, 0, params.magicalElement, 0) or 1
|
|
local multiplierResist = params.canResist and xi.combat.magicHitRate.calculateResistRate(actor, params.aeTarget, 0, 0, xi.skillRank.A_PLUS, params.magicalElement, params.actorStat, 0, 0) or 1
|
|
local multiplierForcedResistTier = params.canResistExtra and xi.spells.damage.calculateAdditionalResistTier(actor, params.aeTarget, params.magicalElement) or 1
|
|
|
|
-- Early return: Resist state is too low. Auto-fail.
|
|
if multiplierResist < params.lowestResist then
|
|
return 0, 0, 0
|
|
end
|
|
|
|
-- Calculate final damage.
|
|
damage = math.floor(damage * multiplierAbsorption)
|
|
damage = math.floor(damage * multiplierNullification)
|
|
damage = math.floor(damage * multiplierDamageTypeSDT)
|
|
damage = math.floor(damage * multiplierPhysicalElementSDT)
|
|
damage = math.floor(damage * multiplierMagicalElementSDT)
|
|
damage = math.floor(damage * multiplierElementalStaff)
|
|
damage = math.floor(damage * multiplierElementalAffinity)
|
|
damage = math.floor(damage * multiplierDayWeather)
|
|
damage = math.floor(damage * multiplierMagicDiff)
|
|
damage = math.floor(damage * multiplierResist)
|
|
damage = math.floor(damage * multiplierForcedResistTier)
|
|
|
|
-- Phalanx, One for all, Stoneskin.
|
|
if damage > 0 then
|
|
damage = utils.clamp(utils.handlePhalanx(params.aeTarget, damage), 0, 99999)
|
|
damage = utils.clamp(utils.handleOneForAll(params.aeTarget, damage), 0, 99999)
|
|
damage = utils.clamp(utils.handleStoneskin(params.aeTarget, damage), 0, 99999)
|
|
end
|
|
|
|
-- Drain HP, MP or TP
|
|
if params.drainHP then
|
|
damage = params.overDrain and damage or utils.clamp(damage, 0, params.aeTarget:getHP())
|
|
params.messageDamage = xi.msg.basic.ADD_EFFECT_HP_DRAIN
|
|
actor:addHP(damage)
|
|
end
|
|
|
|
if params.drainMP then
|
|
damage = params.overDrain and damage or utils.clamp(damage, 0, params.aeTarget:getMP())
|
|
params.messageDamage = xi.msg.basic.ADD_EFFECT_MP_DRAIN
|
|
actor:addMP(damage)
|
|
end
|
|
|
|
if params.drainTP then
|
|
damage = params.overDrain and damage or utils.clamp(damage, 0, params.aeTarget:getTP())
|
|
params.messageDamage = xi.msg.basic.ADD_EFFECT_TP_DRAIN
|
|
actor:addTP(damage)
|
|
end
|
|
|
|
-- No damage, no proc.
|
|
if damage == 0 then
|
|
return 0, 0, 0
|
|
end
|
|
|
|
if damage < 0 then
|
|
params.aeTarget:addHP(-damage) -- Heal target.
|
|
return params.animation, params.messageHeal, -damage
|
|
end
|
|
|
|
local actionDamageType = params.physicalElement > 0 and params.physicalElement or xi.damageType.ELEMENTAL + params.magicalElement
|
|
params.aeTarget:takeDamage(damage, actor, params.attackType, actionDamageType)
|
|
|
|
return params.animation, params.messageDamage, damage
|
|
end
|