landsandboat/scripts/data/status_effect_tables.lua

237 lines
12 KiB
Lua

-----------------------------------
-- Table defining diferent status effect properties.
-----------------------------------
-- Info
-- Resistance: https://wiki-ffo-jp.translate.goog/html/1801.html?_x_tr_sl=ja&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=sc
-- Effects: https://wiki-ffo-jp.translate.goog/html/1720.html?_x_tr_sl=ja&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=sc
-- Resist: https://wiki-ffo-jp.translate.goog/html/795.html?_x_tr_sl=ja&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=sc
-- Immunobreak: https://wiki-ffo-jp.translate.goog/html/27204.html?_x_tr_sl=ja&_x_tr_tl=en&_x_tr_hl=en&_x_tr_pto=sc
-- NOTE: I have yet to find a case where the effect "associated element" isnt determined by the element of the action that causes it.
-- Example: Siren's elegy is wind while spell elegies are earth. Same effect, diferent elements.
-- Unlike sleep, elegy effect doesnt have an associated "effect resistance rank" and uses "element resistance rank" instead.
-----------------------------------
xi = xi or {}
xi.data = xi.data or {}
xi.data.statusEffect = xi.data.statusEffect or {}
-----------------------------------
-- Table column names.
local column =
{
EFFECT_NULLIFIED_BY = 1, -- [effect] is nullified by { effect }. In other words, [effect] cant be applied because { effect } is active.
EFFECT_NULLIFIES = 2, -- TODO: IMPLEMENT. [effect] nullifies { effect }.
EFFECT_ELEMENT = 3, -- Players and most effects dont have "effect resistance ranks", so they always use the effect "associated element" "resistance rank".
EFFECT_IMMUNITY = 4, -- Detected by "Completely resists" message. Cant immunobreak/resistance-hack it.
MOD_RESIST_TRAIT = 5, -- Detected by "Resist!" message. Cant immunobreak/resistance-hack it if triggered.
MOD_RESIST_RANK = 6, -- TODO: IMPLEMENT. For mobs, status effects can either: Use an specific status effect ressistance rank OR use their associated element resistance rank.
MOD_MAGIC_EVASION = 7,
MOD_IMMUNOBREAK = 8,
}
-- Table associating an status effect with their corresponding immunobreak, MEVA and resistance modifiers and immunities.
xi.data.statusEffect.dataTable =
{
[xi.effect.ADDLE ] = { 0, xi.effect.NOCTURNE, xi.element.FIRE, xi.immunity.ADDLE, xi.mod.SLOWRES, 0, 0, xi.mod.ADDLE_IMMUNOBREAK }, -- Addle cant be immunobroken?
[xi.effect.AMNESIA ] = { 0, 0, xi.element.FIRE, 0, xi.mod.AMNESIARES, 0, xi.mod.AMNESIA_MEVA, 0 },
[xi.effect.BIND ] = { 0, 0, xi.element.ICE, xi.immunity.BIND, xi.mod.BINDRES, xi.mod.BIND_RES_RANK, xi.mod.BIND_MEVA, xi.mod.BIND_IMMUNOBREAK },
[xi.effect.BLINDNESS ] = { 0, 0, xi.element.DARK, xi.immunity.BLIND, xi.mod.BLINDRES, xi.mod.BLIND_RES_RANK, xi.mod.BLIND_MEVA, xi.mod.BLIND_IMMUNOBREAK },
[xi.effect.BURN ] = { xi.effect.DROWN, 0, xi.element.FIRE, 0, 0, 0, 0, 0 },
[xi.effect.CHARM_I ] = { 0, 0, xi.element.LIGHT, 0, xi.mod.CHARMRES, 0, xi.mod.CHARM_MEVA, 0 }, -- TODO: charm should be moved from a mob property to a regular immunity
[xi.effect.CHOKE ] = { xi.effect.FROST, 0, xi.element.WIND, 0, 0, 0, 0, 0 },
[xi.effect.CURSE_I ] = { 0, 0, xi.element.DARK, xi.immunity.NONE, xi.mod.CURSERES, 0, xi.mod.CURSE_MEVA, 0 },
[xi.effect.DROWN ] = { xi.effect.SHOCK, 0, xi.element.WATER, 0, 0, 0, 0, 0 },
[xi.effect.FLASH ] = { 0, 0, xi.element.LIGHT, xi.immunity.BLIND, xi.mod.BLINDRES, xi.mod.BLIND_RES_RANK, xi.mod.BLIND_MEVA, xi.mod.BLIND_IMMUNOBREAK },
[xi.effect.FROST ] = { xi.effect.BURN, 0, xi.element.ICE, 0, 0, 0, 0, 0 },
[xi.effect.NOCTURNE ] = { xi.effect.ADDLE, 0, xi.element.FIRE, xi.immunity.ADDLE, xi.mod.SLOWRES, 0, 0, 0 },
[xi.effect.NONE ] = { 0, 0, xi.element.DARK, xi.immunity.DISPEL, 0, 0, 0, 0 },
[xi.effect.PARALYSIS ] = { 0, 0, xi.element.ICE, xi.immunity.PARALYZE, xi.mod.PARALYZERES, xi.mod.PARALYZE_RES_RANK, xi.mod.PARALYZE_MEVA, xi.mod.PARALYZE_IMMUNOBREAK },
[xi.effect.PETRIFICATION] = { 0, 0, xi.element.EARTH, xi.immunity.PETRIFY, xi.mod.PETRIFYRES, 0, xi.mod.PETRIFY_MEVA, xi.mod.PETRIFY_IMMUNOBREAK },
[xi.effect.PLAGUE ] = { 0, 0, xi.element.FIRE, xi.immunity.PLAGUE, xi.mod.VIRUSRES, 0, xi.mod.VIRUS_MEVA, 0 },
[xi.effect.POISON ] = { 0, 0, xi.element.WATER, xi.immunity.POISON, xi.mod.POISONRES, xi.mod.POISON_RES_RANK, xi.mod.POISON_MEVA, xi.mod.POISON_IMMUNOBREAK },
[xi.effect.RASP ] = { xi.effect.CHOKE, 0, xi.element.EARTH, 0, 0, 0, 0, 0 },
[xi.effect.SHOCK ] = { xi.effect.RASP, 0, xi.element.THUNDER, 0, 0, 0, 0, 0 },
[xi.effect.SILENCE ] = { 0, 0, xi.element.WIND, xi.immunity.SILENCE, xi.mod.SILENCERES, xi.mod.SILENCE_RES_RANK, xi.mod.SILENCE_MEVA, xi.mod.SILENCE_IMMUNOBREAK },
[xi.effect.SLEEP_I ] = { 0, 0, xi.element.DARK, xi.immunity.DARK_SLEEP, xi.mod.SLEEPRES, xi.mod.DARK_SLEEP_RES_RANK, xi.mod.SLEEP_MEVA, xi.mod.SLEEP_IMMUNOBREAK },
[xi.effect.SLOW ] = { 0, 0, xi.element.EARTH, xi.immunity.SLOW, xi.mod.SLOWRES, xi.mod.SLOW_RES_RANK, xi.mod.SLOW_MEVA, xi.mod.SLOW_IMMUNOBREAK },
[xi.effect.STUN ] = { 0, 0, xi.element.THUNDER, xi.immunity.STUN, xi.mod.STUNRES, 0, xi.mod.STUN_MEVA, 0 },
[xi.effect.WEIGHT ] = { 0, 0, xi.element.WIND, xi.immunity.GRAVITY, xi.mod.GRAVITYRES, 0, xi.mod.GRAVITY_MEVA, xi.mod.GRAVITY_IMMUNOBREAK },
}
-----------------------------------
-- Helper functions to easily fetch table data.
-----------------------------------
xi.data.statusEffect.getNullificatingEffect = function(effectId)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
-- Fetch effect ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.EFFECT_NULLIFIED_BY]
end
return 0
end
xi.data.statusEffect.getEffectToRemove = function(effectId)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
-- Fetch effect ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.EFFECT_NULLIFIES]
end
return 0
end
xi.data.statusEffect.getAssociatedElement = function(effectId, actionElement)
-- Sanitize fed values
local effectToCheck = utils.defaultIfNil(effectId, 0)
local elementToCheck = utils.defaultIfNil(actionElement, 0)
-- Sleep exception.
if effectToCheck == xi.effect.SLEEP_I then
return elementToCheck
end
-- Fetch element from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.EFFECT_ELEMENT]
end
-- Assume the effect "element" is the same as the action element.
return elementToCheck
end
xi.data.statusEffect.getAssociatedImmunity = function(effectId, actionElement)
-- Sanitize fed values
local effectToCheck = utils.defaultIfNil(effectId, 0)
local elementToCheck = utils.defaultIfNil(actionElement, 0)
-- Sleep exception.
if
effectToCheck == xi.effect.SLEEP_I and
elementToCheck == xi.element.LIGHT
then
return xi.immunity.LIGHT_SLEEP
end
-- Fetch immunity from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.EFFECT_IMMUNITY]
end
return 0
end
xi.data.statusEffect.getAssociatedResistTraitModifier = function(effectId)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
-- Fetch modifier ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.MOD_RESIST_TRAIT]
end
return 0
end
xi.data.statusEffect.getAssociatedResistanceRankModifier = function(effectId, actionElement)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
local elementToCheck = utils.defaultIfNil(actionElement, 0)
-- Sleep exception.
if
effectToCheck == xi.effect.SLEEP_I and
elementToCheck == xi.element.LIGHT
then
return xi.mod.LIGHT_SLEEP_RES_RANK
end
-- Fetch modifier ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.MOD_RESIST_RANK]
end
return 0
end
xi.data.statusEffect.getAssociatedMagicEvasionModifier = function(effectId)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
-- Fetch modifier ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.MOD_MAGIC_EVASION]
end
return 0
end
xi.data.statusEffect.getAssociatedImmunobreakModifier = function(effectId)
-- Sanitize fed value
local effectToCheck = utils.defaultIfNil(effectId, 0)
-- Fetch modifier ID from table if entry exists.
if xi.data.statusEffect.dataTable[effectToCheck] then
return xi.data.statusEffect.dataTable[effectToCheck][column.MOD_IMMUNOBREAK]
end
return 0
end
-----------------------------------
-- Helper functions to check target effect nullification.
-----------------------------------
xi.data.statusEffect.isTargetImmune = function(target, effectId, actionElement)
if not target:isMob() then
return false
end
local immunityId = xi.data.statusEffect.getAssociatedImmunity(effectId, actionElement)
if
immunityId > 0 and
target:hasImmunity(immunityId)
then
return true
end
return false
end
xi.data.statusEffect.isTargetResistant = function(actor, target, effectId)
local modifierId = xi.data.statusEffect.getAssociatedResistTraitModifier(effectId)
if modifierId == 0 then
return false
end
local resistancePower = target:getMod(modifierId) + target:getMod(xi.mod.STATUSRES) + 5
if resistancePower <= 5 then
return false
end
-- TODO: Investigate if this happens always or not. Ex: Terror.
if actor:isNM() then
resistancePower = math.floor(resistancePower / 2)
end
if math.random(1, 100) <= resistancePower then
return true
end
return false
end
xi.data.statusEffect.isEffectNullified = function(target, effectId)
local nullificatingEffect = xi.data.statusEffect.getNullificatingEffect(effectId)
if
nullificatingEffect > 0 and
target:hasStatusEffect(nullificatingEffect)
then
return true
end
return false
end