landsandboat/scripts/combat/action_mobskill_status_effect.lua

167 lines
6 KiB
Lua

-----------------------------------
-- Global file for mobskills that apply status effects.
-----------------------------------
xi = xi or {}
xi.combat = xi.combat or {}
xi.combat.action = xi.combat.action or {}
-----------------------------------
-- Define each step where the process can end.
local step =
{
CANT_GAIN = 1,
IMMUNE_CHECK = 2,
RESIST_TRAIT_CHECK = 3,
NULLIFY_CHECK = 4,
RESIST_RATE_CHECK = 5,
APPLICATION_FAIL = 6,
APPLICATION_SUCCESS = 7,
}
-- Validate the parameters of an specific entry of the status effect table.
local function validateEffectParameters(fedData)
local params = {}
-- Status effect application parameters.
params.effectId = fedData.effectId or 0
params.power = fedData.power or 0
params.tick = fedData.tick or 0
params.duration = fedData.duration or 0
params.subType = fedData.subType or 0
params.subPower = fedData.subPower or 0
params.tier = fedData.tier or 0
-- Calculation parameters.
params.magicalElement = fedData.magicalElement or xi.data.statusEffect.getAssociatedElement(params.effectId, xi.element.NONE)
params.skillRank = fedData.skillRank or xi.skillRank.A_PLUS -- The skill rank used for macc.
params.actorStat = fedData.actorStat or xi.mod.INT -- Stat used for macc.
params.targetStat = fedData.targetStat or params.actorStat
params.bonusMacc = fedData.bonusMacc or 0 -- Flat macc bonus addition.
params.resistRate = fedData.resistRate or 0
return params
end
-- Validate the parameters of the skill messaging.
local function validateMessageParameters(fedData)
local params = {}
-- Action messages per step.
params.messageBypass = fedData.messageBypass or false
params.messageCantGain = fedData.messageCantGain or xi.msg.basic.SKILL_NO_EFFECT
params.messageIsImmune = fedData.messageIsImmune or xi.msg.basic.SKILL_MISS
params.messageIsTraitResisted = fedData.messageIsTraitResisted or xi.msg.basic.SKILL_MISS
params.messageIsIncompatible = fedData.messageIsIncompatible or xi.msg.basic.SKILL_MISS
params.messageIsResisted = fedData.messageIsResisted or xi.msg.basic.SKILL_MISS
params.messageIsNotSuccessful = fedData.messageIsNotSuccessful or xi.msg.basic.SKILL_MISS
params.messageIsSuccessful = fedData.messageIsSuccessful or xi.msg.basic.SKILL_ENFEEB_IS
return params
end
-- Handle (and apply) the action status effect.
local function handleStatusEffect(actor, target, params)
-- Check if can gain.
if not target:canGainStatusEffect(params.effectId, params.power) then
return step.CANT_GAIN
end
-- Check immunity.
if xi.data.statusEffect.isTargetImmune(target, params.effectId, params.magicalElement) then
return step.IMMUNE_CHECK
-- Check resist traits.
elseif xi.data.statusEffect.isTargetResistant(actor, target, params.effectId) then
return step.RESIST_TRAIT_CHECK
-- Check effect incompatibilities.
elseif xi.data.statusEffect.isEffectNullified(target, params.effectId, params.tier) then
return step.NULLIFY_CHECK
end
-- Calculate resist state.
local resistanceRate = xi.combat.magicHitRate.calculateResistRate(actor, target, params)
if not xi.data.statusEffect.isResistRateSuccessfull(params.effectId, resistanceRate, params.resistRate) then
return step.RESIST_RATE_CHECK
end
-- Calculate duration.
local totalDuration = math.floor(params.duration * resistanceRate)
-- Apply effect.
if target:addStatusEffect(params.effectId, { power = params.power, duration = totalDuration, origin = actor, tick = params.tick, subType = params.subType, subPower = params.subPower, tier = params.tier }) then
return step.APPLICATION_SUCCESS
end
return step.APPLICATION_FAIL
end
-- Handle (set) the action message Id.
local function handleActionMessage(skill, bestResult, messageParams)
if messageParams.messageBypass then
return
end
switch(bestResult): caseof
{
[step.CANT_GAIN] = function()
skill:setMsg(messageParams.messageCantGain)
end,
[step.IMMUNE_CHECK] = function()
skill:setMsg(messageParams.messageIsImmune)
end,
[step.RESIST_TRAIT_CHECK] = function()
skill:setMsg(messageParams.messageIsTraitResisted)
end,
[step.NULLIFY_CHECK] = function()
skill:setMsg(messageParams.messageIsIncompatible)
end,
[step.RESIST_RATE_CHECK] = function()
skill:setMsg(messageParams.messageIsResisted)
end,
[step.APPLICATION_FAIL] = function()
skill:setMsg(messageParams.messageIsNotSuccessful)
end,
[step.APPLICATION_SUCCESS] = function()
skill:setMsg(messageParams.messageIsSuccessful)
end,
}
end
xi.combat.action.executeMobskillStatusEffect = function(actor, target, skill, effectData, messageData)
-- Cycle over all effects. Apply (or not) and save the result in a table.
local dTableEffectResults = {}
for i = 1, #effectData do
local effectParams = validateEffectParameters(effectData[i])
local result = handleStatusEffect(actor, target, effectParams)
table.insert(dTableEffectResults, i, { effectParams.effectId, result })
end
-- Decide best effect outcome, for the message and the effect Id to return.
local bestResult = 0
local bestIndex = 0
for j = 1, #dTableEffectResults do
local currentResult = dTableEffectResults[j][2]
if currentResult > bestResult then
bestResult = currentResult
bestIndex = j
end
end
-- Fetch best effect Id.
local effectId = dTableEffectResults[bestIndex][1]
-- Handle messaging.
local messageParams = validateMessageParameters(messageData)
handleActionMessage(skill, bestResult, messageParams)
-- Return best effect Id.
return effectId
end