575 lines
19 KiB
Lua
575 lines
19 KiB
Lua
-----------------------------------
|
|
-- Global file for magic based skills magic hit rate.
|
|
-----------------------------------
|
|
xi = xi or {}
|
|
xi.combat = xi.combat or {}
|
|
xi.combat.magicHitRate = xi.combat.magicHitRate or {}
|
|
-----------------------------------
|
|
|
|
-----------------------------------
|
|
-- Calculate Target Resistance Rank
|
|
-----------------------------------
|
|
local function calculateTargetResistanceRank(actor, target, params)
|
|
-- Early return: Players don't use resistance ranks.
|
|
if target:isPC() then
|
|
return 0
|
|
end
|
|
|
|
-- Calculate what modifier to use.
|
|
local resistanceRankMod = 0 -- Modifier ID of the resistance rank to use.
|
|
if params.effectId > 0 then -- Check if it's an effect.
|
|
resistanceRankMod = xi.data.statusEffect.getAssociatedResistanceRankModifier(params.effectId, params.magicalElement)
|
|
end
|
|
|
|
if resistanceRankMod == 0 then -- If it's an effect and this is 0, try with element.
|
|
resistanceRankMod = xi.data.element.getElementalResistanceRankModifier(params.magicalElement)
|
|
end
|
|
|
|
-- Fetch resistance rank.
|
|
local resistanceRank = target:getMod(resistanceRankMod)
|
|
|
|
-- Apply possible resistance rank modifications.
|
|
if params.effectId > 0 then
|
|
resistanceRank = resistanceRank - target:getMod(xi.data.statusEffect.getAssociatedImmunobreakModifier(params.effectId)) -- Apply immunobreak modification.
|
|
end
|
|
|
|
return utils.clamp(resistanceRank, -3, 11)
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Calculate Actor Magic Accuracy
|
|
-----------------------------------
|
|
|
|
-- Magic Accuracy from spell's skill.
|
|
local function magicAccuracyFromSkill(actor, params)
|
|
local magicAcc = 0
|
|
|
|
-- For known skills.
|
|
if params.skillType > 0 then
|
|
magicAcc = actor:getSkillLevel(params.skillType)
|
|
|
|
-- If a mob is casting something its main/sub jobs cannot (i.e. JoL casting black magic) this is _exceptional_
|
|
-- So give them A+ rank base magic accuracy
|
|
if magicAcc == 0 and actor:isMob() then
|
|
magicAcc = xi.data.skillLevel.getSkillCap(actor:getMainLvl(), xi.skillRank.A_PLUS)
|
|
end
|
|
|
|
if params.skillType == xi.skill.SINGING then
|
|
if actor:isPC() then
|
|
-- String instruments sacrifice accuracy and amplify the AoE in exchange.
|
|
local rangedSkill = actor:getWeaponSkillType(xi.slot.RANGED)
|
|
if rangedSkill == xi.skill.WIND_INSTRUMENT then
|
|
magicAcc = magicAcc + math.floor(actor:getSkillLevel(rangedSkill) / 2)
|
|
end
|
|
else
|
|
magicAcc = magicAcc + math.floor(magicAcc / 2)
|
|
end
|
|
end
|
|
|
|
-- Made for bolts. Will probably see other uses.
|
|
elseif params.skillRank > 0 then
|
|
magicAcc = xi.data.skillLevel.getSkillCap(actor:getMainLvl(), params.skillRank)
|
|
|
|
-- For mob skills / additional effects which don't have a skill.
|
|
else
|
|
magicAcc = xi.data.skillLevel.getSkillCap(actor:getMainLvl(), xi.skillRank.A_PLUS)
|
|
end
|
|
|
|
return magicAcc
|
|
end
|
|
|
|
-- Magic Accuracy from spell's element.
|
|
local function magicAccuracyFromElement(actor, params)
|
|
-- Early return: No element.
|
|
if params.magicalElement <= xi.element.NONE then
|
|
return 0
|
|
end
|
|
|
|
return actor:getMod(xi.data.element.getElementalMACCModifier(params.magicalElement)) + actor:getMod(xi.data.element.getElementalStaffModifier(params.magicalElement)) * 10
|
|
end
|
|
|
|
-- Magic Accuracy from Stat Difference between caster and target.
|
|
local function magicAccuracyFromStatDifference(actor, target, params)
|
|
if params.actorStat == 0 then
|
|
return 0
|
|
end
|
|
|
|
local magicAcc = 0
|
|
local statDiff = actor:getStat(params.actorStat) - target:getStat(params.targetStat)
|
|
|
|
if statDiff <= -31 then
|
|
magicAcc = -20 + (statDiff + 30) / 4
|
|
elseif statDiff <= -11 then
|
|
magicAcc = -10 + (statDiff + 10) / 2
|
|
elseif statDiff < 11 then -- Between -11 and 11
|
|
magicAcc = statDiff
|
|
elseif statDiff >= 31 then
|
|
magicAcc = 20 + (statDiff - 30) / 4
|
|
elseif statDiff >= 11 then
|
|
magicAcc = 10 + (statDiff - 10) / 2
|
|
end
|
|
|
|
return utils.clamp(magicAcc, -30, 30)
|
|
end
|
|
|
|
-- Magic Accuracy from Status Effects.
|
|
local function magicAccuracyFromStatusEffects(actor, params)
|
|
local magicAcc = 0
|
|
local actorJob = actor:getMainJob()
|
|
local actorWeather = actor:getWeather()
|
|
|
|
-- Altruism
|
|
if
|
|
actor:hasStatusEffect(xi.effect.ALTRUISM) and
|
|
params.spellGroup == xi.magic.spellGroup.WHITE
|
|
then
|
|
magicAcc = actor:getStatusEffect(xi.effect.ALTRUISM):getPower()
|
|
end
|
|
|
|
-- Focalization
|
|
if
|
|
actor:hasStatusEffect(xi.effect.FOCALIZATION) and
|
|
params.spellGroup == xi.magic.spellGroup.BLACK
|
|
then
|
|
magicAcc = magicAcc + actor:getStatusEffect(xi.effect.FOCALIZATION):getPower()
|
|
end
|
|
|
|
--Klimaform
|
|
if
|
|
actor:hasStatusEffect(xi.effect.KLIMAFORM) and
|
|
params.magicalElement > 0 and
|
|
(actorWeather == xi.data.element.getAssociatedSingleWeather(params.magicalElement) or actorWeather == xi.data.element.getAssociatedDoubleWeather(params.magicalElement))
|
|
then
|
|
magicAcc = magicAcc + 15
|
|
end
|
|
|
|
-- Apply Divine Emblem to Banish and Holy families
|
|
if
|
|
actor:hasStatusEffect(xi.effect.DIVINE_EMBLEM) and
|
|
actorJob == xi.job.PLD and
|
|
params.skillType == xi.skill.DIVINE_MAGIC
|
|
then
|
|
magicAcc = magicAcc + 256
|
|
end
|
|
|
|
-- Elemental seal
|
|
if
|
|
actor:hasStatusEffect(xi.effect.ELEMENTAL_SEAL) and
|
|
params.skillType ~= xi.skill.DARK_MAGIC and
|
|
params.skillType ~= xi.skill.DIVINE_MAGIC and
|
|
params.magicalElement > 0
|
|
then
|
|
magicAcc = magicAcc + 256
|
|
end
|
|
|
|
-- Dark Seal
|
|
if
|
|
actor:hasStatusEffect(xi.effect.DARK_SEAL) and
|
|
params.skillType == xi.skill.DARK_MAGIC
|
|
then
|
|
magicAcc = magicAcc + 256
|
|
end
|
|
|
|
return magicAcc
|
|
end
|
|
|
|
-- Magic Accuracy from Merits.
|
|
local function magicAccuracyFromMerits(actor, params)
|
|
local magicAcc = 0
|
|
local actorJob = actor:getMainJob()
|
|
|
|
switch (actorJob) : caseof
|
|
{
|
|
[xi.job.BLM] = function()
|
|
if params.skillType == xi.skill.ELEMENTAL_MAGIC then
|
|
magicAcc = actor:getMerit(xi.merit.ELEMENTAL_MAGIC_ACCURACY)
|
|
end
|
|
end,
|
|
|
|
[xi.job.RDM] = function()
|
|
-- Category 1
|
|
if
|
|
params.magicalElement >= xi.element.FIRE and
|
|
params.magicalElement <= xi.element.WATER
|
|
then
|
|
magicAcc = actor:getMerit(xi.data.element.getElementalAccuracyMerit(params.magicalElement))
|
|
end
|
|
|
|
-- Category 2
|
|
magicAcc = magicAcc + actor:getMerit(xi.merit.MAGIC_ACCURACY)
|
|
end,
|
|
|
|
[xi.job.BRD] = function()
|
|
if
|
|
params.skillType == xi.skill.SINGING and
|
|
actor:hasStatusEffect(xi.effect.TROUBADOUR)
|
|
then
|
|
magicAcc = 64 * (actor:getMerit(xi.merit.TROUBADOUR) / 25 - 1)
|
|
end
|
|
end,
|
|
|
|
[xi.job.NIN] = function()
|
|
if params.skillType == xi.skill.NINJUTSU then
|
|
magicAcc = actor:getMerit(xi.merit.NIN_MAGIC_ACCURACY)
|
|
end
|
|
end,
|
|
|
|
[xi.job.BLU] = function()
|
|
if params.skillType == xi.skill.BLUE_MAGIC then
|
|
magicAcc = actor:getMerit(xi.merit.MAGICAL_ACCURACY)
|
|
end
|
|
end,
|
|
}
|
|
|
|
return magicAcc
|
|
end
|
|
|
|
-- Magic Accuracy from Job Points.
|
|
local function magicAccuracyFromJobPoints(actor, params)
|
|
local magicAcc = 0
|
|
local actorJob = actor:getMainJob()
|
|
|
|
switch (actorJob) : caseof
|
|
{
|
|
[xi.job.WHM] = function()
|
|
magicAcc = actor:getJobPointLevel(xi.jp.WHM_MAGIC_ACC_BONUS)
|
|
end,
|
|
|
|
[xi.job.BLM] = function()
|
|
magicAcc = actor:getJobPointLevel(xi.jp.BLM_MAGIC_ACC_BONUS)
|
|
end,
|
|
|
|
[xi.job.RDM] = function()
|
|
-- RDM Job Point: During saboteur, Enfeebling MACC +2
|
|
if
|
|
params.skillType == xi.skill.ENFEEBLING_MAGIC and
|
|
actor:hasStatusEffect(xi.effect.SABOTEUR)
|
|
then
|
|
magicAcc = actor:getJobPointLevel(xi.jp.SABOTEUR_EFFECT) * 2
|
|
end
|
|
|
|
-- RDM Job Point: Magic Accuracy Bonus, All MACC + 1
|
|
magicAcc = magicAcc + actor:getJobPointLevel(xi.jp.RDM_MAGIC_ACC_BONUS)
|
|
end,
|
|
|
|
[xi.job.BRD] = function()
|
|
if params.skillType == xi.skill.SINGING then
|
|
magicAcc = actor:getJobPointLevel(xi.jp.SONG_ACC_BONUS)
|
|
end
|
|
end,
|
|
|
|
[xi.job.NIN] = function()
|
|
if params.skillType == xi.skill.NINJUTSU then
|
|
magicAcc = actor:getJobPointLevel(xi.jp.NINJITSU_ACC_BONUS)
|
|
end
|
|
end,
|
|
|
|
[xi.job.SCH] = function()
|
|
if
|
|
(params.spellGroup == xi.magic.spellGroup.WHITE and actor:hasStatusEffect(xi.effect.PARSIMONY)) or
|
|
(params.spellGroup == xi.magic.spellGroup.BLACK and actor:hasStatusEffect(xi.effect.PENURY))
|
|
then
|
|
magicAcc = actor:getJobPointLevel(xi.jp.STRATEGEM_EFFECT_I)
|
|
end
|
|
end,
|
|
}
|
|
|
|
return magicAcc
|
|
end
|
|
|
|
-- Magic Accuracy from Magic Burst.
|
|
local function magicAccuracyFromMagicBurst(target, params)
|
|
if params.magicalElement == xi.element.NONE then
|
|
return 0
|
|
end
|
|
|
|
if params.magicBurstTier <= 0 then
|
|
return 0
|
|
end
|
|
|
|
return 100
|
|
end
|
|
|
|
-- Magic Accuracy from Weather Element. Note: https://wiki.ffo.jp/html/1796.html claims day does not affect macc.
|
|
local function magicAccuracyFromWeatherElement(actor, params)
|
|
local magicAcc = 0
|
|
|
|
-- Early return: Invalid element.
|
|
if params.magicalElement <= xi.element.NONE then
|
|
return magicAcc
|
|
end
|
|
|
|
-- Define what to apply.
|
|
local applyBonuses = false
|
|
local applyPenalties = false
|
|
|
|
if
|
|
math.randomInt(1, 100) <= 33 or -- Random. Applies to both bonuses and penalties.
|
|
actor:getMod(xi.mod.FORCE_DW_BONUS_PENALTY) >= 1 -- Hachirin-no-Obi forces both bonuses and penalties.
|
|
then
|
|
applyBonuses = true
|
|
applyPenalties = true
|
|
elseif actor:getMod(xi.data.element.getForcedDayOrWeatherBonusModifier(params.magicalElement)) >= 1 then -- Elemental Obis only force bonuses, not penalties.
|
|
applyBonuses = true
|
|
end
|
|
|
|
-- Calculate bonuses/penalties.
|
|
local actorWeather = actor:getWeather()
|
|
|
|
if applyBonuses then
|
|
if actorWeather == xi.data.element.getAssociatedSingleWeather(params.magicalElement) then
|
|
magicAcc = magicAcc + 5 + actor:getMod(xi.mod.IRIDESCENCE) * 5
|
|
elseif actorWeather == xi.data.element.getAssociatedDoubleWeather(params.magicalElement) then
|
|
magicAcc = magicAcc + 10 + actor:getMod(xi.mod.IRIDESCENCE) * 5
|
|
end
|
|
end
|
|
|
|
if applyPenalties then
|
|
if actorWeather == xi.data.element.getOppositeSingleWeather(params.magicalElement) then
|
|
magicAcc = magicAcc - 5 - actor:getMod(xi.mod.IRIDESCENCE) * 5
|
|
elseif actorWeather == xi.data.element.getOppositeDoubleWeather(params.magicalElement) then
|
|
magicAcc = magicAcc - 10 - actor:getMod(xi.mod.IRIDESCENCE) * 5
|
|
end
|
|
end
|
|
|
|
return magicAcc
|
|
end
|
|
|
|
-- Magic Accuracy from Tandem Strike (BST trait).
|
|
local function magicAccuracyFromTandemStrike(actor)
|
|
-- Early return: Can't apply Tandem Strike.
|
|
if not actor:isTandemActive() then
|
|
return 0
|
|
end
|
|
|
|
-- Actor is a pet, with a master. Fetch master modifier.
|
|
local master = actor:getMaster()
|
|
if master and master:isPC() then
|
|
return master:getMod(xi.mod.TANDEM_STRIKE_POWER)
|
|
end
|
|
|
|
-- Actor is the master.
|
|
return actor:getMod(xi.mod.TANDEM_STRIKE_POWER)
|
|
end
|
|
|
|
-- Magic Accuracy from Food.
|
|
local function magicAccuracyFromFoodMultiplier(actor)
|
|
local foodMagicAccBonus = actor:getMod(xi.mod.FOOD_MACCP) / 100
|
|
local foodMagicAccCap = actor:getMod(xi.mod.FOOD_MACC_CAP) / 100
|
|
|
|
if foodMagicAccCap > 0 then
|
|
foodMagicAccBonus = utils.clamp(foodMagicAccBonus, 0, foodMagicAccCap)
|
|
end
|
|
|
|
return 1 + foodMagicAccBonus
|
|
end
|
|
|
|
local function magicAccuracyFromSoulVoiceMultiplier(actor, params)
|
|
local effectTable =
|
|
set{
|
|
xi.effect.SLEEP_I, -- Lullabies
|
|
xi.effect.NONE, -- Magic Finale
|
|
xi.effect.CHARM_I -- Maiden's Virellai
|
|
}
|
|
|
|
if
|
|
effectTable[params.effectId] and
|
|
params.skillType == xi.skill.SINGING
|
|
then
|
|
if actor:hasStatusEffect(xi.effect.SOUL_VOICE) then
|
|
return 2
|
|
elseif actor:hasStatusEffect(xi.effect.MARCATO) then
|
|
return 1.5
|
|
end
|
|
end
|
|
|
|
return 1
|
|
end
|
|
|
|
-- Global function to calculate total magicc accuracy.
|
|
local function calculateActorMagicAccuracy(actor, target, params)
|
|
local finalMagicAcc = 0
|
|
|
|
local magicAccBase = actor:getMod(xi.mod.MACC) + actor:getILvlMacc(xi.slot.MAIN) + params.bonusMacc
|
|
local magicAccSkill = magicAccuracyFromSkill(actor, params)
|
|
local magicAccElement = magicAccuracyFromElement(actor, params)
|
|
local magicAccStatDiff = magicAccuracyFromStatDifference(actor, target, params)
|
|
local magicAccEffects = magicAccuracyFromStatusEffects(actor, params)
|
|
local magicAccMerits = magicAccuracyFromMerits(actor, params)
|
|
local magicAccJobPoints = magicAccuracyFromJobPoints(actor, params)
|
|
local magicAccBurst = magicAccuracyFromMagicBurst(target, params)
|
|
local magicAccWeather = magicAccuracyFromWeatherElement(actor, params)
|
|
local magicAccTandem = magicAccuracyFromTandemStrike(actor)
|
|
|
|
-- Multipliers
|
|
local magicAccFoodFactor = magicAccuracyFromFoodMultiplier(actor)
|
|
local magicAccSoulVoiceFactor = magicAccuracyFromSoulVoiceMultiplier(actor, params)
|
|
|
|
-- Add up food magic accuracy.
|
|
finalMagicAcc = magicAccBase + magicAccSkill + magicAccElement + magicAccStatDiff + magicAccEffects + magicAccMerits + magicAccJobPoints + magicAccBurst + magicAccWeather + magicAccTandem
|
|
finalMagicAcc = math.floor(finalMagicAcc * magicAccFoodFactor * magicAccSoulVoiceFactor)
|
|
|
|
return finalMagicAcc
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Calculate Target Magic Evasion
|
|
-----------------------------------
|
|
local resistRankMultiplier =
|
|
{
|
|
-- [Rank] = Magic Evasion multiplier.
|
|
[-3] = 0.95,
|
|
[-2] = 0.96019,
|
|
[-1] = 0.98,
|
|
[ 0] = 1,
|
|
[ 1] = 1.023,
|
|
[ 2] = 1.049,
|
|
[ 3] = 1.0905,
|
|
[ 4] = 1.126,
|
|
[ 5] = 1.2075,
|
|
[ 6] = 1.3475,
|
|
[ 7] = 1.70065,
|
|
[ 8] = 2.141,
|
|
[ 9] = 2.2,
|
|
[10] = 2.275, -- Impossible to test since 'Magic Hit Rate' is floored to 5% at this point.
|
|
[11] = 2.35, -- Impossible to test since 'Magic Hit Rate' is floored to 5% at this point.
|
|
}
|
|
|
|
local function calculateTargetMagicEvasion(actor, target, params)
|
|
local magicEva = target:getMod(xi.mod.MEVA) -- Base MACC.
|
|
|
|
-- Elemental magic evasion. All actions and effects have an associated element.
|
|
if params.magicalElement ~= xi.element.NONE then
|
|
magicEva = magicEva + target:getMod(xi.data.element.getElementalMEVAModifier(params.magicalElement))
|
|
end
|
|
|
|
-- Magic evasion against specific status effects.
|
|
if params.effectId > 0 then
|
|
magicEva = magicEva + target:getMod(xi.data.statusEffect.getAssociatedMagicEvasionModifier(params.effectId)) + target:getMod(xi.mod.STATUS_MEVA)
|
|
end
|
|
|
|
-- Level correction. Target gets a bonus the higher the level if it's a mob. Never a penalty.
|
|
if
|
|
not target:isPC() and
|
|
xi.data.levelCorrection.isLevelCorrectedZone(actor)
|
|
then
|
|
magicEva = magicEva + utils.clamp(target:getMainLvl() - actor:getMainLvl(), 0, 100) * 4
|
|
end
|
|
|
|
-- Apply resistance rank multiplier.
|
|
magicEva = math.floor(magicEva * resistRankMultiplier[params.resistanceRank])
|
|
|
|
return magicEva
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Magic Hit Rate. The function gets fed the result of both functions above.
|
|
-----------------------------------
|
|
local function calculateMagicHitRate(params)
|
|
local magicHitRate = params.actorMagicAccuracy - params.targetMagicEvasion
|
|
|
|
if magicHitRate < 0 then
|
|
magicHitRate = math.floor(magicHitRate / 2)
|
|
end
|
|
|
|
magicHitRate = utils.clamp((50 + magicHitRate) / 100, 0.05, 0.95)
|
|
|
|
return magicHitRate
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Calculate resist rate.
|
|
-----------------------------------
|
|
local function calculateResistanceFactor(actor, target, params)
|
|
-- Calculate max allowed resist tier.
|
|
local maxResistTier = 3
|
|
|
|
-- Players: Affected by element shown in equipment screen.
|
|
if target:isPC() then
|
|
local playerElementalEvasion = target:getMod(xi.data.element.getElementalMEVAModifier(params.magicalElement)) or 0
|
|
|
|
if playerElementalEvasion < 0 then
|
|
maxResistTier = 1
|
|
elseif playerElementalEvasion == 0 then
|
|
maxResistTier = 2
|
|
end
|
|
end
|
|
|
|
-- Calculate first 3 resist tiers.
|
|
-- Notes: 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
|
|
local resistTier = 0
|
|
for i = 1, maxResistTier do
|
|
if math.randomFloat(0, 1) > params.magicHitRate then
|
|
resistTier = resistTier + 1
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
return 1 / (2 ^ resistTier)
|
|
end
|
|
|
|
-----------------------------------
|
|
-- Resist rate helper function.
|
|
-----------------------------------
|
|
local function validateParameters(actor, target, fedData)
|
|
local params = {}
|
|
|
|
-- Action information.
|
|
params.effectId = fedData.effectId or 0
|
|
params.magicalElement = fedData.magicalElement or xi.element.NONE
|
|
params.bonusMacc = fedData.bonusMacc or 0
|
|
params.magicBurstTier = fedData.magicBurstTier or 0
|
|
params.actorStat = fedData.actorStat or 0
|
|
params.targetStat = fedData.targetStat or params.actorStat
|
|
params.skillType = fedData.skillType or 0
|
|
params.skillRank = fedData.skillRank or 0
|
|
params.spellGroup = fedData.spellGroup or 0
|
|
|
|
-- Initialize future parameters.
|
|
params.resistanceRank = 0
|
|
params.actorMagicAccuracy = 0
|
|
params.targetMagicEvasion = 0
|
|
params.magicHitRate = 0.05
|
|
|
|
return params
|
|
end
|
|
|
|
xi.combat.magicHitRate.calculateResistRate = function(actor, target, fedData)
|
|
-- Validate fed parameters.
|
|
local params = validateParameters(actor, target, fedData)
|
|
|
|
-- Early return: Magic shield.
|
|
if target:hasStatusEffect(xi.effect.MAGIC_SHIELD, 0) then
|
|
return 0
|
|
end
|
|
|
|
-- Early return: Cannot resist non-elemental magic actions.
|
|
if params.magicalElement == xi.element.NONE then
|
|
return 1
|
|
end
|
|
|
|
-- Calculate and table resistance rank. TODO: Feed it to the function directly.
|
|
params.resistanceRank = calculateTargetResistanceRank(actor, target, params)
|
|
|
|
-- Early return: Auto-resist.
|
|
if params.resistanceRank >= 11 then
|
|
if params.effectId > 0 then
|
|
return 0 -- Status Effects
|
|
else
|
|
return 0.25 -- Nukes
|
|
end
|
|
end
|
|
|
|
-- Early return: MHR is floored to 0.05. Skip calculating it.
|
|
if params.resistanceRank >= 10 then
|
|
return calculateResistanceFactor(actor, target, params)
|
|
end
|
|
|
|
-- Calculate and table MACC, MEVA and MHR.
|
|
params.actorMagicAccuracy = calculateActorMagicAccuracy(actor, target, params)
|
|
params.targetMagicEvasion = calculateTargetMagicEvasion(actor, target, params)
|
|
params.magicHitRate = calculateMagicHitRate(params)
|
|
|
|
return calculateResistanceFactor(actor, target, params)
|
|
end
|